diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index 46bdf208be6ad..36c42fced93d0 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -165,6 +165,12 @@ bool shouldPrint(const BinaryFunction &Function) { } } + std::optional Origin = Function.getOriginSectionName(); + if (Origin && llvm::any_of(opts::PrintOnly, [&](const std::string &Name) { + return Name == *Origin; + })) + return true; + return false; } diff --git a/bolt/test/AArch64/constant_island_pie_update.s b/bolt/test/AArch64/constant_island_pie_update.s index 313e103b19c05..889f6b6acd9f2 100644 --- a/bolt/test/AArch64/constant_island_pie_update.s +++ b/bolt/test/AArch64/constant_island_pie_update.s @@ -8,15 +8,15 @@ # RUN: %clang %cflags -fPIC -pie %t.o -o %t.rela.exe -nostdlib \ # RUN: -Wl,-q -Wl,-z,notext # RUN: llvm-bolt %t.rela.exe -o %t.rela.bolt --use-old-text=0 --lite=0 -# RUN: llvm-objdump -j .text -d --show-all-symbols %t.rela.bolt | FileCheck %s +# RUN: llvm-objdump -j .text -d -z --show-all-symbols %t.rela.bolt | FileCheck %s # RUN: llvm-readelf -rsW %t.rela.bolt | FileCheck --check-prefix=ELFCHECK %s // .relr.dyn # RUN: %clang %cflags -fPIC -pie %t.o -o %t.relr.exe -nostdlib \ # RUN: -Wl,-q -Wl,-z,notext -Wl,--pack-dyn-relocs=relr # RUN: llvm-objcopy --remove-section .rela.mytext %t.relr.exe # RUN: llvm-bolt %t.relr.exe -o %t.relr.bolt --use-old-text=0 --lite=0 -# RUN: llvm-objdump -j .text -d --show-all-symbols %t.relr.bolt | FileCheck %s -# RUN: llvm-objdump -j .text -d %t.relr.bolt | \ +# RUN: llvm-objdump -j .text -d -z --show-all-symbols %t.relr.bolt | FileCheck %s +# RUN: llvm-objdump -j .text -d -z %t.relr.bolt | \ # RUN: FileCheck %s --check-prefix=ADDENDCHECK # RUN: llvm-readelf -rsW %t.relr.bolt | FileCheck --check-prefix=RELRELFCHECK %s # RUN: llvm-readelf -SW %t.relr.bolt | FileCheck --check-prefix=RELRSZCHECK %s diff --git a/bolt/test/AArch64/update-weak-reference-symbol.s b/bolt/test/AArch64/update-weak-reference-symbol.s index 600a06b8b6d8f..46819e888b08e 100644 --- a/bolt/test/AArch64/update-weak-reference-symbol.s +++ b/bolt/test/AArch64/update-weak-reference-symbol.s @@ -3,7 +3,7 @@ // RUN: %clang %cflags -Wl,-z,notext -shared -Wl,-q %s -o %t.so // RUN: llvm-bolt %t.so -o %t.so.bolt // RUN: llvm-nm -n %t.so.bolt > %t.out.txt -// RUN: llvm-objdump -dj .rodata %t.so.bolt >> %t.out.txt +// RUN: llvm-objdump -z -dj .rodata %t.so.bolt >> %t.out.txt // RUN: FileCheck %s --input-file=%t.out.txt # CHECK: w func_1 diff --git a/bolt/test/X86/print-only-section.s b/bolt/test/X86/print-only-section.s new file mode 100644 index 0000000000000..d580818ca4fc6 --- /dev/null +++ b/bolt/test/X86/print-only-section.s @@ -0,0 +1,29 @@ +## Check that --print-only flag works with sections. + +# REQUIRES: system-linux + +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t.exe +# RUN: llvm-bolt %t.exe -o %t.out --print-cfg --print-only=unused_code 2>&1 \ +# RUN: | FileCheck %s + +# CHECK: Binary Function "foo" +# CHECK-NOT: Binary Function "_start" + + .text + .globl _start + .type _start, %function +_start: + .cfi_startproc + ret + .cfi_endproc + .size _start, .-_start + + .section unused_code,"ax",@progbits + .globl foo + .type foo, %function +foo: + .cfi_startproc + ret + .cfi_endproc + .size foo, .-foo diff --git a/bolt/test/merge-fdata-uninitialized-header.test b/bolt/test/merge-fdata-uninitialized-header.test new file mode 100644 index 0000000000000..5336961278411 --- /dev/null +++ b/bolt/test/merge-fdata-uninitialized-header.test @@ -0,0 +1,45 @@ +## Test that merge-fdata correctly handles YAML header with an uninitialized +## fields. a.yaml does not have hash-func set and it used to crash merge-fdata. + +# REQUIRES: system-linux + +# RUN: split-file %s %t +# RUN: not merge-fdata %t/a.yaml %t/b.yaml 2>&1 | FileCheck %s + +# CHECK: cannot merge profiles with different hash functions + +#--- a.yaml +--- +header: + profile-version: 1 + binary-name: 'a.out' + binary-build-id: '' + profile-flags: [ lbr ] + profile-origin: branch profile reader + profile-events: '' + dfs-order: false +functions: + - name: 'main' + fid: 1 + hash: 0x50BBA3441D436491 + exec: 1 + nblocks: 0 +... +#--- b.yaml +--- +header: + profile-version: 1 + binary-name: 'a.out' + binary-build-id: '' + profile-flags: [ lbr ] + profile-origin: branch profile reader + profile-events: '' + dfs-order: false + hash-func: xxh3 +functions: + - name: 'main' + fid: 1 + hash: 0x50BBA3441D436491 + exec: 1 + nblocks: 0 +... diff --git a/bolt/tools/merge-fdata/merge-fdata.cpp b/bolt/tools/merge-fdata/merge-fdata.cpp index b640aae808f56..89ca46c1c0a8f 100644 --- a/bolt/tools/merge-fdata/merge-fdata.cpp +++ b/bolt/tools/merge-fdata/merge-fdata.cpp @@ -145,6 +145,10 @@ void mergeProfileHeaders(BinaryProfileHeader &MergedHeader, errs() << "WARNING: merging profiles with different sampling events\n"; MergedHeader.EventNames += "," + Header.EventNames; } + + if (MergedHeader.HashFunction != Header.HashFunction) + report_error("merge conflict", + "cannot merge profiles with different hash functions"); } void mergeBasicBlockProfile(BinaryBasicBlockProfile &MergedBB, @@ -386,6 +390,7 @@ int main(int argc, char **argv) { // Merged information for all functions. StringMap MergedBFs; + bool FirstHeader = true; for (std::string &InputDataFilename : Inputs) { ErrorOr> MB = MemoryBuffer::getFileOrSTDIN(InputDataFilename); @@ -409,7 +414,12 @@ int main(int argc, char **argv) { } // Merge the header. - mergeProfileHeaders(MergedHeader, BP.Header); + if (FirstHeader) { + MergedHeader = BP.Header; + FirstHeader = false; + } else { + mergeProfileHeaders(MergedHeader, BP.Header); + } // Do the function merge. for (BinaryFunctionProfile &BF : BP.Functions) { diff --git a/clang-tools-extra/clang-tidy/bugprone/PosixReturnCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PosixReturnCheck.cpp index 378427a1eab00..f05924b81c4c0 100644 --- a/clang-tools-extra/clang-tidy/bugprone/PosixReturnCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/PosixReturnCheck.cpp @@ -7,19 +7,17 @@ //===----------------------------------------------------------------------===// #include "PosixReturnCheck.h" -#include "../utils/Matchers.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Lex/Lexer.h" using namespace clang::ast_matchers; namespace clang::tidy::bugprone { -static StringRef getFunctionSpelling(const MatchFinder::MatchResult &Result, - const char *BindingStr) { - const CallExpr *MatchedCall = cast( - (Result.Nodes.getNodeAs(BindingStr))->getLHS()); +static StringRef getFunctionSpelling(const MatchFinder::MatchResult &Result) { + const auto *MatchedCall = Result.Nodes.getNodeAs("call"); const SourceManager &SM = *Result.SourceManager; return Lexer::getSourceText(CharSourceRange::getTokenRange( MatchedCall->getCallee()->getSourceRange()), @@ -27,32 +25,40 @@ static StringRef getFunctionSpelling(const MatchFinder::MatchResult &Result, } void PosixReturnCheck::registerMatchers(MatchFinder *Finder) { + const auto PosixCall = + callExpr(callee(functionDecl( + anyOf(matchesName("^::posix_"), matchesName("^::pthread_")), + unless(hasName("::posix_openpt"))))) + .bind("call"); + const auto ZeroIntegerLiteral = integerLiteral(equals(0)); + const auto NegIntegerLiteral = + unaryOperator(hasOperatorName("-"), hasUnaryOperand(integerLiteral())); + Finder->addMatcher( binaryOperator( - hasOperatorName("<"), - hasLHS(callExpr(callee(functionDecl( - anyOf(matchesName("^::posix_"), matchesName("^::pthread_")), - unless(hasName("::posix_openpt")))))), - hasRHS(integerLiteral(equals(0)))) + anyOf(allOf(hasOperatorName("<"), hasLHS(PosixCall), + hasRHS(ZeroIntegerLiteral)), + allOf(hasOperatorName(">"), hasLHS(ZeroIntegerLiteral), + hasRHS(PosixCall)))) .bind("ltzop"), this); Finder->addMatcher( binaryOperator( - hasOperatorName(">="), - hasLHS(callExpr(callee(functionDecl( - anyOf(matchesName("^::posix_"), matchesName("^::pthread_")), - unless(hasName("::posix_openpt")))))), - hasRHS(integerLiteral(equals(0)))) + anyOf(allOf(hasOperatorName(">="), hasLHS(PosixCall), + hasRHS(ZeroIntegerLiteral)), + allOf(hasOperatorName("<="), hasLHS(ZeroIntegerLiteral), + hasRHS(PosixCall)))) .bind("atop"), this); + Finder->addMatcher(binaryOperator(hasAnyOperatorName("==", "!="), + hasOperands(PosixCall, NegIntegerLiteral)) + .bind("binop"), + this); Finder->addMatcher( - binaryOperator( - hasAnyOperatorName("==", "!=", "<=", "<"), - hasLHS(callExpr(callee(functionDecl( - anyOf(matchesName("^::posix_"), matchesName("^::pthread_")), - unless(hasName("::posix_openpt")))))), - hasRHS(unaryOperator(hasOperatorName("-"), - hasUnaryOperand(integerLiteral())))) + binaryOperator(anyOf(allOf(hasAnyOperatorName("<=", "<"), + hasLHS(PosixCall), hasRHS(NegIntegerLiteral)), + allOf(hasAnyOperatorName(">", ">="), + hasLHS(NegIntegerLiteral), hasRHS(PosixCall)))) .bind("binop"), this); } @@ -61,10 +67,13 @@ void PosixReturnCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *LessThanZeroOp = Result.Nodes.getNodeAs("ltzop")) { SourceLocation OperatorLoc = LessThanZeroOp->getOperatorLoc(); + StringRef NewBinOp = + LessThanZeroOp->getOpcode() == BinaryOperator::Opcode::BO_LT ? ">" + : "<"; diag(OperatorLoc, "the comparison always evaluates to false because %0 " "always returns non-negative values") - << getFunctionSpelling(Result, "ltzop") - << FixItHint::CreateReplacement(OperatorLoc, Twine(">").str()); + << getFunctionSpelling(Result) + << FixItHint::CreateReplacement(OperatorLoc, NewBinOp); return; } if (const auto *AlwaysTrueOp = @@ -72,12 +81,12 @@ void PosixReturnCheck::check(const MatchFinder::MatchResult &Result) { diag(AlwaysTrueOp->getOperatorLoc(), "the comparison always evaluates to true because %0 always returns " "non-negative values") - << getFunctionSpelling(Result, "atop"); + << getFunctionSpelling(Result); return; } const auto *BinOp = Result.Nodes.getNodeAs("binop"); diag(BinOp->getOperatorLoc(), "%0 only returns non-negative values") - << getFunctionSpelling(Result, "binop"); + << getFunctionSpelling(Result); } } // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp index ea7eaa0b0ff81..604a7cac0e490 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "UnsafeFunctionsCheck.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Lex/PPCallbacks.h" @@ -18,6 +19,10 @@ using namespace llvm; namespace clang::tidy::bugprone { +static constexpr llvm::StringLiteral OptionNameCustomFunctions = + "CustomFunctions"; +static constexpr llvm::StringLiteral OptionNameReportDefaultFunctions = + "ReportDefaultFunctions"; static constexpr llvm::StringLiteral OptionNameReportMoreUnsafeFunctions = "ReportMoreUnsafeFunctions"; @@ -26,6 +31,8 @@ static constexpr llvm::StringLiteral FunctionNamesWithAnnexKReplacementId = static constexpr llvm::StringLiteral FunctionNamesId = "FunctionsNames"; static constexpr llvm::StringLiteral AdditionalFunctionNamesId = "AdditionalFunctionsNames"; +static constexpr llvm::StringLiteral CustomFunctionNamesId = + "CustomFunctionNames"; static constexpr llvm::StringLiteral DeclRefId = "DRE"; static std::optional @@ -127,57 +134,128 @@ static bool isAnnexKAvailable(std::optional &CacheVar, Preprocessor *PP, return CacheVar.value(); } +static std::vector +parseCheckedFunctions(StringRef Option, ClangTidyContext *Context) { + const std::vector Functions = + utils::options::parseStringList(Option); + std::vector Result; + Result.reserve(Functions.size()); + + for (StringRef Function : Functions) { + if (Function.empty()) + continue; + + const auto [Name, Rest] = Function.split(','); + const auto [Replacement, Reason] = Rest.split(','); + + if (Name.trim().empty()) { + Context->configurationDiag("invalid configuration value for option '%0'; " + "expected the name of an unsafe function") + << OptionNameCustomFunctions; + continue; + } + + Result.push_back( + {Name.trim().str(), + matchers::MatchesAnyListedNameMatcher::NameMatcher(Name.trim()), + Replacement.trim().str(), Reason.trim().str()}); + } + + return Result; +} + +static std::string serializeCheckedFunctions( + const std::vector &Functions) { + std::vector Result; + Result.reserve(Functions.size()); + + for (const auto &Entry : Functions) { + if (Entry.Reason.empty()) + Result.push_back(Entry.Name + "," + Entry.Replacement); + else + Result.push_back(Entry.Name + "," + Entry.Replacement + "," + + Entry.Reason); + } + + return llvm::join(Result, ";"); +} + UnsafeFunctionsCheck::UnsafeFunctionsCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), + CustomFunctions(parseCheckedFunctions( + Options.get(OptionNameCustomFunctions, ""), Context)), + ReportDefaultFunctions( + Options.get(OptionNameReportDefaultFunctions, true)), ReportMoreUnsafeFunctions( Options.get(OptionNameReportMoreUnsafeFunctions, true)) {} void UnsafeFunctionsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, OptionNameCustomFunctions, + serializeCheckedFunctions(CustomFunctions)); + Options.store(Opts, OptionNameReportDefaultFunctions, ReportDefaultFunctions); Options.store(Opts, OptionNameReportMoreUnsafeFunctions, ReportMoreUnsafeFunctions); } void UnsafeFunctionsCheck::registerMatchers(MatchFinder *Finder) { - if (getLangOpts().C11) { - // Matching functions with safe replacements only in Annex K. - auto FunctionNamesWithAnnexKReplacementMatcher = hasAnyName( - "::bsearch", "::ctime", "::fopen", "::fprintf", "::freopen", "::fscanf", - "::fwprintf", "::fwscanf", "::getenv", "::gmtime", "::localtime", - "::mbsrtowcs", "::mbstowcs", "::memcpy", "::memmove", "::memset", - "::printf", "::qsort", "::scanf", "::snprintf", "::sprintf", "::sscanf", - "::strcat", "::strcpy", "::strerror", "::strlen", "::strncat", - "::strncpy", "::strtok", "::swprintf", "::swscanf", "::vfprintf", - "::vfscanf", "::vfwprintf", "::vfwscanf", "::vprintf", "::vscanf", - "::vsnprintf", "::vsprintf", "::vsscanf", "::vswprintf", "::vswscanf", - "::vwprintf", "::vwscanf", "::wcrtomb", "::wcscat", "::wcscpy", - "::wcslen", "::wcsncat", "::wcsncpy", "::wcsrtombs", "::wcstok", - "::wcstombs", "::wctomb", "::wmemcpy", "::wmemmove", "::wprintf", - "::wscanf"); + if (ReportDefaultFunctions) { + if (getLangOpts().C11) { + // Matching functions with safe replacements only in Annex K. + auto FunctionNamesWithAnnexKReplacementMatcher = hasAnyName( + "::bsearch", "::ctime", "::fopen", "::fprintf", "::freopen", + "::fscanf", "::fwprintf", "::fwscanf", "::getenv", "::gmtime", + "::localtime", "::mbsrtowcs", "::mbstowcs", "::memcpy", "::memmove", + "::memset", "::printf", "::qsort", "::scanf", "::snprintf", + "::sprintf", "::sscanf", "::strcat", "::strcpy", "::strerror", + "::strlen", "::strncat", "::strncpy", "::strtok", "::swprintf", + "::swscanf", "::vfprintf", "::vfscanf", "::vfwprintf", "::vfwscanf", + "::vprintf", "::vscanf", "::vsnprintf", "::vsprintf", "::vsscanf", + "::vswprintf", "::vswscanf", "::vwprintf", "::vwscanf", "::wcrtomb", + "::wcscat", "::wcscpy", "::wcslen", "::wcsncat", "::wcsncpy", + "::wcsrtombs", "::wcstok", "::wcstombs", "::wctomb", "::wmemcpy", + "::wmemmove", "::wprintf", "::wscanf"); + Finder->addMatcher( + declRefExpr(to(functionDecl(FunctionNamesWithAnnexKReplacementMatcher) + .bind(FunctionNamesWithAnnexKReplacementId))) + .bind(DeclRefId), + this); + } + + // Matching functions with replacements without Annex K. + auto FunctionNamesMatcher = + hasAnyName("::asctime", "asctime_r", "::gets", "::rewind", "::setbuf"); Finder->addMatcher( - declRefExpr(to(functionDecl(FunctionNamesWithAnnexKReplacementMatcher) - .bind(FunctionNamesWithAnnexKReplacementId))) + declRefExpr( + to(functionDecl(FunctionNamesMatcher).bind(FunctionNamesId))) .bind(DeclRefId), this); + + if (ReportMoreUnsafeFunctions) { + // Matching functions with replacements without Annex K, at user request. + auto AdditionalFunctionNamesMatcher = + hasAnyName("::bcmp", "::bcopy", "::bzero", "::getpw", "::vfork"); + Finder->addMatcher( + declRefExpr(to(functionDecl(AdditionalFunctionNamesMatcher) + .bind(AdditionalFunctionNamesId))) + .bind(DeclRefId), + this); + } } - // Matching functions with replacements without Annex K. - auto FunctionNamesMatcher = - hasAnyName("::asctime", "asctime_r", "::gets", "::rewind", "::setbuf"); - Finder->addMatcher( - declRefExpr(to(functionDecl(FunctionNamesMatcher).bind(FunctionNamesId))) - .bind(DeclRefId), - this); - - if (ReportMoreUnsafeFunctions) { - // Matching functions with replacements without Annex K, at user request. - auto AdditionalFunctionNamesMatcher = - hasAnyName("::bcmp", "::bcopy", "::bzero", "::getpw", "::vfork"); - Finder->addMatcher( - declRefExpr(to(functionDecl(AdditionalFunctionNamesMatcher) - .bind(AdditionalFunctionNamesId))) - .bind(DeclRefId), - this); + if (!CustomFunctions.empty()) { + std::vector FunctionNames; + FunctionNames.reserve(CustomFunctions.size()); + + for (const auto &Entry : CustomFunctions) + FunctionNames.push_back(Entry.Name); + + auto CustomFunctionsMatcher = matchers::matchesAnyListedName(FunctionNames); + + Finder->addMatcher(declRefExpr(to(functionDecl(CustomFunctionsMatcher) + .bind(CustomFunctionNamesId))) + .bind(DeclRefId), + this); } } @@ -186,16 +264,46 @@ void UnsafeFunctionsCheck::check(const MatchFinder::MatchResult &Result) { const auto *FuncDecl = cast(DeclRef->getDecl()); assert(DeclRef && FuncDecl && "No valid matched node in check()"); + // Only one of these are matched at a time. const auto *AnnexK = Result.Nodes.getNodeAs( FunctionNamesWithAnnexKReplacementId); const auto *Normal = Result.Nodes.getNodeAs(FunctionNamesId); const auto *Additional = Result.Nodes.getNodeAs(AdditionalFunctionNamesId); - assert((AnnexK || Normal || Additional) && "No valid match category."); + const auto *Custom = + Result.Nodes.getNodeAs(CustomFunctionNamesId); + assert((AnnexK || Normal || Additional || Custom) && + "No valid match category."); bool AnnexKIsAvailable = isAnnexKAvailable(IsAnnexKAvailable, PP, getLangOpts()); StringRef FunctionName = FuncDecl->getName(); + + if (Custom) { + for (const auto &Entry : CustomFunctions) { + if (Entry.Pattern.match(*FuncDecl)) { + StringRef Reason = + Entry.Reason.empty() ? "is marked as unsafe" : Entry.Reason.c_str(); + + if (Entry.Replacement.empty()) { + diag(DeclRef->getExprLoc(), "function %0 %1; it should not be used") + << FuncDecl << Reason << Entry.Replacement + << DeclRef->getSourceRange(); + } else { + diag(DeclRef->getExprLoc(), + "function %0 %1; '%2' should be used instead") + << FuncDecl << Reason << Entry.Replacement + << DeclRef->getSourceRange(); + } + + return; + } + } + + llvm_unreachable("No custom function was matched."); + return; + } + const std::optional ReplacementFunctionName = [&]() -> std::optional { if (AnnexK) { diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.h b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.h index 5adfee60d1a7d..63058c326ef29 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.h +++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNSAFEFUNCTIONSCHECK_H #include "../ClangTidyCheck.h" +#include "../utils/Matchers.h" #include namespace clang::tidy::bugprone { @@ -32,7 +33,18 @@ class UnsafeFunctionsCheck : public ClangTidyCheck { Preprocessor *ModuleExpanderPP) override; void onEndOfTranslationUnit() override; + struct CheckedFunction { + std::string Name; + matchers::MatchesAnyListedNameMatcher::NameMatcher Pattern; + std::string Replacement; + std::string Reason; + }; + private: + const std::vector CustomFunctions; + + // If true, the default set of functions are reported. + const bool ReportDefaultFunctions; /// If true, additional functions from widely used API-s (such as POSIX) are /// added to the list of reported functions. const bool ReportMoreUnsafeFunctions; diff --git a/clang-tools-extra/clang-tidy/utils/Matchers.h b/clang-tools-extra/clang-tidy/utils/Matchers.h index 5fd98db967870..451c4ce92585b 100644 --- a/clang-tools-extra/clang-tidy/utils/Matchers.h +++ b/clang-tools-extra/clang-tidy/utils/Matchers.h @@ -85,15 +85,7 @@ class MatchesAnyListedNameMatcher NameList.begin(), NameList.end(), std::back_inserter(NameMatchers), [](const llvm::StringRef Name) { return NameMatcher(Name); }); } - bool matches( - const NamedDecl &Node, ast_matchers::internal::ASTMatchFinder *Finder, - ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override { - return llvm::any_of(NameMatchers, [&Node](const NameMatcher &NM) { - return NM.match(Node); - }); - } -private: class NameMatcher { llvm::Regex Regex; enum class MatchMode { @@ -136,6 +128,15 @@ class MatchesAnyListedNameMatcher } }; + bool matches( + const NamedDecl &Node, ast_matchers::internal::ASTMatchFinder *Finder, + ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override { + return llvm::any_of(NameMatchers, [&Node](const NameMatcher &NM) { + return NM.match(Node); + }); + } + +private: std::vector NameMatchers; }; diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp index a8214acc50558..a59d1e7ac8409 100644 --- a/clang-tools-extra/clangd/Diagnostics.cpp +++ b/clang-tools-extra/clangd/Diagnostics.cpp @@ -577,17 +577,7 @@ std::vector StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) { for (auto &Diag : Output) { if (const char *ClangDiag = getDiagnosticCode(Diag.ID)) { // Warnings controlled by -Wfoo are better recognized by that name. - const StringRef Warning = [&] { - if (OrigSrcMgr) { - return OrigSrcMgr->getDiagnostics() - .getDiagnosticIDs() - ->getWarningOptionForDiag(Diag.ID); - } - if (!DiagnosticIDs::IsCustomDiag(Diag.ID)) - return DiagnosticIDs{}.getWarningOptionForDiag(Diag.ID); - return StringRef{}; - }(); - + StringRef Warning = DiagnosticIDs::getWarningOptionForDiag(Diag.ID); if (!Warning.empty()) { Diag.Name = ("-W" + Warning).str(); } else { @@ -904,23 +894,20 @@ void StoreDiags::flushLastDiag() { Output.push_back(std::move(*LastDiag)); } -bool isDiagnosticSuppressed(const clang::Diagnostic &Diag, - const llvm::StringSet<> &Suppress, - const LangOptions &LangOpts) { +bool isBuiltinDiagnosticSuppressed(unsigned ID, + const llvm::StringSet<> &Suppress, + const LangOptions &LangOpts) { // Don't complain about header-only stuff in mainfiles if it's a header. // FIXME: would be cleaner to suppress in clang, once we decide whether the // behavior should be to silently-ignore or respect the pragma. - if (Diag.getID() == diag::pp_pragma_sysheader_in_main_file && - LangOpts.IsHeaderFile) + if (ID == diag::pp_pragma_sysheader_in_main_file && LangOpts.IsHeaderFile) return true; - if (const char *CodePtr = getDiagnosticCode(Diag.getID())) { + if (const char *CodePtr = getDiagnosticCode(ID)) { if (Suppress.contains(normalizeSuppressedCode(CodePtr))) return true; } - StringRef Warning = - Diag.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag( - Diag.getID()); + StringRef Warning = DiagnosticIDs::getWarningOptionForDiag(ID); if (!Warning.empty() && Suppress.contains(Warning)) return true; return false; diff --git a/clang-tools-extra/clangd/Diagnostics.h b/clang-tools-extra/clangd/Diagnostics.h index c45d8dc3aa6ce..d4c0478c63a5c 100644 --- a/clang-tools-extra/clangd/Diagnostics.h +++ b/clang-tools-extra/clangd/Diagnostics.h @@ -181,11 +181,11 @@ class StoreDiags : public DiagnosticConsumer { }; /// Determine whether a (non-clang-tidy) diagnostic is suppressed by config. -bool isDiagnosticSuppressed(const clang::Diagnostic &Diag, - const llvm::StringSet<> &Suppressed, - const LangOptions &); +bool isBuiltinDiagnosticSuppressed(unsigned ID, + const llvm::StringSet<> &Suppressed, + const LangOptions &); /// Take a user-specified diagnostic code, and convert it to a normalized form -/// stored in the config and consumed by isDiagnosticsSuppressed. +/// stored in the config and consumed by isBuiltinDiagnosticsSuppressed. /// /// (This strips err_ and -W prefix so we can match with or without them.) llvm::StringRef normalizeSuppressedCode(llvm::StringRef); diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp index 5cf1691ce3961..045d32afbc938 100644 --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -342,7 +342,7 @@ void applyWarningOptions(llvm::ArrayRef ExtraArgs, if (Enable) { if (Diags.getDiagnosticLevel(ID, SourceLocation()) < DiagnosticsEngine::Warning) { - auto Group = Diags.getDiagnosticIDs()->getGroupForDiag(ID); + auto Group = DiagnosticIDs::getGroupForDiag(ID); if (!Group || !EnabledGroups(*Group)) continue; Diags.setSeverity(ID, diag::Severity::Warning, SourceLocation()); @@ -585,8 +585,8 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs, ASTDiags.setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) { if (Cfg.Diagnostics.SuppressAll || - isDiagnosticSuppressed(Info, Cfg.Diagnostics.Suppress, - Clang->getLangOpts())) + isBuiltinDiagnosticSuppressed(Info.getID(), Cfg.Diagnostics.Suppress, + Clang->getLangOpts())) return DiagnosticsEngine::Ignored; auto It = OverriddenSeverity.find(Info.getID()); diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp index 1fe534d78daec..c14c4d1ba103f 100644 --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -621,8 +621,8 @@ buildPreamble(PathRef FileName, CompilerInvocation CI, PreambleDiagnostics.setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) { if (Cfg.Diagnostics.SuppressAll || - isDiagnosticSuppressed(Info, Cfg.Diagnostics.Suppress, - CI.getLangOpts())) + isBuiltinDiagnosticSuppressed(Info.getID(), Cfg.Diagnostics.Suppress, + CI.getLangOpts())) return DiagnosticsEngine::Ignored; switch (Info.getID()) { case diag::warn_no_newline_eof: diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp index cf9b42828568d..4ecfdf0184ab4 100644 --- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp +++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp @@ -298,41 +298,20 @@ TEST_F(ConfigCompileTests, DiagnosticSuppression) { "unreachable-code", "unused-variable", "typecheck_bool_condition", "unexpected_friend", "warn_alloca")); - clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, nullptr, - new clang::IgnoringDiagConsumer); - - using Diag = clang::Diagnostic; - { - auto D = DiagEngine.Report(diag::warn_unreachable); - EXPECT_TRUE(isDiagnosticSuppressed( - Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions())); - } + EXPECT_TRUE(isBuiltinDiagnosticSuppressed( + diag::warn_unreachable, Conf.Diagnostics.Suppress, LangOptions())); // Subcategory not respected/suppressed. - { - auto D = DiagEngine.Report(diag::warn_unreachable_break); - EXPECT_FALSE(isDiagnosticSuppressed( - Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions())); - } - { - auto D = DiagEngine.Report(diag::warn_unused_variable); - EXPECT_TRUE(isDiagnosticSuppressed( - Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions())); - } - { - auto D = DiagEngine.Report(diag::err_typecheck_bool_condition); - EXPECT_TRUE(isDiagnosticSuppressed( - Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions())); - } - { - auto D = DiagEngine.Report(diag::err_unexpected_friend); - EXPECT_TRUE(isDiagnosticSuppressed( - Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions())); - } - { - auto D = DiagEngine.Report(diag::warn_alloca); - EXPECT_TRUE(isDiagnosticSuppressed( - Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions())); - } + EXPECT_FALSE(isBuiltinDiagnosticSuppressed( + diag::warn_unreachable_break, Conf.Diagnostics.Suppress, LangOptions())); + EXPECT_TRUE(isBuiltinDiagnosticSuppressed( + diag::warn_unused_variable, Conf.Diagnostics.Suppress, LangOptions())); + EXPECT_TRUE(isBuiltinDiagnosticSuppressed(diag::err_typecheck_bool_condition, + Conf.Diagnostics.Suppress, + LangOptions())); + EXPECT_TRUE(isBuiltinDiagnosticSuppressed( + diag::err_unexpected_friend, Conf.Diagnostics.Suppress, LangOptions())); + EXPECT_TRUE(isBuiltinDiagnosticSuppressed( + diag::warn_alloca, Conf.Diagnostics.Suppress, LangOptions())); Frag.Diagnostics.Suppress.emplace_back("*"); EXPECT_TRUE(compileAndApply()); diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp index efb2e5ed2fbe1..7a47d6ebebf3b 100644 --- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -1984,6 +1984,30 @@ TEST(Diagnostics, Tags) { withTag(DiagnosticTag::Deprecated))))); } +TEST(Diagnostics, TidyDiagsArentAffectedFromWerror) { + TestTU TU; + TU.ExtraArgs = {"-Werror"}; + Annotations Test(R"cpp($typedef[[typedef int INT]]; // error-ok)cpp"); + TU.Code = Test.code().str(); + TU.ClangTidyProvider = addTidyChecks("modernize-use-using"); + EXPECT_THAT( + TU.build().getDiagnostics(), + ifTidyChecks(UnorderedElementsAre( + AllOf(Diag(Test.range("typedef"), "use 'using' instead of 'typedef'"), + // Make sure severity for clang-tidy finding isn't bumped to + // error due to Werror in compile flags. + diagSeverity(DiagnosticsEngine::Warning))))); + + TU.ClangTidyProvider = + addTidyChecks("modernize-use-using", /*WarningsAsErrors=*/"modernize-*"); + EXPECT_THAT( + TU.build().getDiagnostics(), + ifTidyChecks(UnorderedElementsAre( + AllOf(Diag(Test.range("typedef"), "use 'using' instead of 'typedef'"), + // Unless bumped explicitly with WarnAsError. + diagSeverity(DiagnosticsEngine::Error))))); +} + TEST(Diagnostics, DeprecatedDiagsAreHints) { ClangdDiagnosticOptions Opts; std::optional Diag; diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 9a130a23b6e89..7d37a4b03222c 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -125,6 +125,10 @@ Changes in existing checks ` check by fixing a crash when determining if an ``enable_if[_t]`` was found. +- Improved :doc:`bugprone-posix-return + ` check to support integer literals + as LHS and posix call as RHS of comparison. + - Improved :doc:`bugprone-sizeof-expression ` check to find suspicious usages of ``sizeof()``, ``alignof()``, and ``offsetof()`` when adding or @@ -135,6 +139,10 @@ Changes in existing checks `bsl::optional` and `bdlb::NullableValue` from _. +- Improved :doc:`bugprone-unsafe-functions + ` check to allow specifying + additional functions to match. + - Improved :doc:`cert-flp30-c ` check to fix false positive that floating point variable is only used in increment expression. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst index a0a267883b6fe..fb070627e31b1 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-functions.rst @@ -19,6 +19,8 @@ The check implements the following rules from the CERT C Coding Standard: Unsafe functions ---------------- +The following functions are reported if :option:`ReportDefaultFunctions` is enabled. + If *Annex K.* is available, a replacement from *Annex K.* is suggested for the following functions: @@ -45,8 +47,7 @@ The following functions are always checked, regardless of *Annex K* availability - ``rewind``, suggested replacement: ``fseek`` - ``setbuf``, suggested replacement: ``setvbuf`` -If `ReportMoreUnsafeFunctions -`_ is enabled, +If :option:`ReportMoreUnsafeFunctions` is enabled, the following functions are also checked: - ``bcmp``, suggested replacement: ``memcmp`` @@ -74,6 +75,44 @@ Both macros have to be defined to suggest replacement functions from *Annex K.* ``__STDC_WANT_LIB_EXT1__`` must be defined to ``1`` by the user **before** including any system headers. +.. _CustomFunctions: + +Custom functions +---------------- + +The option :option:`CustomFunctions` allows the user to define custom functions to be +checked. The format is the following, without newlines: + +.. code:: + + bugprone-unsafe-functions.CustomFunctions=" + functionRegex1[, replacement1[, reason1]]; + functionRegex2[, replacement2[, reason2]]; + ... + " + +The functions are matched using POSIX extended regular expressions. +*(Note: The regular expressions do not support negative* ``(?!)`` *matches.)* + +The `reason` is optional and is used to provide additional information about the +reasoning behind the replacement. The default reason is `is marked as unsafe`. + +If `replacement` is empty, the text `it should not be used` will be shown +instead of the suggestion for a replacement. + +As an example, the configuration `^original$, replacement, is deprecated;` +will produce the following diagnostic message. + +.. code:: c + + original(); // warning: function 'original' is deprecated; 'replacement' should be used instead. + ::std::original(); // no-warning + original_function(); // no-warning + +If the regular expression contains the character `:`, it is matched against the +qualified name (i.e. ``std::original``), otherwise the regex is matched against the unqualified name (``original``). +If the regular expression starts with `::` (or `^::`), it is matched against the +fully qualified name (``::std::original``). Options ------- @@ -86,6 +125,19 @@ Options this option enables. Default is `true`. +.. option:: ReportDefaultFunctions + + When `true`, the check reports the default set of functions. + Consider changing the setting to false if you only want to see custom + functions matched via :ref:`custom functions`. + Default is `true`. + +.. option:: CustomFunctions + + A semicolon-separated list of custom functions to be matched. A matched + function contains a regular expression, an optional name of the replacement + function, and an optional reason, separated by comma. For more information, + see :ref:`Custom functions`. Examples -------- diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/posix-return.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/posix-return.cpp index 271893c707069..76d447a71d68b 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/posix-return.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/posix-return.cpp @@ -74,6 +74,9 @@ void warningLessThanZero() { if (pthread_yield() < 0) {} // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: // CHECK-FIXES: pthread_yield() > 0 + if (0 > pthread_yield() ) {} + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: + // CHECK-FIXES: 0 < pthread_yield() } @@ -90,7 +93,8 @@ void warningAlwaysTrue() { // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: if (pthread_yield() >= 0) {} // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: - + if (0 <= pthread_yield()) {} + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: } void warningEqualsNegative() { @@ -120,7 +124,14 @@ void warningEqualsNegative() { // CHECK-MESSAGES: :[[@LINE-1]]:46: warning: if (pthread_create(NULL, NULL, NULL, NULL) < -1) {} // CHECK-MESSAGES: :[[@LINE-1]]:46: warning: - + if (-1 == pthread_create(NULL, NULL, NULL, NULL)) {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: + if (-1 != pthread_create(NULL, NULL, NULL, NULL)) {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: + if (-1 >= pthread_create(NULL, NULL, NULL, NULL)) {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: + if (-1 > pthread_create(NULL, NULL, NULL, NULL)) {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: } void WarningWithMacro() { @@ -162,6 +173,16 @@ void noWarning() { if (posix_openpt(0) < -1) {} if (posix_fadvise(0, 0, 0, 0) <= 0) {} if (posix_fadvise(0, 0, 0, 0) == 1) {} + if (0 > posix_openpt(0)) {} + if (0 >= posix_openpt(0)) {} + if (-1 == posix_openpt(0)) {} + if (-1 != posix_openpt(0)) {} + if (-1 >= posix_openpt(0)) {} + if (-1 > posix_openpt(0)) {} + if (posix_fadvise(0, 0, 0, 0) <= 0) {} + if (posix_fadvise(0, 0, 0, 0) == 1) {} + if (0 >= posix_fadvise(0, 0, 0, 0)) {} + if (1 == posix_fadvise(0, 0, 0, 0)) {} } namespace i { diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions-custom-regex.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions-custom-regex.cpp new file mode 100644 index 0000000000000..fc97d1bc93bc5 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions-custom-regex.cpp @@ -0,0 +1,44 @@ +// RUN: %check_clang_tidy -check-suffix=NON-STRICT-REGEX %s bugprone-unsafe-functions %t --\ +// RUN: -config="{CheckOptions: {bugprone-unsafe-functions.CustomFunctions: '::name_match,replacement,is a qualname match;^::prefix_match,,is matched on qualname prefix'}}" +// RUN: %check_clang_tidy -check-suffix=STRICT-REGEX %s bugprone-unsafe-functions %t --\ +// RUN: -config="{CheckOptions: {bugprone-unsafe-functions.CustomFunctions: '^name_match$,replacement,is matched on function name only;^::prefix_match$,,is a full qualname match'}}" + +void name_match(); +void prefix_match(); + +namespace regex_test { +void name_match(); +void prefix_match(); +} + +void name_match_regex(); +void prefix_match_regex(); + +void f1() { + name_match(); + // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'name_match' is a qualname match; 'replacement' should be used instead + // CHECK-MESSAGES-STRICT-REGEX: :[[@LINE-2]]:3: warning: function 'name_match' is matched on function name only; 'replacement' should be used instead + prefix_match(); + // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'prefix_match' is matched on qualname prefix; it should not be used + // CHECK-MESSAGES-STRICT-REGEX: :[[@LINE-2]]:3: warning: function 'prefix_match' is a full qualname match; it should not be used + + ::name_match(); + // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'name_match' is a qualname match; 'replacement' should be used instead + // CHECK-MESSAGES-STRICT-REGEX: :[[@LINE-2]]:3: warning: function 'name_match' is matched on function name only; 'replacement' should be used instead + regex_test::name_match(); + // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'name_match' is a qualname match; 'replacement' should be used instead + // CHECK-MESSAGES-STRICT-REGEX: :[[@LINE-2]]:3: warning: function 'name_match' is matched on function name only; 'replacement' should be used instead + name_match_regex(); + // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'name_match_regex' is a qualname match; 'replacement' should be used instead + // no-warning STRICT-REGEX + + ::prefix_match(); + // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'prefix_match' is matched on qualname prefix; it should not be used + // CHECK-MESSAGES-STRICT-REGEX: :[[@LINE-2]]:3: warning: function 'prefix_match' is a full qualname match; it should not be used + regex_test::prefix_match(); + // no-warning NON-STRICT-REGEX + // no-warning STRICT-REGEX + prefix_match_regex(); + // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'prefix_match_regex' is matched on qualname prefix; it should not be used + // no-warning STRICT-REGEX +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions-custom.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions-custom.c new file mode 100644 index 0000000000000..7fd71ec2f2e7b --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions-custom.c @@ -0,0 +1,27 @@ +// RUN: %check_clang_tidy -check-suffix=NON-STRICT-REGEX %s bugprone-unsafe-functions %t --\ +// RUN: -config="{CheckOptions: {bugprone-unsafe-functions.CustomFunctions: '::name_match,replacement,is a qualname match;^::prefix_match,,is matched on qualname prefix'}}" +// RUN: %check_clang_tidy -check-suffix=STRICT-REGEX %s bugprone-unsafe-functions %t --\ +// RUN: -config="{CheckOptions: {bugprone-unsafe-functions.CustomFunctions: '^name_match$,replacement,is matched on function name only;^::prefix_match$,,is a full qualname match'}}" + +void name_match(); +void prefix_match(); + +void name_match_regex(); +void prefix_match_regex(); + +void f1() { + name_match(); + // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'name_match' is a qualname match; 'replacement' should be used instead + // CHECK-MESSAGES-STRICT-REGEX: :[[@LINE-2]]:3: warning: function 'name_match' is matched on function name only; 'replacement' should be used instead + prefix_match(); + // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'prefix_match' is matched on qualname prefix; it should not be used + // CHECK-MESSAGES-STRICT-REGEX: :[[@LINE-2]]:3: warning: function 'prefix_match' is a full qualname match; it should not be used + + name_match_regex(); + // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'name_match_regex' is a qualname match; 'replacement' should be used instead + // no-warning STRICT-REGEX + + prefix_match_regex(); + // CHECK-MESSAGES-NON-STRICT-REGEX: :[[@LINE-1]]:3: warning: function 'prefix_match_regex' is matched on qualname prefix; it should not be used + // no-warning STRICT-REGEX +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions.c index 4bc2bad996d70..0409dd6bfcaa3 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions.c +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-functions.c @@ -12,6 +12,12 @@ // RUN: %check_clang_tidy -check-suffix=WITH-ANNEX-K-CERT-ONLY %s bugprone-unsafe-functions %t -- \ // RUN: -config="{CheckOptions: {bugprone-unsafe-functions.ReportMoreUnsafeFunctions: false}}" \ // RUN: -- -D__STDC_LIB_EXT1__=1 -D__STDC_WANT_LIB_EXT1__=1 +// RUN: %check_clang_tidy -check-suffix=WITH-NONE-ENABLED %s bugprone-unsafe-functions %t --\ +// RUN: -config="{CheckOptions: {bugprone-unsafe-functions.ReportDefaultFunctions: false}}" \ +// RUN: -- -D__STDC_LIB_EXT1__=1 -D__STDC_WANT_LIB_EXT1__=1 + +// CHECK-MESSAGES-WITH-NONE-ENABLED: 1 warning generated +// CHECK-MESSAGES-WITH-NONE-ENABLED: Suppressed 1 warnings typedef __SIZE_TYPE__ size_t; typedef __WCHAR_TYPE__ wchar_t; diff --git a/clang/CodeOwners.rst b/clang/CodeOwners.rst index 2ae04c129eb76..f067b7183ae73 100644 --- a/clang/CodeOwners.rst +++ b/clang/CodeOwners.rst @@ -120,7 +120,7 @@ OpenBSD driver Driver parts not covered by someone else ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | Fangrui Song -| maskray\@google.com (email), MaskRay (Phabricator), MaskRay (GitHub) +| i\@maskray.me (email), MaskRay (Phabricator), MaskRay (GitHub) Tools diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 4da99e899e7f7..f8a20a1e22472 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -133,7 +133,7 @@ def from_param(cls, param: str | bytes | None) -> c_interop_string: ) @staticmethod - def to_python_string(x: c_interop_string, *args: Any) -> str | None: + def to_python_string(x: c_interop_string) -> str | None: return x.value @@ -241,9 +241,9 @@ def __del__(self) -> None: conf.lib.clang_disposeString(self) @staticmethod - def from_result(res: _CXString, fn: Any = None, args: Any = None) -> str: + def from_result(res: _CXString) -> str: assert isinstance(res, _CXString) - pystr: str | None = conf.lib.clang_getCString(res) + pystr = c_interop_string.to_python_string(conf.lib.clang_getCString(res)) if pystr is None: return "" return pystr @@ -424,7 +424,7 @@ def location(self): @property def spelling(self): - return conf.lib.clang_getDiagnosticSpelling(self) # type: ignore [no-any-return] + return _CXString.from_result(conf.lib.clang_getDiagnosticSpelling(self)) @property def ranges(self) -> NoSliceSequence[SourceRange]: @@ -453,7 +453,9 @@ def __len__(self) -> int: def __getitem__(self, key: int) -> FixIt: range = SourceRange() - value = conf.lib.clang_getDiagnosticFixIt(self.diag, key, byref(range)) + value = _CXString.from_result( + conf.lib.clang_getDiagnosticFixIt(self.diag, key, byref(range)) + ) if len(value) == 0: raise IndexError @@ -486,12 +488,12 @@ def category_number(self): @property def category_name(self): """The string name of the category for this diagnostic.""" - return conf.lib.clang_getDiagnosticCategoryText(self) # type: ignore [no-any-return] + return _CXString.from_result(conf.lib.clang_getDiagnosticCategoryText(self)) @property def option(self): """The command-line option that enables this diagnostic.""" - return conf.lib.clang_getDiagnosticOption(self, None) # type: ignore [no-any-return] + return _CXString.from_result(conf.lib.clang_getDiagnosticOption(self, None)) @property def disable_option(self): @@ -511,7 +513,7 @@ def format(self, options=None): options = conf.lib.clang_defaultDiagnosticDisplayOptions() if options & ~Diagnostic._FormatOptionsMask: raise ValueError("Invalid format options") - return conf.lib.clang_formatDiagnostic(self, options) # type: ignore [no-any-return] + return _CXString.from_result(conf.lib.clang_formatDiagnostic(self, options)) def __repr__(self): return "" % ( @@ -1734,7 +1736,7 @@ def get_definition(self): """ # TODO: Should probably check that this is either a reference or # declaration prior to issuing the lookup. - return conf.lib.clang_getCursorDefinition(self) # type: ignore [no-any-return] + return Cursor.from_result(conf.lib.clang_getCursorDefinition(self), self) def get_usr(self): """Return the Unified Symbol Resolution (USR) for the entity referenced @@ -1745,13 +1747,13 @@ def get_usr(self): program. USRs can be compared across translation units to determine, e.g., when references in one translation refer to an entity defined in another translation unit.""" - return conf.lib.clang_getCursorUSR(self) # type: ignore [no-any-return] + return _CXString.from_result(conf.lib.clang_getCursorUSR(self)) def get_included_file(self): """Returns the File that is included by the current inclusion cursor.""" assert self.kind == CursorKind.INCLUSION_DIRECTIVE - return conf.lib.clang_getIncludedFile(self) # type: ignore [no-any-return] + return File.from_result(conf.lib.clang_getIncludedFile(self), self) @property def kind(self): @@ -1762,7 +1764,9 @@ def kind(self): def spelling(self): """Return the spelling of the entity pointed at by the cursor.""" if not hasattr(self, "_spelling"): - self._spelling = conf.lib.clang_getCursorSpelling(self) + self._spelling = _CXString.from_result( + conf.lib.clang_getCursorSpelling(self) + ) return self._spelling @@ -1776,7 +1780,9 @@ def displayname(self): arguments of a class template specialization. """ if not hasattr(self, "_displayname"): - self._displayname = conf.lib.clang_getCursorDisplayName(self) + self._displayname = _CXString.from_result( + conf.lib.clang_getCursorDisplayName(self) + ) return self._displayname @@ -1784,7 +1790,9 @@ def displayname(self): def mangled_name(self): """Return the mangled name for the entity referenced by this cursor.""" if not hasattr(self, "_mangled_name"): - self._mangled_name = conf.lib.clang_Cursor_getMangling(self) + self._mangled_name = _CXString.from_result( + conf.lib.clang_Cursor_getMangling(self) + ) return self._mangled_name @@ -1876,7 +1884,7 @@ def type(self): Retrieve the Type (if any) of the entity pointed at by the cursor. """ if not hasattr(self, "_type"): - self._type = conf.lib.clang_getCursorType(self) + self._type = Type.from_result(conf.lib.clang_getCursorType(self), (self,)) return self._type @@ -1890,7 +1898,9 @@ def canonical(self): declarations will be identical. """ if not hasattr(self, "_canonical"): - self._canonical = conf.lib.clang_getCanonicalCursor(self) + self._canonical = Cursor.from_cursor_result( + conf.lib.clang_getCanonicalCursor(self), self + ) return self._canonical @@ -1898,7 +1908,9 @@ def canonical(self): def result_type(self): """Retrieve the Type of the result for this Cursor.""" if not hasattr(self, "_result_type"): - self._result_type = conf.lib.clang_getCursorResultType(self) + self._result_type = Type.from_result( + conf.lib.clang_getCursorResultType(self), (self,) + ) return self._result_type @@ -1925,7 +1937,9 @@ def underlying_typedef_type(self): """ if not hasattr(self, "_underlying_type"): assert self.kind.is_declaration() - self._underlying_type = conf.lib.clang_getTypedefDeclUnderlyingType(self) + self._underlying_type = Type.from_result( + conf.lib.clang_getTypedefDeclUnderlyingType(self), (self,) + ) return self._underlying_type @@ -1938,7 +1952,9 @@ def enum_type(self): """ if not hasattr(self, "_enum_type"): assert self.kind == CursorKind.ENUM_DECL - self._enum_type = conf.lib.clang_getEnumDeclIntegerType(self) + self._enum_type = Type.from_result( + conf.lib.clang_getEnumDeclIntegerType(self), (self,) + ) return self._enum_type @@ -1972,7 +1988,9 @@ def enum_value(self): def objc_type_encoding(self): """Return the Objective-C type encoding as a str.""" if not hasattr(self, "_objc_type_encoding"): - self._objc_type_encoding = conf.lib.clang_getDeclObjCTypeEncoding(self) + self._objc_type_encoding = _CXString.from_result( + conf.lib.clang_getDeclObjCTypeEncoding(self) + ) return self._objc_type_encoding @@ -1988,7 +2006,9 @@ def hash(self): def semantic_parent(self): """Return the semantic parent for this cursor.""" if not hasattr(self, "_semantic_parent"): - self._semantic_parent = conf.lib.clang_getCursorSemanticParent(self) + self._semantic_parent = Cursor.from_cursor_result( + conf.lib.clang_getCursorSemanticParent(self), self + ) return self._semantic_parent @@ -1996,7 +2016,9 @@ def semantic_parent(self): def lexical_parent(self): """Return the lexical parent for this cursor.""" if not hasattr(self, "_lexical_parent"): - self._lexical_parent = conf.lib.clang_getCursorLexicalParent(self) + self._lexical_parent = Cursor.from_cursor_result( + conf.lib.clang_getCursorLexicalParent(self), self + ) return self._lexical_parent @@ -2014,25 +2036,27 @@ def referenced(self): representing the entity that it references. """ if not hasattr(self, "_referenced"): - self._referenced = conf.lib.clang_getCursorReferenced(self) + self._referenced = Cursor.from_result( + conf.lib.clang_getCursorReferenced(self), self + ) return self._referenced @property def brief_comment(self): """Returns the brief comment text associated with that Cursor""" - return conf.lib.clang_Cursor_getBriefCommentText(self) # type: ignore [no-any-return] + return _CXString.from_result(conf.lib.clang_Cursor_getBriefCommentText(self)) @property def raw_comment(self): """Returns the raw comment text associated with that Cursor""" - return conf.lib.clang_Cursor_getRawCommentText(self) # type: ignore [no-any-return] + return _CXString.from_result(conf.lib.clang_Cursor_getRawCommentText(self)) def get_arguments(self): """Return an iterator for accessing the arguments of this cursor.""" num_args = conf.lib.clang_Cursor_getNumArguments(self) for i in range(0, num_args): - yield conf.lib.clang_Cursor_getArgument(self, i) + yield Cursor.from_result(conf.lib.clang_Cursor_getArgument(self, i), self) def get_num_template_arguments(self): """Returns the number of template args associated with this cursor.""" @@ -2041,11 +2065,15 @@ def get_num_template_arguments(self): def get_template_argument_kind(self, num): """Returns the TemplateArgumentKind for the indicated template argument.""" - return conf.lib.clang_Cursor_getTemplateArgumentKind(self, num) # type: ignore [no-any-return] + return TemplateArgumentKind.from_id( + conf.lib.clang_Cursor_getTemplateArgumentKind(self, num) + ) def get_template_argument_type(self, num): """Returns the CXType for the indicated template argument.""" - return conf.lib.clang_Cursor_getTemplateArgumentType(self, num) # type: ignore [no-any-return] + return Type.from_result( + conf.lib.clang_Cursor_getTemplateArgumentType(self, num), (self, num) + ) def get_template_argument_value(self, num): """Returns the value of the indicated arg as a signed 64b integer.""" @@ -2116,7 +2144,7 @@ def get_bitfield_width(self): return conf.lib.clang_getFieldDeclBitWidth(self) # type: ignore [no-any-return] @staticmethod - def from_result(res, fn, args): + def from_result(res, arg): assert isinstance(res, Cursor) # FIXME: There should just be an isNull method. if res == conf.lib.clang_getNullCursor(): @@ -2125,14 +2153,10 @@ def from_result(res, fn, args): # Store a reference to the TU in the Python object so it won't get GC'd # before the Cursor. tu = None - for arg in args: - if isinstance(arg, TranslationUnit): - tu = arg - break - - if hasattr(arg, "translation_unit"): - tu = arg.translation_unit - break + if isinstance(arg, TranslationUnit): + tu = arg + elif hasattr(arg, "translation_unit"): + tu = arg.translation_unit assert tu is not None @@ -2140,12 +2164,12 @@ def from_result(res, fn, args): return res @staticmethod - def from_cursor_result(res, fn, args): + def from_cursor_result(res, arg): assert isinstance(res, Cursor) if res == conf.lib.clang_getNullCursor(): return None - res._tu = args[0]._tu + res._tu = arg._tu return res @@ -2250,7 +2274,7 @@ class TypeKind(BaseEnumeration): @property def spelling(self): """Retrieve the spelling of this TypeKind.""" - return conf.lib.clang_getTypeKindSpelling(self.value) # type: ignore [no-any-return] + return _CXString.from_result(conf.lib.clang_getTypeKindSpelling(self.value)) INVALID = 0 UNEXPOSED = 1 @@ -2438,7 +2462,9 @@ def __getitem__(self, key: int) -> Type: "%d > %d" % (key, len(self)) ) - result: Type = conf.lib.clang_getArgType(self.parent, key) + result = Type.from_result( + conf.lib.clang_getArgType(self.parent, key), (self.parent, key) + ) if result.kind == TypeKind.INVALID: raise IndexError("Argument could not be retrieved.") @@ -2454,7 +2480,7 @@ def element_type(self): If accessed on a type that is not an array, complex, or vector type, an exception will be raised. """ - result = conf.lib.clang_getElementType(self) + result = Type.from_result(conf.lib.clang_getElementType(self), (self,)) if result.kind == TypeKind.INVALID: raise Exception("Element type not available on this type.") @@ -2482,7 +2508,7 @@ def translation_unit(self): return self._tu @staticmethod - def from_result(res, fn, args): + def from_result(res, args): assert isinstance(res, Type) tu = None @@ -2500,7 +2526,9 @@ def get_num_template_arguments(self): return conf.lib.clang_Type_getNumTemplateArguments(self) # type: ignore [no-any-return] def get_template_argument_type(self, num): - return conf.lib.clang_Type_getTemplateArgumentAsType(self, num) # type: ignore [no-any-return] + return Type.from_result( + conf.lib.clang_Type_getTemplateArgumentAsType(self, num), (self, num) + ) def get_canonical(self): """ @@ -2512,7 +2540,7 @@ def get_canonical(self): example, if 'T' is a typedef for 'int', the canonical type for 'T' would be 'int'. """ - return conf.lib.clang_getCanonicalType(self) # type: ignore [no-any-return] + return Type.from_result(conf.lib.clang_getCanonicalType(self), (self,)) def is_const_qualified(self): """Determine whether a Type has the "const" qualifier set. @@ -2548,7 +2576,7 @@ def get_address_space(self): return conf.lib.clang_getAddressSpace(self) # type: ignore [no-any-return] def get_typedef_name(self): - return conf.lib.clang_getTypedefName(self) # type: ignore [no-any-return] + return _CXString.from_result(conf.lib.clang_getTypedefName(self)) def is_pod(self): """Determine whether this Type represents plain old data (POD).""" @@ -2558,25 +2586,25 @@ def get_pointee(self): """ For pointer types, returns the type of the pointee. """ - return conf.lib.clang_getPointeeType(self) # type: ignore [no-any-return] + return Type.from_result(conf.lib.clang_getPointeeType(self), (self,)) def get_declaration(self): """ Return the cursor for the declaration of the given type. """ - return conf.lib.clang_getTypeDeclaration(self) # type: ignore [no-any-return] + return Cursor.from_result(conf.lib.clang_getTypeDeclaration(self), self) def get_result(self): """ Retrieve the result type associated with a function type. """ - return conf.lib.clang_getResultType(self) # type: ignore [no-any-return] + return Type.from_result(conf.lib.clang_getResultType(self), (self,)) def get_array_element_type(self): """ Retrieve the type of the elements of the array type. """ - return conf.lib.clang_getArrayElementType(self) # type: ignore [no-any-return] + return Type.from_result(conf.lib.clang_getArrayElementType(self), (self,)) def get_array_size(self): """ @@ -2588,13 +2616,13 @@ def get_class_type(self): """ Retrieve the class type of the member pointer type. """ - return conf.lib.clang_Type_getClassType(self) # type: ignore [no-any-return] + return Type.from_result(conf.lib.clang_Type_getClassType(self), (self,)) def get_named_type(self): """ Retrieve the type named by the qualified-id. """ - return conf.lib.clang_Type_getNamedType(self) # type: ignore [no-any-return] + return Type.from_result(conf.lib.clang_Type_getNamedType(self), (self,)) def get_align(self): """ @@ -2647,7 +2675,7 @@ def get_exception_specification_kind(self): @property def spelling(self): """Retrieve the spelling of this Type.""" - return conf.lib.clang_getTypeSpelling(self) # type: ignore [no-any-return] + return _CXString.from_result(conf.lib.clang_getTypeSpelling(self)) def __eq__(self, other): if type(other) != type(self): @@ -2737,7 +2765,9 @@ def __repr__(self): def spelling(self): if self.__kindNumber in SpellingCache: return SpellingCache[self.__kindNumber] - return conf.lib.clang_getCompletionChunkText(self.cs, self.key) # type: ignore [no-any-return] + return _CXString.from_result( + conf.lib.clang_getCompletionChunkText(self.cs, self.key) + ) # We do not use @CachedProperty here, as the manual implementation is # apparently still significantly faster. Please profile carefully if you @@ -2839,7 +2869,9 @@ def availability(self): @property def briefComment(self): if conf.function_exists("clang_getCompletionBriefComment"): - return conf.lib.clang_getCompletionBriefComment(self.obj) # type: ignore [no-any-return] + return _CXString.from_result( + conf.lib.clang_getCompletionBriefComment(self.obj) + ) return _CXString() def __repr__(self): @@ -3125,12 +3157,12 @@ def __del__(self): @property def cursor(self): """Retrieve the cursor that represents the given translation unit.""" - return conf.lib.clang_getTranslationUnitCursor(self) # type: ignore [no-any-return] + return Cursor.from_result(conf.lib.clang_getTranslationUnitCursor(self), self) @property def spelling(self): """Get the original translation unit source file name.""" - return conf.lib.clang_getTranslationUnitSpelling(self) # type: ignore [no-any-return] + return _CXString.from_result(conf.lib.clang_getTranslationUnitSpelling(self)) def get_includes(self): """ @@ -3356,7 +3388,7 @@ def from_name(translation_unit, file_name): @property def name(self): """Return the complete file and path name of the file.""" - return conf.lib.clang_getFileName(self) # type: ignore [no-any-return] + return _CXString.from_result(conf.lib.clang_getFileName(self)) @property def time(self): @@ -3370,12 +3402,12 @@ def __repr__(self): return "" % (self.name) @staticmethod - def from_result(res, fn, args): + def from_result(res, arg): assert isinstance(res, c_object_p) res = File(res) # Copy a reference to the TranslationUnit to prevent premature GC. - res._tu = args[0]._tu + res._tu = arg._tu return res @@ -3440,12 +3472,16 @@ def __init__(self, cmd, ccmds): @property def directory(self): """Get the working directory for this CompileCommand""" - return conf.lib.clang_CompileCommand_getDirectory(self.cmd) # type: ignore [no-any-return] + return _CXString.from_result( + conf.lib.clang_CompileCommand_getDirectory(self.cmd) + ) @property def filename(self): """Get the working filename for this CompileCommand""" - return conf.lib.clang_CompileCommand_getFilename(self.cmd) # type: ignore [no-any-return] + return _CXString.from_result( + conf.lib.clang_CompileCommand_getFilename(self.cmd) + ) @property def arguments(self): @@ -3457,7 +3493,9 @@ def arguments(self): """ length = conf.lib.clang_CompileCommand_getNumArgs(self.cmd) for i in range(length): - yield conf.lib.clang_CompileCommand_getArg(self.cmd, i) + yield _CXString.from_result( + conf.lib.clang_CompileCommand_getArg(self.cmd, i) + ) class CompileCommands: @@ -3482,7 +3520,7 @@ def __getitem__(self, i): return CompileCommand(cc, self) @staticmethod - def from_result(res, fn, args): + def from_result(res): if not res: return None return CompileCommands(res) @@ -3500,7 +3538,7 @@ def __del__(self): conf.lib.clang_CompilationDatabase_dispose(self) @staticmethod - def from_result(res, fn, args): + def from_result(res): if not res: raise CompilationDatabaseError(0, "CompilationDatabase loading failed") return CompilationDatabase(res) @@ -3510,8 +3548,10 @@ def fromDirectory(buildDir): """Builds a CompilationDatabase from the database found in buildDir""" errorCode = c_uint() try: - cdb = conf.lib.clang_CompilationDatabase_fromDirectory( - os.fspath(buildDir), byref(errorCode) + cdb = CompilationDatabase.from_result( + conf.lib.clang_CompilationDatabase_fromDirectory( + os.fspath(buildDir), byref(errorCode) + ) ) except CompilationDatabaseError as e: raise CompilationDatabaseError( @@ -3524,8 +3564,10 @@ def getCompileCommands(self, filename): Get an iterable object providing all the CompileCommands available to build filename. Returns None if filename is not found in the database. """ - return conf.lib.clang_CompilationDatabase_getCompileCommands( # type: ignore [no-any-return] - self, os.fspath(filename) + return CompileCommands.from_result( + conf.lib.clang_CompilationDatabase_getCompileCommands( # type: ignore [no-any-return] + self, os.fspath(filename) + ) ) def getAllCompileCommands(self): @@ -3533,7 +3575,9 @@ def getAllCompileCommands(self): Get an iterable object providing all the CompileCommands available from the database. """ - return conf.lib.clang_CompilationDatabase_getAllCompileCommands(self) # type: ignore [no-any-return] + return CompileCommands.from_result( + conf.lib.clang_CompilationDatabase_getAllCompileCommands(self) # type: ignore [no-any-return] + ) class Token(Structure): @@ -3554,7 +3598,7 @@ def spelling(self): This is the textual representation of the token in source. """ - return conf.lib.clang_getTokenSpelling(self._tu, self) # type: ignore [no-any-return] + return _CXString.from_result(conf.lib.clang_getTokenSpelling(self._tu, self)) @property def kind(self): @@ -3661,41 +3705,19 @@ def write_main_file_to_stdout(self): "clang_CompilationDatabase_fromDirectory", [c_interop_string, POINTER(c_uint)], c_object_p, - CompilationDatabase.from_result, - ), - ( - "clang_CompilationDatabase_getAllCompileCommands", - [c_object_p], - c_object_p, - CompileCommands.from_result, ), + ("clang_CompilationDatabase_getAllCompileCommands", [c_object_p], c_object_p), ( "clang_CompilationDatabase_getCompileCommands", [c_object_p, c_interop_string], c_object_p, - CompileCommands.from_result, ), ("clang_CompileCommands_dispose", [c_object_p]), ("clang_CompileCommands_getCommand", [c_object_p, c_uint], c_object_p), ("clang_CompileCommands_getSize", [c_object_p], c_uint), - ( - "clang_CompileCommand_getArg", - [c_object_p, c_uint], - _CXString, - _CXString.from_result, - ), - ( - "clang_CompileCommand_getDirectory", - [c_object_p], - _CXString, - _CXString.from_result, - ), - ( - "clang_CompileCommand_getFilename", - [c_object_p], - _CXString, - _CXString.from_result, - ), + ("clang_CompileCommand_getArg", [c_object_p, c_uint], _CXString), + ("clang_CompileCommand_getDirectory", [c_object_p], _CXString), + ("clang_CompileCommand_getFilename", [c_object_p], _CXString), ("clang_CompileCommand_getNumArgs", [c_object_p], c_uint), ( "clang_codeCompleteAt", @@ -3743,82 +3765,62 @@ def write_main_file_to_stdout(self): ("clang_equalLocations", [SourceLocation, SourceLocation], bool), ("clang_equalRanges", [SourceRange, SourceRange], bool), ("clang_equalTypes", [Type, Type], bool), - ("clang_formatDiagnostic", [Diagnostic, c_uint], _CXString, _CXString.from_result), - ("clang_getArgType", [Type, c_uint], Type, Type.from_result), - ("clang_getArrayElementType", [Type], Type, Type.from_result), + ("clang_formatDiagnostic", [Diagnostic, c_uint], _CXString), + ("clang_getArgType", [Type, c_uint], Type), + ("clang_getArrayElementType", [Type], Type), ("clang_getArraySize", [Type], c_longlong), ("clang_getFieldDeclBitWidth", [Cursor], c_int), - ("clang_getCanonicalCursor", [Cursor], Cursor, Cursor.from_cursor_result), - ("clang_getCanonicalType", [Type], Type, Type.from_result), + ("clang_getCanonicalCursor", [Cursor], Cursor), + ("clang_getCanonicalType", [Type], Type), ("clang_getChildDiagnostics", [Diagnostic], c_object_p), ("clang_getCompletionAvailability", [c_void_p], c_int), - ("clang_getCompletionBriefComment", [c_void_p], _CXString, _CXString.from_result), + ("clang_getCompletionBriefComment", [c_void_p], _CXString), ("clang_getCompletionChunkCompletionString", [c_void_p, c_int], c_object_p), ("clang_getCompletionChunkKind", [c_void_p, c_int], c_int), - ( - "clang_getCompletionChunkText", - [c_void_p, c_int], - _CXString, - _CXString.from_result, - ), + ("clang_getCompletionChunkText", [c_void_p, c_int], _CXString), ("clang_getCompletionPriority", [c_void_p], c_int), - ( - "clang_getCString", - [_CXString], - c_interop_string, - c_interop_string.to_python_string, - ), + ("clang_getCString", [_CXString], c_interop_string), ("clang_getCursor", [TranslationUnit, SourceLocation], Cursor), ("clang_getCursorAvailability", [Cursor], c_int), - ("clang_getCursorDefinition", [Cursor], Cursor, Cursor.from_result), - ("clang_getCursorDisplayName", [Cursor], _CXString, _CXString.from_result), + ("clang_getCursorDefinition", [Cursor], Cursor), + ("clang_getCursorDisplayName", [Cursor], _CXString), ("clang_getCursorExtent", [Cursor], SourceRange), - ("clang_getCursorLexicalParent", [Cursor], Cursor, Cursor.from_cursor_result), + ("clang_getCursorLexicalParent", [Cursor], Cursor), ("clang_getCursorLocation", [Cursor], SourceLocation), - ("clang_getCursorReferenced", [Cursor], Cursor, Cursor.from_result), + ("clang_getCursorReferenced", [Cursor], Cursor), ("clang_getCursorReferenceNameRange", [Cursor, c_uint, c_uint], SourceRange), - ("clang_getCursorResultType", [Cursor], Type, Type.from_result), - ("clang_getCursorSemanticParent", [Cursor], Cursor, Cursor.from_cursor_result), - ("clang_getCursorSpelling", [Cursor], _CXString, _CXString.from_result), - ("clang_getCursorType", [Cursor], Type, Type.from_result), - ("clang_getCursorUSR", [Cursor], _CXString, _CXString.from_result), - ("clang_Cursor_getMangling", [Cursor], _CXString, _CXString.from_result), + ("clang_getCursorResultType", [Cursor], Type), + ("clang_getCursorSemanticParent", [Cursor], Cursor), + ("clang_getCursorSpelling", [Cursor], _CXString), + ("clang_getCursorType", [Cursor], Type), + ("clang_getCursorUSR", [Cursor], _CXString), + ("clang_Cursor_getMangling", [Cursor], _CXString), # ("clang_getCXTUResourceUsage", # [TranslationUnit], # CXTUResourceUsage), ("clang_getCXXAccessSpecifier", [Cursor], c_uint), - ("clang_getDeclObjCTypeEncoding", [Cursor], _CXString, _CXString.from_result), + ("clang_getDeclObjCTypeEncoding", [Cursor], _CXString), ("clang_getDiagnostic", [c_object_p, c_uint], c_object_p), ("clang_getDiagnosticCategory", [Diagnostic], c_uint), - ("clang_getDiagnosticCategoryText", [Diagnostic], _CXString, _CXString.from_result), - ( - "clang_getDiagnosticFixIt", - [Diagnostic, c_uint, POINTER(SourceRange)], - _CXString, - _CXString.from_result, - ), + ("clang_getDiagnosticCategoryText", [Diagnostic], _CXString), + ("clang_getDiagnosticFixIt", [Diagnostic, c_uint, POINTER(SourceRange)], _CXString), ("clang_getDiagnosticInSet", [c_object_p, c_uint], c_object_p), ("clang_getDiagnosticLocation", [Diagnostic], SourceLocation), ("clang_getDiagnosticNumFixIts", [Diagnostic], c_uint), ("clang_getDiagnosticNumRanges", [Diagnostic], c_uint), - ( - "clang_getDiagnosticOption", - [Diagnostic, POINTER(_CXString)], - _CXString, - _CXString.from_result, - ), + ("clang_getDiagnosticOption", [Diagnostic, POINTER(_CXString)], _CXString), ("clang_getDiagnosticRange", [Diagnostic, c_uint], SourceRange), ("clang_getDiagnosticSeverity", [Diagnostic], c_int), - ("clang_getDiagnosticSpelling", [Diagnostic], _CXString, _CXString.from_result), - ("clang_getElementType", [Type], Type, Type.from_result), + ("clang_getDiagnosticSpelling", [Diagnostic], _CXString), + ("clang_getElementType", [Type], Type), ("clang_getEnumConstantDeclUnsignedValue", [Cursor], c_ulonglong), ("clang_getEnumConstantDeclValue", [Cursor], c_longlong), - ("clang_getEnumDeclIntegerType", [Cursor], Type, Type.from_result), + ("clang_getEnumDeclIntegerType", [Cursor], Type), ("clang_getFile", [TranslationUnit, c_interop_string], c_object_p), - ("clang_getFileName", [File], _CXString, _CXString.from_result), + ("clang_getFileName", [File], _CXString), ("clang_getFileTime", [File], c_uint), - ("clang_getIBOutletCollectionType", [Cursor], Type, Type.from_result), - ("clang_getIncludedFile", [Cursor], c_object_p, File.from_result), + ("clang_getIBOutletCollectionType", [Cursor], Type), + ("clang_getIncludedFile", [Cursor], c_object_p), ( "clang_getInclusions", [TranslationUnit, translation_unit_includes_callback, py_object], @@ -3842,41 +3844,26 @@ def write_main_file_to_stdout(self): ("clang_getNumDiagnosticsInSet", [c_object_p], c_uint), ("clang_getNumElements", [Type], c_longlong), ("clang_getNumOverloadedDecls", [Cursor], c_uint), - ("clang_getOverloadedDecl", [Cursor, c_uint], Cursor, Cursor.from_cursor_result), - ("clang_getPointeeType", [Type], Type, Type.from_result), + ("clang_getOverloadedDecl", [Cursor, c_uint], Cursor), + ("clang_getPointeeType", [Type], Type), ("clang_getRange", [SourceLocation, SourceLocation], SourceRange), ("clang_getRangeEnd", [SourceRange], SourceLocation), ("clang_getRangeStart", [SourceRange], SourceLocation), - ("clang_getResultType", [Type], Type, Type.from_result), - ("clang_getSpecializedCursorTemplate", [Cursor], Cursor, Cursor.from_cursor_result), + ("clang_getResultType", [Type], Type), + ("clang_getSpecializedCursorTemplate", [Cursor], Cursor), ("clang_getTemplateCursorKind", [Cursor], c_uint), ("clang_getTokenExtent", [TranslationUnit, Token], SourceRange), ("clang_getTokenKind", [Token], c_uint), ("clang_getTokenLocation", [TranslationUnit, Token], SourceLocation), - ( - "clang_getTokenSpelling", - [TranslationUnit, Token], - _CXString, - _CXString.from_result, - ), - ("clang_getTranslationUnitCursor", [TranslationUnit], Cursor, Cursor.from_result), - ( - "clang_getTranslationUnitSpelling", - [TranslationUnit], - _CXString, - _CXString.from_result, - ), - ( - "clang_getTUResourceUsageName", - [c_uint], - c_interop_string, - c_interop_string.to_python_string, - ), - ("clang_getTypeDeclaration", [Type], Cursor, Cursor.from_result), - ("clang_getTypedefDeclUnderlyingType", [Cursor], Type, Type.from_result), - ("clang_getTypedefName", [Type], _CXString, _CXString.from_result), - ("clang_getTypeKindSpelling", [c_uint], _CXString, _CXString.from_result), - ("clang_getTypeSpelling", [Type], _CXString, _CXString.from_result), + ("clang_getTokenSpelling", [TranslationUnit, Token], _CXString), + ("clang_getTranslationUnitCursor", [TranslationUnit], Cursor), + ("clang_getTranslationUnitSpelling", [TranslationUnit], _CXString), + ("clang_getTUResourceUsageName", [c_uint], c_interop_string), + ("clang_getTypeDeclaration", [Type], Cursor), + ("clang_getTypedefDeclUnderlyingType", [Cursor], Type), + ("clang_getTypedefName", [Type], _CXString), + ("clang_getTypeKindSpelling", [c_uint], _CXString), + ("clang_getTypeSpelling", [Type], _CXString), ("clang_hashCursor", [Cursor], c_uint), ("clang_isAttribute", [CursorKind], bool), ("clang_isConstQualifiedType", [Type], bool), @@ -3909,31 +3896,27 @@ def write_main_file_to_stdout(self): ), ("clang_visitChildren", [Cursor, cursor_visit_callback, py_object], c_uint), ("clang_Cursor_getNumArguments", [Cursor], c_int), - ("clang_Cursor_getArgument", [Cursor, c_uint], Cursor, Cursor.from_result), + ("clang_Cursor_getArgument", [Cursor, c_uint], Cursor), ("clang_Cursor_getNumTemplateArguments", [Cursor], c_int), - ( - "clang_Cursor_getTemplateArgumentKind", - [Cursor, c_uint], - TemplateArgumentKind.from_id, - ), - ("clang_Cursor_getTemplateArgumentType", [Cursor, c_uint], Type, Type.from_result), + ("clang_Cursor_getTemplateArgumentKind", [Cursor, c_uint], c_uint), + ("clang_Cursor_getTemplateArgumentType", [Cursor, c_uint], Type), ("clang_Cursor_getTemplateArgumentValue", [Cursor, c_uint], c_longlong), ("clang_Cursor_getTemplateArgumentUnsignedValue", [Cursor, c_uint], c_ulonglong), ("clang_Cursor_isAnonymous", [Cursor], bool), ("clang_Cursor_isBitField", [Cursor], bool), ("clang_Cursor_getBinaryOpcode", [Cursor], c_int), - ("clang_Cursor_getBriefCommentText", [Cursor], _CXString, _CXString.from_result), - ("clang_Cursor_getRawCommentText", [Cursor], _CXString, _CXString.from_result), + ("clang_Cursor_getBriefCommentText", [Cursor], _CXString), + ("clang_Cursor_getRawCommentText", [Cursor], _CXString), ("clang_Cursor_getOffsetOfField", [Cursor], c_longlong), ("clang_Location_isInSystemHeader", [SourceLocation], bool), ("clang_Type_getAlignOf", [Type], c_longlong), - ("clang_Type_getClassType", [Type], Type, Type.from_result), + ("clang_Type_getClassType", [Type], Type), ("clang_Type_getNumTemplateArguments", [Type], c_int), - ("clang_Type_getTemplateArgumentAsType", [Type, c_uint], Type, Type.from_result), + ("clang_Type_getTemplateArgumentAsType", [Type, c_uint], Type), ("clang_Type_getOffsetOf", [Type, c_interop_string], c_longlong), ("clang_Type_getSizeOf", [Type], c_longlong), ("clang_Type_getCXXRefQualifier", [Type], c_uint), - ("clang_Type_getNamedType", [Type], Type, Type.from_result), + ("clang_Type_getNamedType", [Type], Type), ("clang_Type_visitFields", [Type, fields_visit_callback, py_object], c_uint), ] diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py index 7476947bde2ea..77d8ca415708f 100644 --- a/clang/bindings/python/tests/cindex/test_cursor.py +++ b/clang/bindings/python/tests/cindex/test_cursor.py @@ -14,6 +14,7 @@ from clang.cindex import TranslationUnit from clang.cindex import TypeKind from clang.cindex import BinaryOperator +from clang.cindex import StorageClass from .util import get_cursor from .util import get_cursors from .util import get_tu @@ -279,6 +280,90 @@ def test_is_default_method(self): self.assertTrue(xc.is_default_method()) self.assertFalse(yc.is_default_method()) + def test_is_deleted_method(self): + source = "class X { X() = delete; }; class Y { Y(); };" + tu = get_tu(source, lang="cpp") + + xs = get_cursors(tu, "X") + ys = get_cursors(tu, "Y") + + self.assertEqual(len(xs), 2) + self.assertEqual(len(ys), 2) + + xc = xs[1] + yc = ys[1] + + self.assertTrue(xc.is_deleted_method()) + self.assertFalse(yc.is_deleted_method()) + + def test_is_copy_assignment_operator_method(self): + source_with_copy_assignment_operators = """ + struct Foo { + // Those are copy-assignment operators + bool operator=(const Foo&); + bool operator=(Foo&); + Foo operator=(Foo); + bool operator=(volatile Foo&); + bool operator=(const volatile Foo&); + + // Positive-check that the recognition works for templated classes too + template + class Bar { + bool operator=(const Bar&); + Bar operator=(const Bar); + bool operator=(Bar&); + bool operator=(volatile Bar&); + bool operator=(const volatile Bar&); + }; + """ + source_without_copy_assignment_operators = """ + struct Foo { + // Those are not copy-assignment operators + template + bool operator=(const T&); + bool operator=(const bool&); + bool operator=(char&); + bool operator=(volatile unsigned int&); + bool operator=(const volatile unsigned char&); + bool operator=(int); + bool operator=(Foo&&); + }; + """ + tu_with_copy_assignment_operators = get_tu( + source_with_copy_assignment_operators, lang="cpp" + ) + tu_without_copy_assignment_operators = get_tu( + source_without_copy_assignment_operators, lang="cpp" + ) + + copy_assignment_operators_cursors = get_cursors( + tu_with_copy_assignment_operators, "operator=" + ) + non_copy_assignment_operators_cursors = get_cursors( + tu_without_copy_assignment_operators, "operator=" + ) + + self.assertEqual(len(copy_assignment_operators_cursors), 10) + self.assertTrue(len(non_copy_assignment_operators_cursors), 9) + + self.assertTrue( + all( + [ + cursor.is_copy_assignment_operator_method() + for cursor in copy_assignment_operators_cursors + ] + ) + ) + + self.assertFalse( + any( + [ + cursor.is_copy_assignment_operator_method() + for cursor in non_copy_assignment_operators_cursors + ] + ) + ) + def test_is_move_assignment_operator_method(self): """Ensure Cursor.is_move_assignment_operator_method works.""" source_with_move_assignment_operators = """ @@ -482,6 +567,41 @@ def test_is_scoped_enum(self): self.assertFalse(regular_enum.is_scoped_enum()) self.assertTrue(scoped_enum.is_scoped_enum()) + def test_get_definition(self): + """Ensure Cursor.get_definition works.""" + tu = get_tu( + """ +class A { + constexpr static int f(){return 3;} +}; +struct B { + int b = A::f(); +}; +""", + lang="cpp", + ) + curs = get_cursors(tu, "f") + self.assertEqual(len(curs), 4) + self.assertEqual(curs[0].kind, CursorKind.CXX_METHOD) + self.assertEqual(curs[1].get_definition(), curs[0]) + self.assertEqual(curs[2].get_definition(), curs[0]) + self.assertEqual(curs[3].get_definition(), curs[0]) + + def test_get_usr(self): + """Ensure Cursor.get_usr works.""" + tu = get_tu( + """ +int add(int, int); +int add(int a, int b) { return a + b; } +int add(float a, float b) { return a + b; } +""", + lang="cpp", + ) + curs = get_cursors(tu, "add") + self.assertEqual(len(curs), 3) + self.assertEqual(curs[0].get_usr(), curs[1].get_usr()) + self.assertNotEqual(curs[0].get_usr(), curs[2].get_usr()) + def test_underlying_type(self): tu = get_tu("typedef int foo;") typedef = get_cursor(tu, "foo") @@ -570,6 +690,23 @@ def test_enum_values_cpp(self): self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL) self.assertEqual(ham.enum_value, 0x10000000000) + def test_enum_values_unsigned(self): + tu = get_tu("enum TEST : unsigned char { SPAM=0, HAM = 200};", lang="cpp") + enum = get_cursor(tu, "TEST") + self.assertIsNotNone(enum) + + self.assertEqual(enum.kind, CursorKind.ENUM_DECL) + + enum_constants = list(enum.get_children()) + self.assertEqual(len(enum_constants), 2) + + spam, ham = enum_constants + + self.assertEqual(spam.kind, CursorKind.ENUM_CONSTANT_DECL) + self.assertEqual(spam.enum_value, 0) + self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL) + self.assertEqual(ham.enum_value, 200) + def test_annotation_attribute(self): tu = get_tu( 'int foo (void) __attribute__ ((annotate("here be annotation attribute")));' @@ -625,6 +762,25 @@ def test_result_type_objc_method_decl(self): self.assertEqual(cursor.kind, CursorKind.OBJC_INSTANCE_METHOD_DECL) self.assertEqual(result_type.kind, TypeKind.VOID) + def test_storage_class(self): + tu = get_tu( + """ +extern int ex; +register int reg; +int count(int a, int b){ + static int counter = 0; + return 0; +} +""", + lang="cpp", + ) + cursor = get_cursor(tu, "ex") + self.assertEqual(cursor.storage_class, StorageClass.EXTERN) + cursor = get_cursor(tu, "counter") + self.assertEqual(cursor.storage_class, StorageClass.STATIC) + cursor = get_cursor(tu, "reg") + self.assertEqual(cursor.storage_class, StorageClass.REGISTER) + def test_availability(self): tu = get_tu("class A { A(A const&) = delete; };", lang="cpp") @@ -681,6 +837,23 @@ def test_get_token_cursor(self): r_cursor = t_cursor.referenced # should not raise an exception self.assertEqual(r_cursor.kind, CursorKind.CLASS_DECL) + def test_get_field_offsetof(self): + tu = get_tu( + "struct myStruct {int a; char b; char c; short d; char e;};", lang="cpp" + ) + c1 = get_cursor(tu, "myStruct") + c2 = get_cursor(tu, "a") + c3 = get_cursor(tu, "b") + c4 = get_cursor(tu, "c") + c5 = get_cursor(tu, "d") + c6 = get_cursor(tu, "e") + self.assertEqual(c1.get_field_offsetof(), -1) + self.assertEqual(c2.get_field_offsetof(), 0) + self.assertEqual(c3.get_field_offsetof(), 32) + self.assertEqual(c4.get_field_offsetof(), 40) + self.assertEqual(c5.get_field_offsetof(), 48) + self.assertEqual(c6.get_field_offsetof(), 64) + def test_get_arguments(self): tu = get_tu("void foo(int i, int j);") foo = get_cursor(tu, "foo") @@ -799,3 +972,13 @@ def test_binop(self): for op, typ in operators.items(): c = get_cursor(tu, op) assert c.binary_operator == typ + + def test_from_result_null(self): + tu = get_tu("int a = 1+2;", lang="cpp") + op = next(next(tu.cursor.get_children()).get_children()) + self.assertEqual(op.kind, CursorKind.BINARY_OPERATOR) + self.assertEqual(op.get_definition(), None) + + def test_from_cursor_result_null(self): + tu = get_tu("") + self.assertEqual(tu.cursor.semantic_parent, None) diff --git a/clang/bindings/python/tests/cindex/test_diagnostics.py b/clang/bindings/python/tests/cindex/test_diagnostics.py index 57c41baaa2541..041083d12c7f1 100644 --- a/clang/bindings/python/tests/cindex/test_diagnostics.py +++ b/clang/bindings/python/tests/cindex/test_diagnostics.py @@ -46,6 +46,8 @@ def test_diagnostic_fixit(self): self.assertEqual(tu.diagnostics[0].location.column, 26) self.assertRegex(tu.diagnostics[0].spelling, "use of GNU old-style.*") self.assertEqual(len(tu.diagnostics[0].fixits), 1) + with self.assertRaises(IndexError): + tu.diagnostics[0].fixits[1] self.assertEqual(tu.diagnostics[0].fixits[0].range.start.line, 1) self.assertEqual(tu.diagnostics[0].fixits[0].range.start.column, 26) self.assertEqual(tu.diagnostics[0].fixits[0].range.end.line, 1) @@ -97,6 +99,8 @@ def test_diagnostic_children(self): children = d.children self.assertEqual(len(children), 1) + with self.assertRaises(IndexError): + children[1] self.assertEqual(children[0].severity, Diagnostic.Note) self.assertRegex(children[0].spelling, ".*declared here") self.assertEqual(children[0].location.line, 1) @@ -111,3 +115,16 @@ def test_diagnostic_string_repr(self): repr(d), ", spelling \"expected ';' after struct\">", ) + + def test_diagnostic_string_format(self): + tu = get_tu("struct MissingSemicolon{}") + self.assertEqual(len(tu.diagnostics), 1) + d = tu.diagnostics[0] + + self.assertEqual(str(d), "t.c:1:26: error: expected ';' after struct") + self.assertEqual( + d.format(0b111111), + "t.c:1:26: error: expected ';' after struct [3, Parse Issue]", + ) + with self.assertRaises(ValueError): + d.format(0b1000000) diff --git a/clang/bindings/python/tests/cindex/test_type.py b/clang/bindings/python/tests/cindex/test_type.py index 1dd8db0e3e814..928a9794e4213 100644 --- a/clang/bindings/python/tests/cindex/test_type.py +++ b/clang/bindings/python/tests/cindex/test_type.py @@ -10,7 +10,9 @@ from clang.cindex import CursorKind from clang.cindex import TranslationUnit from clang.cindex import TypeKind +from clang.cindex import RefQualifierKind from .util import get_cursor +from .util import get_cursors from .util import get_tu @@ -308,10 +310,10 @@ def test_element_type(self): def test_invalid_element_type(self): """Ensure Type.element_type raises if type doesn't have elements.""" tu = get_tu("int i;") - i = get_cursor(tu, "i") - self.assertIsNotNone(i) - with self.assertRaises(Exception): - i.element_type + ty = get_cursor(tu, "i").type + with self.assertRaises(Exception) as ctx: + ty.element_type + self.assertEqual(str(ctx.exception), "Element type not available on this type.") def test_element_count(self): """Ensure Type.element_count works.""" @@ -357,6 +359,49 @@ def test_is_restrict_qualified(self): self.assertTrue(i.type.is_restrict_qualified()) self.assertFalse(j.type.is_restrict_qualified()) + def test_get_result(self): + tu = get_tu("void foo(); int bar(char, short);") + foo = get_cursor(tu, "foo") + bar = get_cursor(tu, "bar") + self.assertEqual(foo.type.get_result().spelling, "void") + self.assertEqual(bar.type.get_result().spelling, "int") + + def test_get_class_type(self): + tu = get_tu( + """ +class myClass +{ + char *myAttr; +}; + +char *myClass::*pMyAttr = &myClass::myAttr; +""", + lang="cpp", + ) + cur = get_cursor(tu, "pMyAttr") + self.assertEqual(cur.type.get_class_type().spelling, "myClass") + + def test_get_named_type(self): + tu = get_tu("using char_alias = char; char_alias xyz;", lang="cpp") + cur = get_cursor(tu, "xyz") + self.assertEqual(cur.type.get_named_type().spelling, "char_alias") + + def test_get_ref_qualifier(self): + tu = get_tu( + """ +class A +{ + const int& getAttr() const &; + int getAttr() const &&; +}; +""", + lang="cpp", + ) + getters = get_cursors(tu, "getAttr") + self.assertEqual(len(getters), 2) + self.assertEqual(getters[0].type.get_ref_qualifier(), RefQualifierKind.LVALUE) + self.assertEqual(getters[1].type.get_ref_qualifier(), RefQualifierKind.RVALUE) + def test_record_layout(self): """Ensure Cursor.type.get_size, Cursor.type.get_align and Cursor.type.get_offset works.""" diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index a16b9c44ef0ea..baf39befd796a 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -586,28 +586,36 @@

Node Matchers

#pragma omp declare simd int min(); -attr() - matches "nodiscard", "nonnull", "noinline", and the whole "#pragma" line. + +The matcher attr() +matches nodiscard, nonnull, noinline, and +declare simd. Matcher<CXXBaseSpecifier>cxxBaseSpecifierMatcher<CXXBaseSpecifier>...
Matches class bases.
 
-Examples matches public virtual B.
+Given
   class B {};
   class C : public virtual B {};
+
+The matcher cxxRecordDecl(hasDirectBase(cxxBaseSpecifier()))
+matches C.
 
Matcher<CXXCtorInitializer>cxxCtorInitializerMatcher<CXXCtorInitializer>...
Matches constructor initializers.
 
-Examples matches i(42).
+Given
   class C {
     C() : i(42) {}
     int i;
   };
+
+The matcher cxxCtorInitializer()
+matches i(42).
 
@@ -619,17 +627,22 @@

Node Matchers

public: int a; }; -accessSpecDecl() - matches 'public:' + +The matcher accessSpecDecl() +matches public:. Matcher<Decl>bindingDeclMatcher<BindingDecl>...
Matches binding declarations
-Example matches foo and bar
-(matcher = bindingDecl()
 
-  auto [foo, bar] = std::make_pair{42, 42};
+Given
+  struct pair { int x; int y; };
+  pair make(int, int);
+  auto [foo, bar] = make(42, 42);
+
+The matcher bindingDecl()
+matches foo and bar.
 
@@ -642,14 +655,18 @@

Node Matchers

myFunc(^(int p) { printf("%d", p); }) + Matcher<Decl>classTemplateDeclMatcher<ClassTemplateDecl>...
Matches C++ class template declarations.
 
-Example matches Z
+Given
   template<class T> class Z {};
+
+The matcher classTemplateDecl()
+matches Z.
 
@@ -660,13 +677,14 @@

Node Matchers

template<class T1, class T2, int I> class A {}; - template<class T, int I> - class A<T, T*, I> {}; + template<class T, int I> class A<T, T*, I> {}; template<> class A<int, int, 1> {}; -classTemplatePartialSpecializationDecl() - matches the specialization A<T,T*,I> but not A<int,int,1> + +The matcher classTemplatePartialSpecializationDecl() +matches template<class T, int I> class A<T, T*, I> {}, +but does not match A<int, int, 1>. @@ -677,87 +695,128 @@

Node Matchers

template<typename T> class A {}; template<> class A<double> {}; A<int> a; -classTemplateSpecializationDecl() - matches the specializations A<int> and A<double> + +The matcher classTemplateSpecializationDecl() +matches class A<int> +and class A<double>. Matcher<Decl>conceptDeclMatcher<ConceptDecl>...
Matches concept declarations.
 
-Example matches integral
-  template<typename T>
-  concept integral = std::is_integral_v<T>;
+Given
+  template<typename T> concept my_concept = true;
+
+
+The matcher conceptDecl()
+matches template<typename T>
+concept my_concept = true.
 
Matcher<Decl>cxxConstructorDeclMatcher<CXXConstructorDecl>...
Matches C++ constructor declarations.
 
-Example matches Foo::Foo() and Foo::Foo(int)
+Given
   class Foo {
    public:
     Foo();
     Foo(int);
     int DoSomething();
   };
+
+  struct Bar {};
+
+
+The matcher cxxConstructorDecl()
+matches Foo() and Foo(int).
 
Matcher<Decl>cxxConversionDeclMatcher<CXXConversionDecl>...
Matches conversion operator declarations.
 
-Example matches the operator.
+Given
   class X { operator int() const; };
+
+
+The matcher cxxConversionDecl()
+matches operator int() const.
 
Matcher<Decl>cxxDeductionGuideDeclMatcher<CXXDeductionGuideDecl>...
Matches user-defined and implicitly generated deduction guide.
 
-Example matches the deduction guide.
+Given
   template<typename T>
-  class X { X(int) };
+  class X { X(int); };
   X(int) -> X<int>;
+
+
+The matcher cxxDeductionGuideDecl()
+matches the written deduction guide
+auto (int) -> X<int>,
+the implicit copy deduction guide auto (int) -> X<T>
+and the implicitly declared deduction guide
+auto (X<T>) -> X<T>.
 
Matcher<Decl>cxxDestructorDeclMatcher<CXXDestructorDecl>...
Matches explicit C++ destructor declarations.
 
-Example matches Foo::~Foo()
+Given
   class Foo {
    public:
     virtual ~Foo();
   };
+
+  struct Bar {};
+
+
+The matcher cxxDestructorDecl()
+matches virtual ~Foo().
 
Matcher<Decl>cxxMethodDeclMatcher<CXXMethodDecl>...
Matches method declarations.
 
-Example matches y
+Given
   class X { void y(); };
+
+
+The matcher cxxMethodDecl()
+matches void y().
 
Matcher<Decl>cxxRecordDeclMatcher<CXXRecordDecl>...
Matches C++ class declarations.
 
-Example matches X, Z
+Given
   class X;
   template<class T> class Z {};
+
+The matcher cxxRecordDecl()
+matches X and Z.
 
Matcher<Decl>declMatcher<Decl>...
Matches declarations.
 
-Examples matches X, C, and the friend declaration inside C;
+Given
   void X();
   class C {
-    friend X;
+    friend void X();
   };
+
+The matcher decl()
+matches void X(), C
+and friend void X().
 
@@ -767,40 +826,49 @@

Node Matchers

Given class X { int y; }; -declaratorDecl() - matches int y. + +The matcher declaratorDecl() +matches int y. Matcher<Decl>decompositionDeclMatcher<DecompositionDecl>...
Matches decomposition-declarations.
 
-Examples matches the declaration node with foo and bar, but not
-number.
-(matcher = declStmt(has(decompositionDecl())))
-
+Given
+  struct pair { int x; int y; };
+  pair make(int, int);
   int number = 42;
-  auto [foo, bar] = std::make_pair{42, 42};
+  auto [foo, bar] = make(42, 42);
+
+The matcher decompositionDecl()
+matches auto [foo, bar] = make(42, 42),
+but does not match number.
 
Matcher<Decl>enumConstantDeclMatcher<EnumConstantDecl>...
Matches enum constants.
 
-Example matches A, B, C
+Given
   enum X {
     A, B, C
   };
+The matcher enumConstantDecl()
+matches A, B and C.
 
Matcher<Decl>enumDeclMatcher<EnumDecl>...
Matches enum declarations.
 
-Example matches X
+Given
   enum X {
     A, B, C
   };
+
+The matcher enumDecl()
+matches the enum X.
 
@@ -808,9 +876,14 @@

Node Matchers

Matches field declarations.
 
 Given
-  class X { int m; };
-fieldDecl()
-  matches 'm'.
+  int a;
+  struct Foo {
+    int x;
+  };
+  void bar(int val);
+
+The matcher fieldDecl()
+matches int x.
 
@@ -819,16 +892,20 @@

Node Matchers

Given class X { friend void foo(); }; -friendDecl() - matches 'friend void foo()'. + +The matcher friendDecl() +matches friend void foo(). Matcher<Decl>functionDeclMatcher<FunctionDecl>...
Matches function declarations.
 
-Example matches f
+Given
   void f();
+
+The matcher functionDecl()
+matches void f().
 
@@ -837,6 +914,10 @@

Node Matchers

Example matches f template<class T> void f(T t) {} + + +The matcher functionTemplateDecl() +matches template<class T> void f(T t) {}. @@ -845,8 +926,8 @@

Node Matchers

Given struct X { struct { int a; }; }; -indirectFieldDecl() - matches 'a'. +The matcher indirectFieldDecl() +matches a. @@ -854,10 +935,13 @@

Node Matchers

Matches a declaration of label.
 
 Given
-  goto FOO;
-  FOO: bar();
-labelDecl()
-  matches 'FOO:'
+  void bar();
+  void foo() {
+    goto FOO;
+    FOO: bar();
+  }
+The matcher labelDecl()
+matches FOO: bar().
 
@@ -866,8 +950,9 @@

Node Matchers

Given extern "C" {} -linkageSpecDecl() - matches "extern "C" {}" + +The matcher linkageSpecDecl() +matches extern "C" {}. @@ -875,12 +960,18 @@

Node Matchers

Matches a declaration of anything that could have a name.
 
 Example matches X, S, the anonymous union type, i, and U;
+Given
   typedef int X;
   struct S {
     union {
       int i;
     } U;
   };
+The matcher namedDecl()
+matches typedef int X, S, int i
+ and U,
+with S matching twice in C++.
+Once for the injected class name and once for the declaration itself.
 
@@ -890,8 +981,10 @@

Node Matchers

Given namespace test {} namespace alias = ::test; -namespaceAliasDecl() - matches "namespace alias" but not "namespace test" + +The matcher namespaceAliasDecl() +matches alias, +but does not match test. @@ -901,8 +994,9 @@

Node Matchers

Given namespace {} namespace test {} -namespaceDecl() - matches "namespace {}" and "namespace test {}" + +The matcher namespaceDecl() +matches namespace {} and namespace test {}. @@ -911,8 +1005,10 @@

Node Matchers

Given template <typename T, int N> struct C {}; -nonTypeTemplateParmDecl() - matches 'N', but not 'T'. + +The matcher nonTypeTemplateParmDecl() +matches int N, +but does not match typename T. @@ -922,6 +1018,7 @@

Node Matchers

Example matches Foo (Additions) @interface Foo (Additions) @end + @@ -931,6 +1028,7 @@

Node Matchers

Example matches Foo (Additions) @implementation Foo (Additions) @end + @@ -940,6 +1038,7 @@

Node Matchers

Example matches Foo @implementation Foo @end + @@ -949,6 +1048,7 @@

Node Matchers

Example matches Foo @interface Foo @end + @@ -960,6 +1060,7 @@

Node Matchers

BOOL _enabled; } @end + @@ -974,6 +1075,7 @@

Node Matchers

@implementation Foo - (void)method {} @end + @@ -984,6 +1086,7 @@

Node Matchers

@interface Foo @property BOOL enabled; @end + @@ -993,6 +1096,7 @@

Node Matchers

Example matches FooDelegate @protocol FooDelegate @end + @@ -1001,48 +1105,58 @@

Node Matchers

Given void f(int x); -parmVarDecl() - matches int x. +The matcher parmVarDecl() +matches int x. Matcher<Decl>recordDeclMatcher<RecordDecl>...
Matches class, struct, and union declarations.
 
-Example matches X, Z, U, and S
+Given
   class X;
   template<class T> class Z {};
   struct S {};
   union U {};
+
+The matcher recordDecl()
+matches X, Z,
+S and U.
 
Matcher<Decl>staticAssertDeclMatcher<StaticAssertDecl>...
Matches a C++ static_assert declaration.
 
-Example:
-  staticAssertDecl()
-matches
-  static_assert(sizeof(S) == sizeof(int))
-in
+Given
   struct S {
     int x;
   };
   static_assert(sizeof(S) == sizeof(int));
+
+
+The matcher staticAssertDecl()
+matches static_assert(sizeof(S) == sizeof(int)).
 
Matcher<Decl>tagDeclMatcher<TagDecl>...
Matches tag declarations.
 
-Example matches X, Z, U, S, E
+Given
   class X;
   template<class T> class Z {};
   struct S {};
   union U {};
-  enum E {
-    A, B, C
-  };
+  enum E { A, B, C };
+
+
+The matcher tagDecl()
+matches class X, class Z {}, the injected class name
+class Z, struct S {},
+the injected class name struct S, union U {},
+the injected class name union U
+and enum E { A, B, C }.
 
@@ -1051,8 +1165,10 @@

Node Matchers

Given template <template <typename> class Z, int N> struct C {}; -templateTypeParmDecl() - matches 'Z', but not 'N'. + +The matcher templateTemplateParmDecl() +matches template <typename> class Z, +but does not match int N. @@ -1061,8 +1177,10 @@

Node Matchers

Given template <typename T, int N> struct C {}; -templateTypeParmDecl() - matches 'T', but not 'N'. + +The matcher templateTypeParmDecl() +matches typename T, +but does not int N. @@ -1072,10 +1190,12 @@

Node Matchers

Given int X; namespace NS { - int Y; + int Y; } // namespace NS -decl(hasDeclContext(translationUnitDecl())) - matches "int X", but not "int Y". + +The matcher namedDecl(hasDeclContext(translationUnitDecl())) +matches X and NS, +but does not match Y. @@ -1085,17 +1205,22 @@

Node Matchers

Given typedef int X; using Y = int; -typeAliasDecl() - matches "using Y = int", but not "typedef int X" + +The matcher typeAliasDecl() +matches using Y = int, +but does not match typedef int X. Matcher<Decl>typeAliasTemplateDeclMatcher<TypeAliasTemplateDecl>...
Matches type alias template declarations.
 
-typeAliasTemplateDecl() matches
-  template <typename T>
-  using Y = X<T>;
+Given
+  template <typename T> struct X {};
+  template <typename T> using Y = X<T>;
+
+The matcher typeAliasTemplateDecl()
+matches template <typename T> using Y = X<T>.
 
@@ -1105,8 +1230,10 @@

Node Matchers

Given typedef int X; using Y = int; -typedefDecl() - matches "typedef int X", but not "using Y = int" + +The matcher typedefDecl() +matches typedef int X, +but does not match using Y = int. @@ -1116,8 +1243,9 @@

Node Matchers

Given typedef int X; using Y = int; -typedefNameDecl() - matches "typedef int X" and "using Y = int" + +The matcher typedefNameDecl() +matches typedef int X and using Y = int. @@ -1133,8 +1261,10 @@

Node Matchers

struct S : private Base<T> { using typename Base<T>::Foo; }; -unresolvedUsingTypenameDecl() - matches using Base<T>::Foo + +The matcher unresolvedUsingTypenameDecl() + matches using typename Base<T>::Foo + Matcher<Decl>unresolvedUsingValueDeclMatcher<UnresolvedUsingValueDecl>... @@ -1145,8 +1275,10 @@

Node Matchers

class C : private X { using X::x; }; -unresolvedUsingValueDecl() - matches using X::x + +The matcher unresolvedUsingValueDecl() + matches using X::x + Matcher<Decl>usingDeclMatcher<UsingDecl>... @@ -1155,8 +1287,10 @@

Node Matchers

Given namespace X { int x; } using X::x; -usingDecl() - matches using X::x + +The matcher usingDecl() + matches using X::x + Matcher<Decl>usingDirectiveDeclMatcher<UsingDirectiveDecl>... @@ -1165,26 +1299,34 @@

Node Matchers

Given namespace X { int x; } using namespace X; -usingDirectiveDecl() - matches using namespace X + +The matcher usingDirectiveDecl() + matches using namespace X + Matcher<Decl>usingEnumDeclMatcher<UsingEnumDecl>...
Matches using-enum declarations.
 
 Given
-  namespace X { enum x {...}; }
+  namespace X { enum x { val1, val2 }; }
   using enum X::x;
-usingEnumDecl()
-  matches using enum X::x 
+ +The matcher usingEnumDecl() + matches using enum X::x + Matcher<Decl>valueDeclMatcher<ValueDecl>...
Matches any value declaration.
 
-Example matches A, B, C and F
+Given
   enum X { A, B, C };
   void F();
+  int V = 0;
+The matcher valueDecl()
+matches A, B, C, void F()
+and int V = 0.
 
@@ -1196,6 +1338,13 @@

Node Matchers

Example matches a int a; + struct Foo { + int x; + }; + void bar(int val); + +The matcher varDecl() +matches int a and int val, but not int x. @@ -1208,13 +1357,29 @@

Node Matchers

auto f = [x](){}; auto g = [x = 1](){}; } -In the matcher `lambdaExpr(hasAnyCapture(lambdaCapture()))`, -`lambdaCapture()` matches `x` and `x=1`. + +The matcher +lambdaExpr(hasAnyCapture(lambdaCapture().bind("capture"))), +matches [x](){} and [x = 1](){}, +with lambdaCapture() matching +x and x = 1. Matcher<NestedNameSpecifierLoc>nestedNameSpecifierLocMatcher<NestedNameSpecifierLoc>...
Same as nestedNameSpecifier but matches NestedNameSpecifierLoc.
+
+Given
+  namespace ns {
+    struct A { static void f(); };
+    void A::f() {}
+    void g() { A::f(); }
+  }
+  ns::A a;
+
+
+The matcher nestedNameSpecifierLoc() matches
+A:: twice, and ns:: once.
 
@@ -1228,8 +1393,9 @@

Node Matchers

void g() { A::f(); } } ns::A a; -nestedNameSpecifier() - matches "ns::" and both "A::" + +The matcher nestedNameSpecifier() +matches ns and both A @@ -1237,20 +1403,38 @@

Node Matchers

Matches OpenMP ``default`` clause.
 
 Given
+  void foo() {
+    #pragma omp parallel default(none)
+      ;
+    #pragma omp parallel default(shared)
+      ;
+    #pragma omp parallel default(private)
+      ;
+    #pragma omp parallel default(firstprivate)
+      ;
+    #pragma omp parallel
+      ;
+  }
 
-  #pragma omp parallel default(none)
-  #pragma omp parallel default(shared)
-  #pragma omp parallel default(private)
-  #pragma omp parallel default(firstprivate)
-  #pragma omp parallel
 
-``ompDefaultClause()`` matches ``default(none)``, ``default(shared)``,
-`` default(private)`` and ``default(firstprivate)``
+The matcher
+ompExecutableDirective(hasAnyClause(ompDefaultClause())) matches
+#pragma omp parallel default(none),
+#pragma omp parallel default(shared),
+#pragma omp parallel default(private) and
+#pragma omp parallel default(firstprivate).
 
Matcher<QualType>qualTypeMatcher<QualType>...
Matches QualTypes in the clang AST.
+
+Given
+  int a = 0;
+  const int b = 1;
+
+The matcher varDecl(hasType(qualType(isConstQualified())))
+matches const int b = 1, but not int a = 0.
 
@@ -1258,34 +1442,39 @@

Node Matchers

Matches address of label statements (GNU extension).
 
 Given
+void bar();
+void foo() {
   FOO: bar();
   void *ptr = &&FOO;
-  goto *bar;
-addrLabelExpr()
-  matches '&&FOO'
+  goto *ptr;
+}
+The matcher addrLabelExpr()
+matches &&FOO
 
Matcher<Stmt>arrayInitIndexExprMatcher<ArrayInitIndexExpr>...
The arrayInitIndexExpr consists of two subexpressions: a common expression
-(the source array) that is evaluated once up-front, and a per-element initializer
-that runs once for each array element. Within the per-element initializer,
-the current index may be obtained via an ArrayInitIndexExpr.
+(the source array) that is evaluated once up-front, and a per-element
+initializer that runs once for each array element. Within the per-element
+initializer, the current index may be obtained via an ArrayInitIndexExpr.
 
 Given
-  void testStructBinding() {
+  void testStructuredBinding() {
     int a[2] = {1, 2};
     auto [x, y] = a;
   }
-arrayInitIndexExpr() matches the array index that implicitly iterates
-over the array `a` to copy each element to the anonymous array
-that backs the structured binding `[x, y]` elements of which are
-referred to by their aliases `x` and `y`.
+
+
+The matcher arrayInitIndexExpr() matches the array index
+that implicitly iterates over the array `a` to copy each element to the
+anonymous array that backs the structured binding.
 
Matcher<Stmt>arrayInitLoopExprMatcher<ArrayInitLoopExpr>... -
Matches a loop initializing the elements of an array in a number of contexts:
+
Matches a loop initializing the elements of an array in a number of
+contexts:
  * in the implicit copy/move constructor for a class with an array member
  * when a lambda-expression captures an array by value
  * when a decomposition declaration decomposes an array
@@ -1293,13 +1482,12 @@ 

Node Matchers

Given void testLambdaCapture() { int a[10]; - auto Lam1 = [a]() { - return; - }; + [a]() {}; } -arrayInitLoopExpr() matches the implicit loop that initializes each element of -the implicit array field inside the lambda object, that represents the array `a` -captured by value. + +The matcher arrayInitLoopExpr() matches the implicit loop that +initializes each element of the implicit array field inside the lambda +object, that represents the array a captured by value.
@@ -1307,26 +1495,34 @@

Node Matchers

Matches array subscript expressions.
 
 Given
-  int i = a[1];
-arraySubscriptExpr()
-  matches "a[1]"
+  void foo() {
+    int a[2] = {0, 1};
+    int i = a[1];
+  }
+The matcher arraySubscriptExpr()
+matches a[1].
 
Matcher<Stmt>asmStmtMatcher<AsmStmt>...
Matches asm statements.
 
+void foo() {
  int i = 100;
-  __asm("mov al, 2");
-asmStmt()
-  matches '__asm("mov al, 2")'
+  __asm("mov %al, 2");
+}
+The matcher asmStmt()
+matches __asm("mov %al, 2")
 
Matcher<Stmt>atomicExprMatcher<AtomicExpr>...
Matches atomic builtins.
-Example matches __atomic_load_n(ptr, 1)
+
+Given
   void foo() { int *ptr; __atomic_load_n(ptr, 1); }
+
+The matcher atomicExpr() matches __atomic_load_n(ptr, 1).
 
@@ -1337,24 +1533,35 @@

Node Matchers

@autoreleasepool { int x = 0; } -autoreleasePoolStmt(stmt()) matches the declaration of "x" -inside the autorelease pool. + +The matcher autoreleasePoolStmt(stmt()) matches the declaration of +int x = 0 inside the autorelease pool.
Matcher<Stmt>binaryConditionalOperatorMatcher<BinaryConditionalOperator>...
Matches binary conditional operator expressions (GNU extension).
 
-Example matches a ?: b
-  (a ?: b) + 42;
+Given
+  int f(int a, int b) {
+    return (a ?: b) + 42;
+  }
+
+The matcher binaryConditionalOperator() matches a ?: b.
 
Matcher<Stmt>binaryOperatorMatcher<BinaryOperator>...
Matches binary operator expressions.
 
-Example matches a || b
-  !(a || b)
+Given
+  void foo(bool a, bool b) {
+    !(a || b);
+  }
+
+
+The matcher binaryOperator() matches a || b.
+
 See also the binaryOperation() matcher for more-general matching.
 
@@ -1362,8 +1569,11 @@

Node Matchers

Matcher<Stmt>blockExprMatcher<BlockExpr>...
Matches a reference to a block.
 
-Example: matches "^{}":
+Given
   void f() { ^{}(); }
+
+
+The matcher blockExpr() matches ^{}.
 
@@ -1371,17 +1581,23 @@

Node Matchers

Matches break statements.
 
 Given
+void foo() {
   while (true) { break; }
-breakStmt()
-  matches 'break'
+}
+
+The matcher breakStmt()
+matches break
 
Matcher<Stmt>cStyleCastExprMatcher<CStyleCastExpr>...
Matches a C-style cast expression.
 
-Example: Matches (int) 2.2f in
+Given
   int i = (int) 2.2f;
+
+The matcher cStyleCastExpr()
+matches (int) 2.2f.
 
@@ -1389,9 +1605,16 @@

Node Matchers

Matches call expressions.
 
 Example matches x.y() and y()
-  X x;
-  x.y();
-  y();
+  struct X { void foo(); };
+  void bar();
+  void foobar() {
+    X x;
+    x.foo();
+    bar();
+  }
+
+The matcher callExpr()
+matches x.foo() and bar();
 
@@ -1399,22 +1622,41 @@

Node Matchers

Matches case statements inside switch statements.
 
 Given
+void foo(int a) {
   switch(a) { case 42: break; default: break; }
-caseStmt()
-  matches 'case 42:'.
+}
+The matcher caseStmt()
+matches case 42: break.
 
Matcher<Stmt>castExprMatcher<CastExpr>...
Matches any cast nodes of Clang's AST.
 
-Example: castExpr() matches each of the following:
-  (int) 3;
-  const_cast<Expr *>(SubExpr);
-  char c = 0;
-but does not match
-  int i = (0);
-  int k = 0;
+Given
+  struct S {};
+  const S* s;
+  S* s2 = const_cast<S*>(s);
+
+  const int val = 0;
+  char val0 = 1;
+  char val1 = (char)2;
+  char val2 = static_cast<char>(3);
+  int* val3 = reinterpret_cast<int*>(4);
+  char val4 = char(5);
+
+
+The matcher castExpr()
+matches
+const_cast<S*>(s) and the implicit l- to r-value cast for s,
+the implicit cast to char for the initializer 1,
+the c-style cast (char)2 and it's implicit cast to char
+(part of the c-style cast) 2,
+static_cast<char>(3) and it's implicit cast to char
+(part of the static_cast) 3,
+reinterpret_cast<int*>(4),
+char(5) and it's implicit cast to char
+(part of the functional cast) 5.
 
@@ -1424,14 +1666,24 @@

Node Matchers

Not matching Hex-encoded chars (e.g. 0x1234, which is a IntegerLiteral), though. -Example matches 'a', L'a' +Given char ch = 'a'; wchar_t chw = L'a'; + + +The matcher characterLiteral() matches 'a' and +L'a'. Matcher<Stmt>chooseExprMatcher<ChooseExpr>...
Matches GNU __builtin_choose_expr.
+
+Given
+  void f() { (void)__builtin_choose_expr(1, 2, 3); }
+
+The matcher chooseExpr() matches
+__builtin_choose_expr(1, 2, 3).
 
@@ -1439,9 +1691,45 @@

Node Matchers

Matches co_await expressions.
 
 Given
-  co_await 1;
-coawaitExpr()
-  matches 'co_await 1'
+  namespace std {
+  template <typename T = void>
+  struct coroutine_handle {
+      static constexpr coroutine_handle from_address(void* addr) {
+        return {};
+      }
+  };
+
+  struct always_suspend {
+      bool await_ready() const noexcept;
+      bool await_resume() const noexcept;
+      template <typename T>
+      bool await_suspend(coroutine_handle<T>) const noexcept;
+  };
+
+  template <typename T>
+  struct coroutine_traits {
+      using promise_type = T::promise_type;
+  };
+  }  // namespace std
+
+  struct generator {
+      struct promise_type {
+          std::always_suspend yield_value(int&&);
+          std::always_suspend initial_suspend() const noexcept;
+          std::always_suspend final_suspend() const noexcept;
+          void return_void();
+          void unhandled_exception();
+          generator get_return_object();
+      };
+  };
+
+  std::always_suspend h();
+
+  generator g() { co_await h(); }
+
+The matcher
+coawaitExpr(has(callExpr(callee(functionDecl(hasName("h"))))))
+matches co_await h().
 
@@ -1449,35 +1737,48 @@

Node Matchers

Matches compound (i.e. non-scalar) literals
 
 Example match: {1}, (1, 2)
-  int array[4] = {1};
-  vector int myvec = (vector int)(1, 2);
+  struct vector { int x; int y; };
+  struct vector myvec = (struct vector){ 1, 2 };
+
+The matcher compoundLiteralExpr()
+matches (struct vector){ 1, 2 }.
 
Matcher<Stmt>compoundStmtMatcher<CompoundStmt>...
Matches compound statements.
 
-Example matches '{}' and '{{}}' in 'for (;;) {{}}'
-  for (;;) {{}}
+Given
+void foo() { for (;;) {{}} }
+
+The matcher compoundStmt() matches
+{ for (;;) {{}} }, {{}} and {}.
 
Matcher<Stmt>conditionalOperatorMatcher<ConditionalOperator>...
Matches conditional operator expressions.
 
-Example matches a ? b : c
-  (a ? b : c) + 42
+Given
+  int f(int a, int b, int c) {
+    return (a ? b : c) + 42;
+  }
+
+The matcher conditionalOperator() matches a ? b : c.
 
Matcher<Stmt>constantExprMatcher<ConstantExpr>...
Matches a constant expression wrapper.
 
-Example matches the constant in the case statement:
-    (matcher = constantExpr())
-  switch (a) {
-  case 37: break;
+Given
+  void f(int a) {
+    switch (a) {
+      case 37: break;
+    }
   }
+
+The matcher constantExpr() matches 37.
 
@@ -1485,14 +1786,26 @@

Node Matchers

Matches continue statements.
 
 Given
+void foo() {
   while (true) { continue; }
-continueStmt()
-  matches 'continue'
+}
+
+The matcher continueStmt()
+matches continue
 
Matcher<Stmt>convertVectorExprMatcher<ConvertVectorExpr>...
Matches builtin function __builtin_convertvector.
+
+Given
+  typedef double vector4double __attribute__((__vector_size__(32)));
+  typedef float  vector4float  __attribute__((__vector_size__(16)));
+  vector4float vf;
+  void f() { (void)__builtin_convertvector(vf, vector4double); }
+
+The matcher convertVectorExpr() matches
+__builtin_convertvector(vf, vector4double).
 
@@ -1500,19 +1813,85 @@

Node Matchers

Matches co_return statements.
 
 Given
-  while (true) { co_return; }
-coreturnStmt()
-  matches 'co_return'
+  namespace std {
+  template <typename T = void>
+  struct coroutine_handle {
+      static constexpr coroutine_handle from_address(void* addr) {
+        return {};
+      }
+  };
+
+  struct always_suspend {
+      bool await_ready() const noexcept;
+      bool await_resume() const noexcept;
+      template <typename T>
+      bool await_suspend(coroutine_handle<T>) const noexcept;
+  };
+
+  template <typename T>
+  struct coroutine_traits {
+      using promise_type = T::promise_type;
+  };
+  }  // namespace std
+
+  struct generator {
+      struct promise_type {
+          void return_value(int v);
+          std::always_suspend yield_value(int&&);
+          std::always_suspend initial_suspend() const noexcept;
+          std::always_suspend final_suspend() const noexcept;
+          void unhandled_exception();
+          generator get_return_object();
+      };
+  };
+
+  generator f() {
+      co_return 10;
+  }
+
+
+The matcher coreturnStmt(has(integerLiteral()))
+matches co_return 10
 
Matcher<Stmt>coroutineBodyStmtMatcher<CoroutineBodyStmt>...
Matches coroutine body statements.
 
-coroutineBodyStmt() matches the coroutine below
-  generator<int> gen() {
-    co_return;
-  }
+Given
+  namespace std {
+  template <typename T = void>
+  struct coroutine_handle {
+      static constexpr coroutine_handle from_address(void* addr) {
+        return {};
+      }
+  };
+
+  struct suspend_always {
+      bool await_ready() const noexcept;
+      bool await_resume() const noexcept;
+      template <typename T>
+      bool await_suspend(coroutine_handle<T>) const noexcept;
+  };
+
+  template <typename...>
+  struct coroutine_traits {
+      struct promise_type {
+          std::suspend_always initial_suspend() const noexcept;
+          std::suspend_always final_suspend() const noexcept;
+          void return_void();
+          void unhandled_exception();
+          coroutine_traits get_return_object();
+      };
+  };
+  }  // namespace std
+
+  void f() { while (true) { co_return; } }
+
+
+
+The matcher coroutineBodyStmt() matches
+{ while (true) { co_return; } }.
 
@@ -1520,27 +1899,77 @@

Node Matchers

Matches co_yield expressions.
 
 Given
-  co_yield 1;
-coyieldExpr()
-  matches 'co_yield 1'
+  namespace std {
+  template <typename T = void>
+  struct coroutine_handle {
+      static constexpr coroutine_handle from_address(void* addr) {
+        return {};
+      }
+  };
+
+  struct always_suspend {
+      bool await_ready() const noexcept;
+      bool await_resume() const noexcept;
+      template <typename T>
+      bool await_suspend(coroutine_handle<T>) const noexcept;
+  };
+
+  template <typename T>
+  struct coroutine_traits {
+      using promise_type = T::promise_type;
+  };
+  }  // namespace std
+
+  struct generator {
+      struct promise_type {
+          std::always_suspend yield_value(int&&);
+          std::always_suspend initial_suspend() const noexcept;
+          std::always_suspend final_suspend() const noexcept;
+          void return_void();
+          void unhandled_exception();
+          generator get_return_object();
+      };
+  };
+
+  generator f() {
+      while (true) {
+          co_yield 10;
+      }
+  }
+
+The matcher coyieldExpr()
+matches co_yield 10
 
Matcher<Stmt>cudaKernelCallExprMatcher<CUDAKernelCallExpr>...
Matches CUDA kernel call expression.
 
-Example matches,
-  kernel<<<i,j>>>();
+Given
+  __global__ void kernel() {}
+  void f() {
+    kernel<<<32,32>>>();
+  }
+
+The matcher cudaKernelCallExpr()
+matches kernel<<<i, k>>>()
 
Matcher<Stmt>cxxBindTemporaryExprMatcher<CXXBindTemporaryExpr>...
Matches nodes where temporaries are created.
 
-Example matches FunctionTakesString(GetStringByValue())
-    (matcher = cxxBindTemporaryExpr())
-  FunctionTakesString(GetStringByValue());
-  FunctionTakesStringByPointer(GetStringPointer());
+Given
+  struct S {
+    S() { }  // User defined constructor makes S non-POD.
+    ~S() { } // User defined destructor makes it non-trivial.
+  };
+  void test() {
+    const S &s_ref = S(); // Requires a CXXBindTemporaryExpr.
+  }
+
+The matcher cxxBindTemporaryExpr()
+matches the constructor call S().
 
@@ -1548,49 +1977,71 @@

Node Matchers

Matches bool literals.
 
 Example matches true
-  true
+  bool Flag = true;
+
+
+The matcher cxxBoolLiteral() matches true.
 
Matcher<Stmt>cxxCatchStmtMatcher<CXXCatchStmt>...
Matches catch statements.
 
+void foo() {
   try {} catch(int i) {}
-cxxCatchStmt()
-  matches 'catch(int i)'
+}
+
+The matcher cxxCatchStmt()
+matches catch(int i) {}
 
Matcher<Stmt>cxxConstCastExprMatcher<CXXConstCastExpr>...
Matches a const_cast expression.
 
-Example: Matches const_cast<int*>(&r) in
+Given
   int n = 42;
   const int &r(n);
   int* p = const_cast<int*>(&r);
+
+
+The matcher cxxConstCastExpr()
+matches const_cast<int*>(&r).
 
Matcher<Stmt>cxxConstructExprMatcher<CXXConstructExpr>...
Matches constructor call expressions (including implicit ones).
 
-Example matches string(ptr, n) and ptr within arguments of f
-    (matcher = cxxConstructExpr())
+Given
+  struct string {
+    string(const char*);
+    string(const char*s, int n);
+  };
   void f(const string &a, const string &b);
-  char *ptr;
-  int n;
-  f(string(ptr, n), ptr);
+  void foo(char *ptr, int n) {
+    f(string(ptr, n), ptr);
+  }
+
+
+The matcher cxxConstructExpr() matches string(ptr, n)
+and ptr within arguments of f .
 
Matcher<Stmt>cxxDefaultArgExprMatcher<CXXDefaultArgExpr>...
Matches the value of a default argument at the call site.
 
-Example matches the CXXDefaultArgExpr placeholder inserted for the
-    default value of the second parameter in the call expression f(42)
-    (matcher = cxxDefaultArgExpr())
+Given
   void f(int x, int y = 0);
-  f(42);
+  void g() {
+    f(42);
+  }
+
+
+The matcher callExpr(has(cxxDefaultArgExpr()))
+matches the CXXDefaultArgExpr placeholder inserted for the default value
+of the second parameter in the call expression f(42).
 
@@ -1598,9 +2049,17 @@

Node Matchers

Matches delete expressions.
 
 Given
-  delete X;
-cxxDeleteExpr()
-  matches 'delete X'.
+  void* operator new(decltype(sizeof(void*)));
+  void operator delete(void*);
+  struct X {};
+  void foo() {
+    auto* x = new X;
+    delete x;
+  }
+
+
+The matcher cxxDeleteExpr()
+matches delete x.
 
@@ -1610,7 +2069,8 @@

Node Matchers

Given template <class T> void f() { T t; t.g(); } -cxxDependentScopeMemberExpr() + +The matcher cxxDependentScopeMemberExpr() matches t.g @@ -1618,53 +2078,83 @@

Node Matchers

Matcher<Stmt>cxxDynamicCastExprMatcher<CXXDynamicCastExpr>...
Matches a dynamic_cast expression.
 
-Example:
-  cxxDynamicCastExpr()
-matches
-  dynamic_cast<D*>(&b);
-in
+Given
   struct B { virtual ~B() {} }; struct D : B {};
   B b;
   D* p = dynamic_cast<D*>(&b);
+
+
+The matcher cxxDynamicCastExpr()
+matches dynamic_cast<D*>(&b).
 
Matcher<Stmt>cxxFoldExprMatcher<CXXFoldExpr>...
Matches C++17 fold expressions.
 
-Example matches `(0 + ... + args)`:
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
   }
+
+
+The matcher cxxFoldExpr() matches (0 + ... + args).
 
Matcher<Stmt>cxxForRangeStmtMatcher<CXXForRangeStmt>...
Matches range-based for statements.
 
-cxxForRangeStmt() matches 'for (auto a : i)'
-  int i[] =  {1, 2, 3}; for (auto a : i);
-  for(int j = 0; j < 5; ++j);
+Given
+  void foo() {
+    int i[] =  {1, 2, 3}; for (auto a : i);
+    for(int j = 0; j < 5; ++j);
+  }
+
+The matcher cxxForRangeStmt()
+matches for (auto a : i);
 
Matcher<Stmt>cxxFunctionalCastExprMatcher<CXXFunctionalCastExpr>...
Matches functional cast expressions
 
-Example: Matches Foo(bar);
-  Foo f = bar;
-  Foo g = (Foo) bar;
-  Foo h = Foo(bar);
+Given
+  struct Foo {
+    Foo(int x);
+  };
+
+  void foo(int bar) {
+    Foo f = bar;
+    Foo g = (Foo) bar;
+    Foo h = Foo(bar);
+  }
+
+
+The matcher cxxFunctionalCastExpr()
+matches Foo(bar).
 
Matcher<Stmt>cxxMemberCallExprMatcher<CXXMemberCallExpr>...
Matches member call expressions.
 
-Example matches x.y()
-  X x;
-  x.y();
+Given
+  struct X {
+    void y();
+    void m() { y(); }
+  };
+  void f();
+  void g() {
+    X x;
+    x.y();
+    f();
+  }
+
+
+The matcher cxxMemberCallExpr() matches x.y() and
+y(), but not f().
 
@@ -1672,9 +2162,15 @@

Node Matchers

Matches new expressions.
 
 Given
-  new X;
-cxxNewExpr()
-  matches 'new X'.
+  void* operator new(decltype(sizeof(void*)));
+  struct X {};
+  void foo() {
+    auto* x = new X;
+  }
+
+
+The matcher cxxNewExpr()
+matches new X.
 
@@ -1687,14 +2183,24 @@

Node Matchers

bool c() noexcept(false); bool d() noexcept(noexcept(a())); bool e = noexcept(b()) || noexcept(c()); -cxxNoexceptExpr() - matches `noexcept(a())`, `noexcept(b())` and `noexcept(c())`. - doesn't match the noexcept specifier in the declarations a, b, c or d. + +The matcher cxxNoexceptExpr() +matches noexcept(a()), noexcept(b()) and +noexcept(c()), but does not match the noexcept specifier in the +declarations a, b, c or d. Matcher<Stmt>cxxNullPtrLiteralExprMatcher<CXXNullPtrLiteralExpr>...
Matches nullptr literal.
+
+Given
+  int a = 0;
+  int* b = 0;
+  int *c = nullptr;
+
+
+The matcher cxxNullPtrLiteralExpr() matches nullptr.
 
@@ -1706,11 +2212,16 @@

Node Matchers

Currently it does not match operators such as new delete. FIXME: figure out why these do not match? -Example matches both operator<<((o << b), c) and operator<<(o, b) - (matcher = cxxOperatorCallExpr()) +Given + struct ostream; ostream &operator<< (ostream &out, int i) { }; - ostream &o; int b = 1, c = 1; - o << b << c; + void f(ostream& o, int b, int c) { + o << b << c; + } + + +The matcher cxxOperatorCallExpr() matches o << b << c +and o << b. See also the binaryOperation() matcher for more-general matching of binary uses of this AST node. @@ -1725,6 +2236,10 @@

Node Matchers

Example matches reinterpret_cast<char*>(&p) in void* p = reinterpret_cast<char*>(&p); + + +The matcher cxxReinterpretCastExpr() +matches reinterpret_cast<char*>(&p). @@ -1732,16 +2247,20 @@

Node Matchers

Matches rewritten binary operators
 
 Example matches use of "<":
-  #include <compare>
   struct HasSpaceshipMem {
     int a;
-    constexpr auto operator<=>(const HasSpaceshipMem&) const = default;
+    constexpr bool operator==(const HasSpaceshipMem&) const = default;
   };
   void compare() {
     HasSpaceshipMem hs1, hs2;
-    if (hs1 < hs2)
+    if (hs1 != hs2)
         return;
   }
+
+
+The matcher cxxRewrittenBinaryOperator() matches
+hs1 != hs2.
+
 See also the binaryOperation() matcher for more-general matching
 of this AST node.
 
@@ -1753,12 +2272,12 @@

Node Matchers

See also: hasDestinationType See also: reinterpretCast -Example: - cxxStaticCastExpr() -matches - static_cast<long>(8) -in +Given long eight(static_cast<long>(8)); + + +The matcher cxxStaticCastExpr() +matches static_cast<long>(8). @@ -1766,69 +2285,110 @@

Node Matchers

Matches C++ initializer list expressions.
 
 Given
-  std::vector<int> a({ 1, 2, 3 });
-  std::vector<int> b = { 4, 5 };
+  namespace std {
+    template <typename T>
+    class initializer_list {
+      const T* begin;
+      const T* end;
+    };
+  }
+  template <typename T> class vector {
+    public: vector(std::initializer_list<T>) {}
+  };
+
+  vector<int> a({ 1, 2, 3 });
+  vector<int> b = { 4, 5 };
   int c[] = { 6, 7 };
-  std::pair<int, int> d = { 8, 9 };
-cxxStdInitializerListExpr()
-  matches "{ 1, 2, 3 }" and "{ 4, 5 }"
+  struct pair { int x; int y; };
+  pair d = { 8, 9 };
+
+The matcher cxxStdInitializerListExpr()
+matches { 1, 2, 3 } and { 4, 5 }.
 
Matcher<Stmt>cxxTemporaryObjectExprMatcher<CXXTemporaryObjectExpr>...
Matches functional cast expressions having N != 1 arguments
 
-Example: Matches Foo(bar, bar)
-  Foo h = Foo(bar, bar);
+Given
+  struct Foo {
+    Foo(int x, int y);
+  };
+
+  void foo(int bar) {
+    Foo h = Foo(bar, bar);
+  }
+
+
+The matcher cxxTemporaryObjectExpr()
+matches Foo(bar, bar).
 
-Matcher<Stmt>cxxThisExprMatcher<CXXThisExpr>... -
Matches implicit and explicit this expressions.
+Matcher<Stmt>cxxThisExprMatcher<CXXThisExpr>...
+
Matches implicit and explicit this expressions.
+
+Given
+  struct foo {
+    int i;
+    int f() { return i; }
+    int g() { return this->i; }
+  };
+
 
-Example matches the implicit this expression in "return i".
-    (matcher = cxxThisExpr())
-struct foo {
-  int i;
-  int f() { return i; }
-};
+The matcher cxxThisExpr()
+matches this of this->i and the implicit this expression
+of i.
 
Matcher<Stmt>cxxThrowExprMatcher<CXXThrowExpr>...
Matches throw expressions.
 
+void foo() {
   try { throw 5; } catch(int i) {}
-cxxThrowExpr()
-  matches 'throw 5'
+}
+
+The matcher cxxThrowExpr()
+matches throw 5
 
Matcher<Stmt>cxxTryStmtMatcher<CXXTryStmt>...
Matches try statements.
 
+void foo() {
   try {} catch(int i) {}
-cxxTryStmt()
-  matches 'try {}'
+}
+
+The matcher cxxTryStmt()
+matches try {} catch(int i) {}
 
Matcher<Stmt>cxxUnresolvedConstructExprMatcher<CXXUnresolvedConstructExpr>...
Matches unresolved constructor call expressions.
 
-Example matches T(t) in return statement of f
-    (matcher = cxxUnresolvedConstructExpr())
+Given
   template <typename T>
   void f(const T& t) { return T(t); }
+
+
+The matcher cxxUnresolvedConstructExpr() matches
+T(t).
 
Matcher<Stmt>declRefExprMatcher<DeclRefExpr>...
Matches expressions that refer to declarations.
 
-Example matches x in if (x)
-  bool x;
-  if (x) {}
+Given
+  void f(bool x) {
+    if (x) {}
+  }
+
+
+The matcher declRefExpr() matches x.
 
@@ -1836,9 +2396,11 @@

Node Matchers

Matches declaration statements.
 
 Given
-  int a;
-declStmt()
-  matches 'int a'.
+  void foo() {
+    int a;
+  }
+The matcher declStmt()
+matches int a;.
 
@@ -1846,22 +2408,75 @@

Node Matchers

Matches default statements inside switch statements.
 
 Given
+void foo(int a) {
   switch(a) { case 42: break; default: break; }
-defaultStmt()
-  matches 'default:'.
+}
+The matcher defaultStmt()
+matches default: break.
 
Matcher<Stmt>dependentCoawaitExprMatcher<DependentCoawaitExpr>...
Matches co_await expressions where the type of the promise is dependent
+
+Given
+  namespace std {
+  template <typename T = void>
+  struct coroutine_handle {
+      static constexpr coroutine_handle from_address(void* addr) {
+        return {};
+      }
+  };
+
+  struct always_suspend {
+      bool await_ready() const noexcept;
+      bool await_resume() const noexcept;
+      template <typename T>
+      bool await_suspend(coroutine_handle<T>) const noexcept;
+  };
+
+  template <typename T>
+  struct coroutine_traits {
+      using promise_type = T::promise_type;
+  };
+  }  // namespace std
+
+  template <typename T>
+  struct generator {
+      struct promise_type {
+          std::always_suspend yield_value(int&&);
+          std::always_suspend initial_suspend() const noexcept;
+          std::always_suspend final_suspend() const noexcept;
+          void return_void();
+          void unhandled_exception();
+          generator get_return_object();
+      };
+  };
+
+  template <typename T>
+  std::always_suspend h();
+
+  template <>
+  std::always_suspend h<void>();
+
+  template<typename T>
+  generator<T> g() { co_await h<T>(); }
+
+The matcher dependentCoawaitExpr()
+matches co_await h<T>().
 
Matcher<Stmt>designatedInitExprMatcher<DesignatedInitExpr>...
Matches C99 designated initializer expressions [C99 6.7.8].
 
-Example: Matches { [2].y = 1.0, [0].x = 1.0 }
-  point ptarray[10] = { [2].y = 1.0, [0].x = 1.0 };
+Example: Given
+  struct point2 { double x; double y; };
+  struct point2 ptarray[10] = { [0].x = 1.0 };
+  struct point2 pt = { .x = 2.0 };
+
+The matcher designatedInitExpr()
+matches [0].x = 1.0 and .x = 2.0.
 
@@ -1869,9 +2484,12 @@

Node Matchers

Matches do statements.
 
 Given
+void foo() {
   do {} while (true);
-doStmt()
-  matches 'do {} while(true)'
+}
+
+The matcher doStmt()
+matches do {} while (true)
 
@@ -1889,18 +2507,36 @@

Node Matchers

See also: hasDestinationType. -Example: matches all five of the casts in - int((int)(reinterpret_cast<int>(static_cast<int>(const_cast<int>(42))))) -but does not match the implicit conversion in - long ell = 42; + struct S {}; + const S* s; + S* s2 = const_cast<S*>(s); + + const int val = 0; + char val0 = val; + char val1 = (char)val; + char val2 = static_cast<char>(val); + int* val3 = reinterpret_cast<int*>(val); + char val4 = char(val); + + +The matcher explicitCastExpr() +matches (char)val, static_cast<char>(val), +reinterpret_cast<int*>(val), const_cast<S*>(s) +and char(val), but not the initialization of val0 with +val.
Matcher<Stmt>exprMatcher<Expr>...
Matches expressions.
 
-Example matches x()
-  void f() { x(); }
+Given
+  int f(int x, int y) { return x + y; }
+
+The matcher expr() matches x + y once,
+x twice and y twice, matching the
+DeclRefExpr , and the ImplicitCastExpr that does an l- to r-value
+cast.
 
@@ -1909,12 +2545,33 @@

Node Matchers

of the sub-expression's evaluation. Example matches std::string() - const std::string str = std::string(); + struct A { ~A(); }; + void f(A); + void g(A&); + void h() { + A a = A{}; + f(A{}); + f(a); + g(a); + } + + +The matcher exprWithCleanups() matches A{}, +f(A{}) and f(a), +but does not match passing g(a). Matcher<Stmt>fixedPointLiteralMatcher<FixedPointLiteral>...
Matches fixed point literals
+
+Given
+  void f() {
+    0.0k;
+  }
+
+
+The matcher fixedPointLiteral() matches 0.0k.
 
@@ -1922,27 +2579,62 @@

Node Matchers

Matches float literals of all sizes / encodings, e.g.
 1.0, 1.0f, 1.0L and 1e10.
 
-Does not match implicit conversions such as
-  float a = 10;
+Given
+  int a = 1.0;
+  int b = 1.0F;
+  int c = 1.0L;
+  int d = 1e10;
+  int e = 1;
+
+The matcher floatLiteral() matches
+1.0, 1.0F, 1.0L and 1e10, but does not match
+1.
 
Matcher<Stmt>forStmtMatcher<ForStmt>...
Matches for statements.
 
-Example matches 'for (;;) {}'
-  for (;;) {}
-  int i[] =  {1, 2, 3}; for (auto a : i);
+Given
+  void foo() {
+    for (;;) {}
+    int i[] =  {1, 2, 3}; for (auto a : i);
+  }
+
+
+The matcher forStmt() matches for (;;) {},
+but not for (auto a : i);.
 
Matcher<Stmt>genericSelectionExprMatcher<GenericSelectionExpr>...
Matches C11 _Generic expression.
+
+Given
+  double fdouble(double);
+  float ffloat(float);
+  #define GENERIC_MACRO(X) _Generic((X), double: fdouble, float: ffloat)(X)
+
+  void f() {
+      GENERIC_MACRO(0.0);
+      GENERIC_MACRO(0.0F);
+  }
+
+
+The matcher genericSelectionExpr() matches
+the generic selection expression that is expanded in
+GENERIC_MACRO(0.0) and GENERIC_MACRO(0.0F).
 
Matcher<Stmt>gnuNullExprMatcher<GNUNullExpr>...
Matches GNU __null expression.
+
+Given
+  auto val = __null;
+
+
+The matcher gnuNullExpr() matches __null.
 
@@ -1950,24 +2642,39 @@

Node Matchers

Matches goto statements.
 
 Given
+void bar();
+void foo() {
   goto FOO;
   FOO: bar();
-gotoStmt()
-  matches 'goto FOO'
+}
+The matcher gotoStmt()
+matches goto FOO
 
Matcher<Stmt>ifStmtMatcher<IfStmt>...
Matches if statements.
 
-Example matches 'if (x) {}'
-  if (x) {}
+Given
+  void foo(int x) {
+    if (x) {}
+  }
+
+The matcher ifStmt() matches if (x) {}.
 
Matcher<Stmt>imaginaryLiteralMatcher<ImaginaryLiteral>...
Matches imaginary literals, which are based on integer and floating
 point literals e.g.: 1i, 1.0i
+
+Given
+  auto a = 1i;
+  auto b = 1.0i;
+
+
+The matcher imaginaryLiteral() matches 1i and
+1.0i.
 
@@ -1976,6 +2683,17 @@

Node Matchers

This matches many different places, including function call return value eliding, as well as any type conversions. + +void f(int); +void g(int val1, int val2) { + unsigned int a = val1; + f(val2); +} + +The matcher implicitCastExpr() +matches val1 for the implicit cast from an l- to an r-value +and for the cast to int}, f for the function pointer +decay, and val2 for the cast from an l- to an r-value. @@ -1983,9 +2701,11 @@

Node Matchers

Matches implicit initializers of init list expressions.
 
 Given
-  point ptarray[10] = { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 };
-implicitValueInitExpr()
-  matches "[0].y" (implicitly)
+  struct point { double x; double y; };
+  struct point pt = { .x = 42.0 };
+The matcher
+initListExpr(has(implicitValueInitExpr().bind("implicit")))
+matches { .x = 42.0 }.
 
@@ -1995,9 +2715,9 @@

Node Matchers

Given int a[] = { 1, 2 }; struct B { int x, y; }; - B b = { 5, 6 }; -initListExpr() - matches "{ 1, 2 }" and "{ 5, 6 }" + struct B b = { 5, 6 }; +The matcher initListExpr() +matches { 1, 2 } and { 5, 6 } @@ -2006,6 +2726,17 @@

Node Matchers

1, 1L, 0x1 and 1U. Does not match character-encoded integers such as L'a'. + +Given + int a = 1; + int b = 1L; + int c = 0x1; + int d = 1U; + int e = 1.0; + +The matcher integerLiteral() matches +1, 1L, 0x1 and 1U, but does not match +1.0. @@ -2013,18 +2744,26 @@

Node Matchers

Matches label statements.
 
 Given
+void bar();
+void foo() {
   goto FOO;
   FOO: bar();
-labelStmt()
-  matches 'FOO:'
+}
+The matcher labelStmt()
+matches FOO: bar()
 
Matcher<Stmt>lambdaExprMatcher<LambdaExpr>...
Matches lambda expressions.
 
-Example matches [&](){return 5;}
-  [&](){return 5;}
+Given
+  void f() {
+    []() { return 5; };
+  }
+
+
+The matcher lambdaExpr() matches []() { return 5; }.
 
@@ -2035,12 +2774,17 @@

Node Matchers

struct T {void func();}; T f(); void g(T); -materializeTemporaryExpr() matches 'f()' in these statements - T u(f()); - g(f()); - f().func(); -but does not match - f(); + void foo() { + T u(f()); + g(f()); + f().func(); + f(); // does not match + } + +The matcher materializeTemporaryExpr() matches +f() three times before C++17 and it +matches f() time with C++17 and later, but +it does not match the f() in the last line in any version. @@ -2052,17 +2796,20 @@

Node Matchers

void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; } int a; static int b; }; -memberExpr() - matches this->x, x, y.x, a, this->b + +The matcher memberExpr() +matches this->x, x, y.x, a, this->b. Matcher<Stmt>nullStmtMatcher<NullStmt>...
Matches null statements.
 
+void foo() {
   foo();;
-nullStmt()
-  matches the second ';'
+}
+The matcher nullStmt()
+matches the second ;
 
@@ -2072,6 +2819,7 @@

Node Matchers

Example matches @catch @try {} @catch (...) {} + @@ -2081,19 +2829,23 @@

Node Matchers

Example matches @finally @try {} @finally {} + Matcher<Stmt>objcIvarRefExprMatcher<ObjCIvarRefExpr>...
Matches a reference to an ObjCIvar.
 
-Example: matches "a" in "init" method:
+Given
 @implementation A {
   NSString *a;
 }
 - (void) init {
   a = @"hello";
 }
+
+
+The matcher objcIvarRefExpr() matches a.
 
@@ -2105,6 +2857,10 @@

Node Matchers

"initWithString" instance method on the object returned from NSString's "alloc". This matcher should match both message sends. [[NSString alloc] initWithString:@"Hello"] + + +The matcher objcMessageExpr() matches +[[NSString alloc] initWithString:@"Hello"] @@ -2113,6 +2869,7 @@

Node Matchers

Example matches @"abcd" NSString *s = @"abcd"; + @@ -2120,6 +2877,7 @@

Node Matchers

Matches Objective-C statements.
 
 Example matches @throw obj;
+
 
@@ -2129,6 +2887,7 @@

Node Matchers

Example matches @try @try {} @catch (...) {} + @@ -2136,13 +2895,19 @@

Node Matchers

Matches any ``#pragma omp`` executable directive.
 
 Given
+  void foo() {
+    #pragma omp parallel
+      {}
+    #pragma omp parallel default(none)
+      {
+        #pragma omp taskyield
+      }
+  }
 
-  #pragma omp parallel
-  #pragma omp parallel default(none)
-  #pragma omp taskyield
-
-``ompExecutableDirective()`` matches ``omp parallel``,
-``omp parallel default(none)`` and ``omp taskyield``.
+The matcher ompExecutableDirective()
+matches #pragma omp parallel,
+#pragma omp parallel default(none)
+and #pragma omp taskyield.
 
@@ -2151,17 +2916,27 @@

Node Matchers

to reference another expressions and can be met in BinaryConditionalOperators, for example. -Example matches 'a' - (a ?: c) + 42; +Given + int f(int a, int b) { + return (a ?: b) + 42; + } + + +The matcher opaqueValueExpr() matches a twice, +once for the check and once for the expression of the true path. Matcher<Stmt>parenExprMatcher<ParenExpr>...
Matches parentheses used in expressions.
 
-Example matches (foo() + 1)
+Given
   int foo() { return 1; }
-  int a = (foo() + 1);
+  int bar() {
+    int a = (foo() + 1);
+  }
+
+The matcher parenExpr() matches (foo() + 1).
 
@@ -2177,8 +2952,12 @@

Node Matchers

int a = 0, b = 1; int i = (a, b); } }; -parenListExpr() matches "*this" but NOT matches (a, b) because (a, b) -has a predefined type and is a ParenExpr, not a ParenListExpr. + +The matcher parenListExpr() +matches (*this), +but does not match (a, b) +because (a, b) has a predefined type and is a ParenExpr, not a +ParenListExpr. @@ -2186,7 +2965,12 @@

Node Matchers

Matches predefined identifier expressions [C99 6.4.2.2].
 
 Example: Matches __func__
-  printf("%s", __func__);
+  void f() {
+    const char* func_name = __func__;
+  }
+
+The matcher predefinedExpr()
+matches __func__.
 
@@ -2194,9 +2978,11 @@

Node Matchers

Matches return statements.
 
 Given
+int foo() {
   return 1;
-returnStmt()
-  matches 'return 1'
+}
+The matcher returnStmt()
+matches return 1
 
@@ -2204,26 +2990,35 @@

Node Matchers

Matches statements.
 
 Given
-  { ++a; }
-stmt()
-  matches both the compound statement '{ ++a; }' and '++a'.
+  void foo(int a) { { ++a; } }
+The matcher stmt()
+matches the function body itself { { ++a; } }, the compound
+statement { ++a; }, the expression ++a and a.
 
Matcher<Stmt>stmtExprMatcher<StmtExpr>...
Matches statement expression (GNU extension).
 
-Example match: ({ int X = 4; X; })
-  int C = ({ int X = 4; X; });
+Given
+  void f() {
+    int C = ({ int X = 4; X; });
+  }
+
+The matcher stmtExpr() matches ({ int X = 4; X; }).
 
Matcher<Stmt>stringLiteralMatcher<StringLiteral>...
Matches string literals (also matches wide string literals).
 
-Example matches "abcd", L"abcd"
+Given
   char *s = "abcd";
   wchar_t *ws = L"abcd";
+
+
+The matcher stringLiteral() matches "abcd" and
+L"abcd".
 
@@ -2234,8 +3029,9 @@

Node Matchers

template <int N> struct A { static const int n = N; }; struct B : public A<42> {}; -substNonTypeTemplateParmExpr() - matches "N" in the right-hand side of "static const int n = N;" + +The matcher substNonTypeTemplateParmExpr() +matches N in the right-hand side of "static const int n = N;" @@ -2243,9 +3039,11 @@

Node Matchers

Matches case and default statements inside switch statements.
 
 Given
+void foo(int a) {
   switch(a) { case 42: break; default: break; }
-switchCase()
-  matches 'case 42:' and 'default:'.
+}
+The matcher switchCase()
+matches case 42: break and default: break
 
@@ -2253,9 +3051,11 @@

Node Matchers

Matches switch statements.
 
 Given
+void foo(int a) {
   switch(a) { case 42: break; default: break; }
-switchStmt()
-  matches 'switch(a)'.
+}
+The matcher switchStmt()
+matches switch(a) { case 42: break; default: break; }.
 
@@ -2263,10 +3063,11 @@

Node Matchers

Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
 
 Given
-  Foo x = bar;
+  int x = 42;
   int y = sizeof(x) + alignof(x);
-unaryExprOrTypeTraitExpr()
-  matches sizeof(x) and alignof(x)
+
+The matcher unaryExprOrTypeTraitExpr()
+matches sizeof(x) and alignof(x)
 
@@ -2274,7 +3075,12 @@

Node Matchers

Matches unary operator expressions.
 
 Example matches !a
-  !a || b
+  void foo(bool a, bool b) {
+    !a || b;
+  }
+
+
+The matcher unaryOperator() matches !a.
 
@@ -2289,8 +3095,10 @@

Node Matchers

void bar() { foo<T>(); } -unresolvedLookupExpr() - matches foo<T>() + +The matcher unresolvedLookupExpr() +matches foo<T>. + Matcher<Stmt>unresolvedMemberExprMatcher<UnresolvedMemberExpr>... @@ -2302,8 +3110,9 @@

Node Matchers

void g(); }; template <class T> void h() { X x; x.f<T>(); x.g(); } -unresolvedMemberExpr() - matches x.f<T> + +The matcher unresolvedMemberExpr() +matches x.f<T> @@ -2311,6 +3120,12 @@

Node Matchers

Matches user defined literal operator call.
 
 Example match: "foo"_suffix
+Given
+  float operator ""_foo(long double);
+  float a = 1234.5_foo;
+
+
+The matcher userDefinedLiteral() matches 1234.5_foo.
 
@@ -2318,9 +3133,12 @@

Node Matchers

Matches while statements.
 
 Given
+void foo() {
   while (true) {}
-whileStmt()
-  matches 'while (true) {}'.
+}
+
+The matcher whileStmt()
+matches while (true) {}.
 
@@ -2330,8 +3148,9 @@

Node Matchers

Given template <typename T> struct C {}; C<int> c; -templateArgumentLoc() - matches 'int' in C<int>. + +The matcher templateArgumentLoc() +matches int in C<int>. @@ -2341,8 +3160,10 @@

Node Matchers

Given template <typename T> struct C {}; C<int> c; -templateArgument() - matches 'int' in C<int>. + +The matcher +templateSpecializationType(hasAnyTemplateArgument(templateArgument())) +matches C<int>. @@ -2350,10 +3171,14 @@

Node Matchers

Matches template name.
 
 Given
-  template <typename T> class X { };
-  X<int> xi;
-templateName()
-  matches 'X' in X<int>.
+  template<template <typename> class S> class X {};
+  template<typename T> class Y {};
+  X<Y> xi;
+
+The matcher
+classTemplateSpecializationDecl(hasAnyTemplateArgument(
+              refersToTemplate(templateName())))
+matches the specialization class X<Y>
 
@@ -2363,8 +3188,8 @@

Node Matchers

Given struct s {}; struct s ss; -elaboratedTypeLoc() - matches the `TypeLoc` of the variable declaration of `ss`. +The matcher elaboratedTypeLoc() +matches the type struct s of ss. @@ -2373,8 +3198,8 @@

Node Matchers

Given int* x; -pointerTypeLoc() - matches `int*`. +The matcher pointerTypeLoc() + matches int*. @@ -2383,8 +3208,11 @@

Node Matchers

Given const int x = 0; -qualifiedTypeLoc() - matches `const int`. + +The matcher qualifiedTypeLoc() +matches the type of the variable declaration x . However, the +current implementation of QualifiedTypeLoc does not store the source +locations for the qualifiers of the type int. @@ -2395,8 +3223,10 @@

Node Matchers

int x = 3; int& l = x; int&& r = 3; -referenceTypeLoc() - matches `int&` and `int&&`. + + +The matcher referenceTypeLoc() + matches int& and int&&. @@ -2406,13 +3236,25 @@

Node Matchers

Given template <typename T> class C {}; C<char> var; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(typeLoc()))) - matches `C<char> var`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(typeLoc()))))) +matches C<char> var. Matcher<TypeLoc>typeLocMatcher<TypeLoc>...
Matches TypeLocs in the clang AST.
+
+That is, information about a type and where it was written.
+
+  void foo(int val);
+
+The matcher declaratorDecl(hasTypeLoc(typeLoc().bind("type")))
+matches void foo(int val) and int val, with
+typeLoc() matching void and
+int respectively.
 
@@ -2423,8 +3265,9 @@

Node Matchers

int a[] = { 2, 3 }; int b[4]; void f() { int c[a[0]]; } -arrayType() - matches "int a[]", "int b[4]" and "int c[a[0]]"; +The matcher arrayType() +int[4], int[a[0]] and +int[]; @@ -2433,20 +3276,25 @@

Node Matchers

Given _Atomic(int) i; -atomicType() - matches "_Atomic(int) i" +The matcher atomicType() +_Atomic(int) Matcher<Type>autoTypeMatcher<AutoType>...
Matches types nodes representing C++11 auto types.
 
-Given:
-  auto n = 4;
-  int v[] = { 2, 3 }
-  for (auto i : v) { }
-autoType()
-  matches "auto n" and "auto i"
+Given
+  void foo() {
+    auto n = 4;
+    int v[] = { 2, 3 };
+    for (auto i : v) { };
+  }
+
+The matcher autoType()
+matches the auto of n and i ,
+as well as the auto types for the implicitly generated code of the range-for
+loop (for the range, the begin iterator and the end iterator).
 
@@ -2462,13 +3310,12 @@

Node Matchers

Matches builtin Types.
 
 Given
-  struct A {};
-  A a;
+  enum E { Ok };
+  enum E e;
   int b;
   float c;
-  bool d;
-builtinType()
-  matches "int b", "float c" and "bool d"
+The matcher varDecl(hasType(builtinType()))
+matches int b and float c.
 
@@ -2477,8 +3324,8 @@

Node Matchers

Given _Complex float f; -complexType() - matches "_Complex float f" +The matcher complexType() +_Complex float @@ -2486,37 +3333,38 @@

Node Matchers

Matches C arrays with a specified constant size.
 
 Given
-  void() {
+  void foo() {
     int a[2];
     int b[] = { 2, 3 };
     int c[b[0]];
   }
-constantArrayType()
-  matches "int a[2]"
+The matcher constantArrayType()
+int[2]
 
Matcher<Type>decayedTypeMatcher<DecayedType>...
Matches decayed type
-Example matches i[] in declaration of f.
-    (matcher = valueDecl(hasType(decayedType(hasDecayedType(pointerType())))))
-Example matches i[1].
-    (matcher = expr(hasType(decayedType(hasDecayedType(pointerType())))))
   void f(int i[]) {
     i[1] = 0;
   }
-
+The matcher +valueDecl(hasType(decayedType(hasDecayedType(pointerType())))) +matches int i[] in declaration of The matcher +expr(hasType(decayedType(hasDecayedType(pointerType())))) +matches i in Matcher<Type>decltypeTypeMatcher<DecltypeType>...
Matches types nodes representing C++11 decltype(<expr>) types.
 
-Given:
+Given
   short i = 1;
   int j = 42;
   decltype(i + j) result = i + j;
-decltypeType()
-  matches "decltype(i + j)"
+
+The matcher decltypeType()
+decltype(i + j)
 
@@ -2529,8 +3377,9 @@

Node Matchers

class C { public: C(T); }; C c(123); -deducedTemplateSpecializationType() matches the type in the declaration -of the variable c. + +The matcher deducedTemplateSpecializationType() matches the type +C of the declaration of the variable c. @@ -2542,8 +3391,9 @@

Node Matchers

class array { T data[Size]; }; -dependentSizedArrayType() - matches "T data[Size]" + +The matcher dependentSizedArrayType() +T[Size] @@ -2556,8 +3406,9 @@

Node Matchers

class vector { typedef T __attribute__((ext_vector_type(Size))) type; }; -dependentSizedExtVectorType() - matches "T __attribute__((ext_vector_type(Size)))" + +The matcher dependentSizedExtVectorType() +T __attribute__((ext_vector_type(Size))) @@ -2573,11 +3424,17 @@

Node Matchers

} class C {}; - class C c; + C c; N::M::D d; -elaboratedType() matches the type of the variable declarations of both -c and d. + +The matcher elaboratedType() matches the type +C three times. Once for the type of the +variable c, once for the type of the class definition and once for the +type in the injected class name. For D}, it matches +N::M::D of variable d and its class definition and +injected class name +D one time respectively. @@ -2591,8 +3448,10 @@

Node Matchers

C c; S s; -enumType() matches the type of the variable declarations of both c and -s. + +The matcher enumType() matches the type +enum C of c , +and the type enum S of s . @@ -2602,9 +3461,11 @@

Node Matchers

Given int (*f)(int); void g(); -functionProtoType() - matches "int (*f)(int)" and the type of "g" in C++ mode. - In C mode, "g" is not matched because it does not contain a prototype. +The matcher functionProtoType() +matches the type int (int) of 'f' and the type +void (void) of 'g' in C++ mode. +In C, the type void () of 'g' is not +matched because it does not contain a prototype. @@ -2614,8 +3475,12 @@

Node Matchers

Given int (*f)(int); void g(); -functionType() - matches "int (*f)(int)" and the type of "g". +The matcher functionType() +int (int) and the type of +void (void) in C++ and in C23 and +later. Before C23, the function type for f will be matched the same way, +but the function type for g will match +void (). @@ -2626,27 +3491,30 @@

Node Matchers

int a[] = { 2, 3 }; int b[42]; void f(int c[]) { int d[a[0]]; }; -incompleteArrayType() - matches "int a[]" and "int c[]" +The matcher incompleteArrayType() +int[] and int[] Matcher<Type>injectedClassNameTypeMatcher<InjectedClassNameType>...
Matches injected class name types.
 
-Example matches S s, but not S<T> s.
-    (matcher = parmVarDecl(hasType(injectedClassNameType())))
+Given
   template <typename T> struct S {
     void f(S s);
     void g(S<T> s);
   };
+
+The matcher
+parmVarDecl(hasType(elaboratedType(namesType(injectedClassNameType()))))
+matches S s, but not s}
 
Matcher<Type>lValueReferenceTypeMatcher<LValueReferenceType>...
Matches lvalue reference types.
 
-Given:
+Given
   int *a;
   int &b = *a;
   int &&c = 1;
@@ -2655,8 +3523,11 @@ 

Node Matchers

auto &&f = 2; int g = 5; -lValueReferenceType() matches the types of b, d, and e. e is -matched since the type is deduced as int& by reference collapsing rules. + +The matcher lValueReferenceType() matches the type +int & of b and the type auto & +of d. +FIXME: figure out why auto changechange matches twice
@@ -2667,18 +3538,23 @@

Node Matchers

#define CDECL __attribute__((cdecl)) typedef void (CDECL *X)(); typedef void (__attribute__((cdecl)) *Y)(); -macroQualifiedType() - matches the type of the typedef declaration of X but not Y. +The matcher macroQualifiedType() +matches the type CDECL void +(void) of the typedef declaration of X , unless when in C98-C17, there +CDECL void (), +but it does not match the type +__attribute((cdecl)) void () of Y . Matcher<Type>memberPointerTypeMatcher<MemberPointerType>...
Matches member pointer types.
 Given
-  struct A { int i; }
-  A::* ptr = A::i;
-memberPointerType()
-  matches "A::* ptr"
+  struct A { int i; };
+  int A::* ptr = &A::i;
+
+The matcher memberPointerType()
+matches int struct A::*.
 
@@ -2692,8 +3568,10 @@

Node Matchers

@interface Foo @end Foo *f; -pointerType() - matches "Foo *f", but does not match "int *a". + +The matcher pointerType() +matches Foo *, but does not match +int *. @@ -2704,8 +3582,9 @@

Node Matchers

int (*ptr_to_array)[4]; int *array_of_ptrs[4]; -varDecl(hasType(pointsTo(parenType()))) matches ptr_to_array but not -array_of_ptrs. +The matcher varDecl(hasType(pointsTo(parenType()))) + matches ptr_to_array but not + array_of_ptrs. @@ -2714,22 +3593,28 @@

Node Matchers

types. Given - int *a; - int &b = *a; - int c = 5; + typedef int* int_ptr; + void foo(char *str, + int val, + int *val_ptr, + int_ptr not_a_ptr, + int_ptr *ptr); + +The matcher parmVarDecl(hasType(pointerType())) +matches char *str, int *val_ptr and +int_ptr *ptr. @interface Foo @end Foo *f; -pointerType() - matches "int *a", but does not match "Foo *f". + Matcher<Type>rValueReferenceTypeMatcher<RValueReferenceType>...
Matches rvalue reference types.
 
-Given:
+Given
   int *a;
   int &b = *a;
   int &&c = 1;
@@ -2738,8 +3623,10 @@ 

Node Matchers

auto &&f = 2; int g = 5; -rValueReferenceType() matches the types of c and f. e is not -matched as it is deduced to int& by reference collapsing rules. + +The matcher rValueReferenceType() matches the type +int && of c and the type +auto && of f.
@@ -2753,8 +3640,14 @@

Node Matchers

C c; S s; -recordType() matches the type of the variable declarations of both c -and s. + +The matcher recordType() matches the type +class C of the variable declaration of c and +matches the type struct S of the variable +declaration of s. +Both of these types are matched three times, once for the type of the +variable, once for the definition of the class, and once for the type of the +injected class name. @@ -2770,7 +3663,12 @@

Node Matchers

auto &&f = 2; int g = 5; -referenceType() matches the types of b, c, d, e, and f. + +The matcher referenceType() matches the type +int & of b , the type int && of +c, the type +auto & d, and the type +auto && of e and f. @@ -2781,10 +3679,17 @@

Node Matchers

Given template <typename T> void F(T t) { + T local; int i = 1 + t; } + void f() { + F(0); + } -substTemplateTypeParmType() matches the type of 't' but not '1' + +The matcher varDecl(hasType(substTemplateTypeParmType())) +matches T t and T local for the substituted template type +int in the instantiation of F . @@ -2792,14 +3697,18 @@

Node Matchers

Matches tag types (record and enum types).
 
 Given
-  enum E {};
+  enum E { Ok };
   class C {};
 
   E e;
   C c;
 
-tagType() matches the type of the variable declarations of both e
-and c.
+
+The matcher tagType() matches the type
+enum E of variable e and the type
+class C three times, once for the type
+of the variable c , once for the type of the class definition and once of
+the type in the injected class name.
 
@@ -2810,25 +3719,38 @@

Node Matchers

template <typename T> class C { }; - template class C<int>; // A - C<char> var; // B + template class C<int>; + C<int> intvar; + C<char> charvar; -templateSpecializationType() matches the type of the explicit -instantiation in A and the type of the variable declaration in B. + +The matcher templateSpecializationType() matches the type +C<int> of the explicit instantiation in A and the +type C<char> of the variable declaration in +B. Matcher<Type>templateTypeParmTypeMatcher<TemplateTypeParmType>...
Matches template type parameter types.
 
-Example matches T, but not int.
-    (matcher = templateTypeParmType())
+Given
   template <typename T> void f(int i);
+
+The matcher templateTypeParmType() matches T,
+but does not match int.
 
Matcher<Type>typeMatcher<Type>...
Matches Types in the clang AST.
+
+Given
+  const int b = 1;
+
+The matcher varDecl(hasType(type().bind("type")))
+matches const int b = 1, with type()
+matching int.
 
@@ -2837,18 +3759,22 @@

Node Matchers

Given typedef int X; -typedefType() - matches "typedef int X" + X x = 0; +The matcher typedefType() +matches X. Matcher<Type>unaryTransformTypeMatcher<UnaryTransformType>...
Matches types nodes representing unary type transformations.
 
-Given:
-  typedef __underlying_type(T) type;
-unaryTransformType()
-  matches "__underlying_type(T)"
+Given
+  template <typename T> struct A {
+    typedef __underlying_type(T) type;
+  };
+
+The matcher unaryTransformType()
+matches __underlying_type(T)
 
@@ -2860,7 +3786,9 @@

Node Matchers

using a::S; S s; -usingType() matches the type of the variable declaration of s. + +The matcher usingType() matches the type a::S +of the variable declaration of s. @@ -2870,12 +3798,12 @@

Node Matchers

Given void f() { - int a[] = { 2, 3 } + int a[] = { 2, 3 }; int b[42]; int c[a[0]]; } -variableArrayType() - matches "int c[a[0]]" +The matcher variableArrayType() +int[a[0]] @@ -2899,6 +3827,12 @@

Narrowing Matchers

Matches if all given matchers match.
 
 Usable as: Any Matcher
+
+  int v0 = 0;
+  int v1 = 1;
+
+The matcher varDecl(allOf(hasName("v0"), hasType(isInteger())))
+matches int v0 = 0.
 
@@ -2906,6 +3840,13 @@

Narrowing Matchers

Matches if any of the given matchers matches.
 
 Usable as: Any Matcher
+
+  char v0 = 'a';
+  int v1 = 1;
+  float v2 = 2.0;
+
+The matcher varDecl(anyOf(hasName("v0"), hasType(isInteger())))
+matches char v0 = 'a' and int v1 = 1.
 
@@ -2916,11 +3857,11 @@

Narrowing Matchers

additional constraint. This will often be used with an explicit conversion to an internal::Matcher<> type such as TypeMatcher. -Example: DeclarationMatcher(anything()) matches all declarations, e.g., -"int* p" and "void f()" in +Given int* p; void f(); - +The matcher decl(anything()) +matches int* p and void f(). Usable as: Any Matcher @@ -2929,21 +3870,25 @@

Narrowing Matchers

Matches any of the NodeMatchers with InnerMatchers nested within
 
 Given
-  if (true);
-  for (; true; );
-with the matcher
-  mapAnyOf(ifStmt, forStmt).with(
-    hasCondition(cxxBoolLiteralExpr(equals(true)))
-    ).bind("trueCond")
-matches the if and the for. It is equivalent to:
-  auto trueCond = hasCondition(cxxBoolLiteralExpr(equals(true)));
-  anyOf(
-    ifStmt(trueCond).bind("trueCond"),
-    forStmt(trueCond).bind("trueCond")
-    );
+  void f() {
+    if (true);
+    for (; true; );
+  }
+
+
+The matcher stmt(mapAnyOf(ifStmt, forStmt).with(
+    hasCondition(cxxBoolLiteral(equals(true)))
+    )),
+which is equivalent to
+stmt(anyOf(
+    ifStmt(hasCondition(cxxBoolLiteral(equals(true)))).bind("trueCond"),
+    forStmt(hasCondition(cxxBoolLiteral(equals(true)))).bind("trueCond")
+    )),
+matches if (true); and for (; true; );.
 
 The with() chain-call accepts zero or more matchers which are combined
 as-if with allOf() in each of the node matchers.
+
 Usable as: Any Matcher
 
@@ -2951,10 +3896,13 @@

Narrowing Matchers

Matcher<*>unlessMatcher<*>
Matches if the provided matcher does not match.
 
-Example matches Y (matcher = cxxRecordDecl(unless(hasName("X"))))
+Given
   class X {};
   class Y {};
 
+The matcher cxxRecordDecl(unless(hasName("X")))
+matches Y
+
 Usable as: Any Matcher
 
@@ -2962,6 +3910,20 @@

Narrowing Matchers

Matcher<Attr>isImplicit
Matches an entity that has been implicitly added by the compiler (e.g.
 implicit default/copy constructors).
+
+Given
+  struct S {};
+  void f(S obj) {
+    S copy = obj;
+    [&](){ return copy; };
+  }
+
+
+The matcher cxxConstructorDecl(isImplicit(), isCopyConstructor())
+matches the implicit copy constructor of S.
+The matcher lambdaExpr(forEachLambdaCapture(
+    lambdaCapture(isImplicit()))) matches [&](){ return copy; },
+because it implicitly captures copy .
 
@@ -2969,9 +3931,26 @@

Narrowing Matchers

Matches operator expressions (binary or unary) that have any of the
 specified names.
 
-   hasAnyOperatorName("+", "-")
- Is equivalent to
-   anyOf(hasOperatorName("+"), hasOperatorName("-"))
+It provides a compact way of writing if an operator has any of the specified
+names:
+The matcher
+   hasAnyOperatorName("+", "-")
+Is equivalent to
+   hasOperatorName("-"))}
+
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+void bar(bool a, bool b) {
+  a && b;
+ }
+
+The matcher binaryOperator(hasAnyOperatorName("||", "&&"))
+matches a || b and a && b.
+The matcher unaryOperator(hasAnyOperatorName("-", "!"))
+matches !(a || b).
 
@@ -2979,43 +3958,62 @@

Narrowing Matchers

Matches the operator Name of operator expressions and fold expressions
 (binary or unary).
 
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
-  !(a || b)
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
   }
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
 
Matcher<BinaryOperator>isAssignmentOperator
Matches all kinds of assignment operators.
 
-Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+Given
+void foo(int a, int b) {
   if (a == b)
     a += b;
+}
+The matcher binaryOperator(isAssignmentOperator())
+matches a += b.
 
-Example 2: matches s1 = s2
-           (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+Given
   struct S { S& operator=(const S&); };
   void x() { S s1, s2; s1 = s2; }
+
+The matcher cxxOperatorCallExpr(isAssignmentOperator())
+matches s1 = s2.
 
Matcher<BinaryOperator>isComparisonOperator
Matches comparison operators.
 
-Example 1: matches a == b (matcher = binaryOperator(isComparisonOperator()))
+Given
+void foo(int a, int b) {
   if (a == b)
     a += b;
+}
+The matcher binaryOperator(isComparisonOperator())
+matches a == b
 
-Example 2: matches s1 < s2
-           (matcher = cxxOperatorCallExpr(isComparisonOperator()))
+Given
   struct S { bool operator<(const S& other); };
   void x(S s1, S s2) { bool b1 = s1 < s2; }
+
+The matcher cxxOperatorCallExpr(isComparisonOperator())
+matches s1 < s2
 
@@ -3023,16 +4021,25 @@

Narrowing Matchers

Matches private C++ declarations and C++ base specifers that specify private
 inheritance.
 
-Examples:
+Given
   class C {
   public:    int a;
   protected: int b;
-  private:   int c; // fieldDecl(isPrivate()) matches 'c'
+  private:   int c;
   };
 
+The matcher fieldDecl(isPrivate())
+matches c.
+
   struct Base {};
-  struct Derived1 : private Base {}; // matches 'Base'
-  class Derived2 : Base {}; // matches 'Base'
+  struct Derived1 : private Base {}; // Base
+  class Derived2 : Base {}; // Base
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isPrivate()).bind("base")))
+matches Derived1 and Derived2, with
+cxxBaseSpecifier(isPrivate()) matching
+Base.
 
@@ -3040,15 +4047,24 @@

Narrowing Matchers

Matches protected C++ declarations and C++ base specifers that specify
 protected inheritance.
 
-Examples:
+Given
   class C {
   public:    int a;
-  protected: int b; // fieldDecl(isProtected()) matches 'b'
+  protected: int b;
   private:   int c;
   };
 
+The matcher fieldDecl(isProtected())
+matches b.
+
   class Base {};
-  class Derived : protected Base {}; // matches 'Base'
+  class Derived : protected Base {};
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isProtected()).bind("base")))
+matches Derived, with
+cxxBaseSpecifier(isProtected()) matching
+Base.
 
@@ -3056,16 +4072,26 @@

Narrowing Matchers

Matches public C++ declarations and C++ base specifers that specify public
 inheritance.
 
-Examples:
+Given
   class C {
-  public:    int a; // fieldDecl(isPublic()) matches 'a'
+  public:    int a;
   protected: int b;
   private:   int c;
   };
 
+The matcher fieldDecl(isPublic())
+matches a.
+
+Given
   class Base {};
-  class Derived1 : public Base {}; // matches 'Base'
-  struct Derived2 : Base {}; // matches 'Base'
+  class Derived1 : public Base {};
+  struct Derived2 : Base {};
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isPublic()).bind("base")))
+matches Derived1 and Derived2,
+with cxxBaseSpecifier(isPublic()) matching
+public Base and Base.
 
@@ -3073,16 +4099,23 @@

Narrowing Matchers

Matches declarations of virtual methods and C++ base specifers that specify
 virtual inheritance.
 
-Example:
+Given
   class A {
    public:
     virtual void x(); // matches x
   };
 
-Example:
-  class Base {};
-  class DirectlyDerived : virtual Base {}; // matches Base
-  class IndirectlyDerived : DirectlyDerived, Base {}; // matches Base
+The matcher cxxMethodDecl(isVirtual())
+matches x.
+
+Given
+  struct Base {};
+  struct DirectlyDerived : virtual Base {}; // matches Base
+  struct IndirectlyDerived : DirectlyDerived, Base {}; // matches Base
+
+The matcher
+cxxRecordDecl(hasDirectBase(cxxBaseSpecifier(isVirtual())))
+matches DirectlyDerived.
 
 Usable as: Matcher<CXXMethodDecl>, Matcher<CXXBaseSpecifier>
 
@@ -3096,22 +4129,27 @@

Narrowing Matchers

Matches literals that are equal to the given value of type ValueT.
 
 Given
+void f(char, bool, double, int);
+void foo() {
   f('false, 3.14, 42);
-characterLiteral(equals(0))
-  matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
-  match false
-floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
-  match 3.14
-integerLiteral(equals(42))
-  matches 42
+}
+
+The matcher characterLiteral(equals(0U)) matches 'The matchers cxxBoolLiteral(equals(false)) and
+cxxBoolLiteral(equals(0)) match false.
+The matcher floatLiteral(equals(3.14)) matches 3.14.
+The matcher integerLiteral(equals(42)) matches 42.
 
 Note that you cannot directly match a negative numeric literal because the
 minus sign is not part of the literal: It is a unary operator whose operand
 is the positive numeric literal. Instead, you must use a unaryOperator()
 matcher to match the minus sign:
 
-unaryOperator(hasOperatorName("-"),
-              hasUnaryOperand(integerLiteral(equals(13))))
+Given
+  int val = -1;
+
+The matcher unaryOperator(hasOperatorName("-"),
+              hasUnaryOperand(integerLiteral(equals(1))))
+matches -1.
 
 Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteralExpr>,
            Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
@@ -3130,14 +4168,15 @@ 

Narrowing Matchers

Matches a C++ catch statement that has a catch-all handler.
 
 Given
-  try {
-    // ...
-  } catch (int) {
-    // ...
-  } catch (...) {
-    // ...
+  void foo() {
+    try {}
+    catch (int) {}
+    catch (...) {}
   }
-cxxCatchStmt(isCatchAll()) matches catch(...) but not catch(int).
+
+The matcher cxxCatchStmt(isCatchAll())
+matches catch (...) {}
+but does not match catch(int)
 
@@ -3145,12 +4184,15 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has at least
 the specified number of arguments (including absent default arguments).
 
-Example matches f(0, 0) and g(0, 0, 0)
-(matcher = callExpr(argumentCountAtLeast(2)))
+Given
   void f(int x, int y);
   void g(int x, int y, int z);
-  f(0, 0);
-  g(0, 0, 0);
+  void foo() {
+    f(0, 0);
+    g(0, 0, 0);
+  }
+The matcher callExpr(argumentCountAtLeast(2))
+matches f(0, 0) and g(0, 0, 0)
 
@@ -3158,14 +4200,39 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has
 a specific number of arguments (including absent default arguments).
 
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+Given
   void f(int x, int y);
-  f(0, 0);
+  void foo() {
+    f(0, 0);
+  }
+The matcher callExpr(argumentCountIs(2))
+matches f(0, 0)
 
Matcher<CXXConstructExpr>isListInitialization
Matches a constructor call expression which uses list initialization.
+
+Given
+  namespace std {
+    template <typename T>
+    class initializer_list {
+      const T* begin;
+      const T* end;
+    };
+  }
+  template <typename T> class vector {
+    public: vector(std::initializer_list<T>) {}
+  };
+
+  vector<int> a({ 1, 2, 3 });
+  vector<int> b = { 4, 5 };
+  int c[] = { 6, 7 };
+  struct pair { int x; int y; };
+  pair d = { 8, 9 };
+
+The matcher cxxConstructExpr(isListInitialization())
+matches { 4, 5 }.
 
@@ -3175,11 +4242,15 @@

Narrowing Matchers

Given void foo() { - struct point { double x; double y; }; - point pt[2] = { { 1.0, 2.0 } }; + struct Foo { + double x; + }; + auto Val = Foo(); } -initListExpr(has(cxxConstructExpr(requiresZeroInitialization())) -will match the implicit array filler for pt[1]. + +The matcher +cxxConstructExpr(requiresZeroInitialization()) +matches Foo() because the x member has to be zero initialized.
@@ -3192,7 +4263,10 @@

Narrowing Matchers

S(const S &); // #2 S(S &&); // #3 }; -cxxConstructorDecl(isCopyConstructor()) will match #2, but not #1 or #3. + +The matcher cxxConstructorDecl(isCopyConstructor()) +matches S(const S &), +but does not match S() or S(S &&). @@ -3205,7 +4279,10 @@

Narrowing Matchers

S(const S &); // #2 S(S &&); // #3 }; -cxxConstructorDecl(isDefaultConstructor()) will match #1, but not #2 or #3. + +The matcher cxxConstructorDecl(isDefaultConstructor()) +matches S() +but does not match S(const S &); or S(S &&);. @@ -3219,8 +4296,10 @@

Narrowing Matchers

S(S &&) : S() {} // #3 }; S::S() : S(0) {} // #4 -cxxConstructorDecl(isDelegatingConstructor()) will match #3 and #4, but not -#1 or #2. + +The matcher cxxConstructorDecl(isDelegatingConstructor()) +matches S(S &&) : S() {} and S::S() : S(0) {}, +but does not match S() or S(int). @@ -3236,15 +4315,27 @@

Narrowing Matchers

explicit S(double); // #2 operator int(); // #3 explicit operator bool(); // #4 - explicit(false) S(bool) // # 7 - explicit(true) S(char) // # 8 - explicit(b) S(S) // # 9 + explicit(false) S(bool); // # 7 + explicit(true) S(char); // # 8 + explicit(b) S(float); // # 9 }; - S(int) -> S<true> // #5 - explicit S(double) -> S<false> // #6 -cxxConstructorDecl(isExplicit()) will match #2 and #8, but not #1, #7 or #9. -cxxConversionDecl(isExplicit()) will match #4, but not #3. -cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5. + S(int) -> S<true>; // #5 + explicit S(double) -> S<false>; // #6 + +The matcher cxxConstructorDecl(isExplicit()) +matches explicit S(double) +and explicit(true) S(char) +but does not match S(int);, explicit(false) S(bool); or +explicit(b) S(float) +The matcher cxxConversionDecl(isExplicit()) +matches explicit operator bool() +but does not match operator int(). +The matcher cxxDeductionGuideDecl(isExplicit()) +matches the deduction guide explicit S(double) -> S<false>, +the implicit copy deduction candiate +auto (double) -> S<b> and +the implicitly generated deduction guide for explicit(true) S(char), +but does not match S(int) -> S<true>. @@ -3261,7 +4352,10 @@

Narrowing Matchers

S(const S &); // #2 S(S &&); // #3 }; -cxxConstructorDecl(isMoveConstructor()) will match #3, but not #1 or #2. + +The matcher cxxConstructorDecl(isMoveConstructor()) +matches S(S &&) +but does not match S(); or S(S &&); @@ -3277,15 +4371,27 @@

Narrowing Matchers

explicit S(double); // #2 operator int(); // #3 explicit operator bool(); // #4 - explicit(false) S(bool) // # 7 - explicit(true) S(char) // # 8 - explicit(b) S(S) // # 9 + explicit(false) S(bool); // # 7 + explicit(true) S(char); // # 8 + explicit(b) S(float); // # 9 }; - S(int) -> S<true> // #5 - explicit S(double) -> S<false> // #6 -cxxConstructorDecl(isExplicit()) will match #2 and #8, but not #1, #7 or #9. -cxxConversionDecl(isExplicit()) will match #4, but not #3. -cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5. + S(int) -> S<true>; // #5 + explicit S(double) -> S<false>; // #6 + +The matcher cxxConstructorDecl(isExplicit()) +matches explicit S(double) +and explicit(true) S(char) +but does not match S(int);, explicit(false) S(bool); or +explicit(b) S(float) +The matcher cxxConversionDecl(isExplicit()) +matches explicit operator bool() +but does not match operator int(). +The matcher cxxDeductionGuideDecl(isExplicit()) +matches the deduction guide explicit S(double) -> S<false>, +the implicit copy deduction candiate +auto (double) -> S<b> and +the implicitly generated deduction guide for explicit(true) S(char), +but does not match S(int) -> S<true>. @@ -3302,8 +4408,12 @@

Narrowing Matchers

struct E : B { E() : B() {} }; + +The matcher cxxConstructorDecl(hasAnyConstructorInitializer(isBaseInitializer())) - will match E(), but not match D(int). +matches E() : B() {} and D(int i) : I(i) {}. +The constructor of D is matched, because it implicitly has a constructor +initializer for B . @@ -3320,8 +4430,11 @@

Narrowing Matchers

struct E : B { E() : B() {} }; + +The matcher cxxConstructorDecl(hasAnyConstructorInitializer(isMemberInitializer())) - will match D(int), but not match E(). + will match D(int i) : I(i) {}, but not match E() : B() + {}. @@ -3330,13 +4443,16 @@

Narrowing Matchers

code (as opposed to implicitly added by the compiler). Given + struct Bar { explicit Bar(const char*); }; struct Foo { Foo() { } Foo(int) : foo_("A") { } - string foo_; + Bar foo_{""}; }; -cxxConstructorDecl(hasAnyConstructorInitializer(isWritten())) - will match Foo(int), but not Foo() + +The matcher +cxxConstructorDecl(hasAnyConstructorInitializer(isWritten())) will +match Foo(int) : foo_("A") { }, but not Foo() { } @@ -3352,15 +4468,27 @@

Narrowing Matchers

explicit S(double); // #2 operator int(); // #3 explicit operator bool(); // #4 - explicit(false) S(bool) // # 7 - explicit(true) S(char) // # 8 - explicit(b) S(S) // # 9 + explicit(false) S(bool); // # 7 + explicit(true) S(char); // # 8 + explicit(b) S(float); // # 9 }; - S(int) -> S<true> // #5 - explicit S(double) -> S<false> // #6 -cxxConstructorDecl(isExplicit()) will match #2 and #8, but not #1, #7 or #9. -cxxConversionDecl(isExplicit()) will match #4, but not #3. -cxxDeductionGuideDecl(isExplicit()) will match #6, but not #5. + S(int) -> S<true>; // #5 + explicit S(double) -> S<false>; // #6 + +The matcher cxxConstructorDecl(isExplicit()) +matches explicit S(double) +and explicit(true) S(char) +but does not match S(int);, explicit(false) S(bool); or +explicit(b) S(float) +The matcher cxxConversionDecl(isExplicit()) +matches explicit operator bool() +but does not match operator int(). +The matcher cxxDeductionGuideDecl(isExplicit()) +matches the deduction guide explicit S(double) -> S<false>, +the implicit copy deduction candiate +auto (double) -> S<b> and +the implicitly generated deduction guide for explicit(true) S(char), +but does not match S(int) -> S<true>. @@ -3382,7 +4510,9 @@

Narrowing Matchers

S<T> s; s.mem(); } -cxxDependentScopeMemberExpr(hasMemberName("mem")) matches `s.mem()` + +The matcher cxxDependentScopeMemberExpr(hasMemberName("mem")) +matches s.mem. @@ -3401,14 +4531,25 @@

Narrowing Matchers

}; template <class T> class Z { - void x() { this->m; } + void x() { + this->m; + this->t; + this->t->m; + } + int m; + T* t; }; -memberExpr(isArrow()) - matches this->x, x, y.x, a, this->b -cxxDependentScopeMemberExpr(isArrow()) - matches this->m -unresolvedMemberExpr(isArrow()) - matches this->f<T>, f<T> + +The matcher memberExpr(isArrow()) +matches this->x, x, a, +this->b, this->m and two times this->t, +once for the standalone member expression, and once for the member +expression that later accesses m . +Additionally, it does not match this->t->t. +The matcher cxxDependentScopeMemberExpr(isArrow()) +matches this->t->m, but not this->m or this->t. +The matcher unresolvedMemberExpr(isArrow()) +matches this->f<T>, f<T> @@ -3432,19 +4573,20 @@

Narrowing Matchers

S<T> s; s.mem(); } -The matcher -@code -cxxDependentScopeMemberExpr( - hasObjectExpression(declRefExpr(hasType(templateSpecializationType( + +The matcher cxxDependentScopeMemberExpr( + hasObjectExpression(declRefExpr(hasType( + elaboratedType(namesType(templateSpecializationType( hasDeclaration(classTemplateDecl(has(cxxRecordDecl(has( cxxMethodDecl(hasName("mem")).bind("templMem") ))))) - )))), + ))) + ))), memberHasSameNameAsBoundNode("templMem") - ) -@endcode -first matches and binds the @c mem member of the @c S template, then -compares its name to the usage in @c s.mem() in the @c x function template +) +matches s.mem, with the inner matcher +cxxMethodDecl(hasName("mem")) matching +void mem() of the S template. @@ -3452,23 +4594,29 @@

Narrowing Matchers

Matches the operator Name of operator expressions and fold expressions
 (binary or unary).
 
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
-  !(a || b)
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
   }
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
 
Matcher<CXXFoldExpr>isBinaryFold
Matches binary fold expressions, i.e. fold expressions with an initializer.
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(isBinaryFold()))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
@@ -3478,14 +4626,17 @@ 

Narrowing Matchers

auto multiply(Args... args) { return (args * ...); } + + +The matcher cxxFoldExpr(isBinaryFold()) +matches (0 + ... + args).
Matcher<CXXFoldExpr>isLeftFold
Matches left-folding fold expressions.
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(isLeftFold()))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
@@ -3495,14 +4646,17 @@ 

Narrowing Matchers

auto multiply(Args... args) { return (args * ... * 1); } + + +The matcher cxxFoldExpr(isLeftFold()) +matches (0 + ... + args).
Matcher<CXXFoldExpr>isRightFold
Matches right-folding fold expressions.
 
-Example matches `(args * ... * 1)`
-    (matcher = cxxFoldExpr(isRightFold()))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
@@ -3512,6 +4666,10 @@ 

Narrowing Matchers

auto multiply(Args... args) { return (args * ... * 1); } + + +The matcher cxxFoldExpr(isRightFold()) +matches (args * ... * 1).
@@ -3519,8 +4677,7 @@

Narrowing Matchers

Matches unary fold expressions, i.e. fold expressions without an
 initializer.
 
-Example matches `(args * ...)`
-    (matcher = cxxFoldExpr(isUnaryFold()))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
@@ -3530,6 +4687,10 @@ 

Narrowing Matchers

auto multiply(Args... args) { return (args * ...); } + + +The matcher cxxFoldExpr(isUnaryFold()) +matches (args * ...), but not (0 + ... + args).
@@ -3542,7 +4703,9 @@

Narrowing Matchers

void bar(); }; -cxxMethodDecl(isConst()) matches A::foo() but not A::bar() + +The matcher cxxMethodDecl(isConst()) +matches foo but not bar @@ -3556,8 +4719,10 @@

Narrowing Matchers

A &operator=(A &&); }; -cxxMethodDecl(isCopyAssignmentOperator()) matches the first method but not -the second one. + +The matcher cxxMethodDecl(isCopyAssignmentOperator()) +matches A &operator=(const A &) +but does not match A &operator=(A &&) @@ -3573,15 +4738,19 @@

Narrowing Matchers

int operator+(int); }; -cxxMethodDecl(isExplicitObjectMemberFunction()) matches the first two -methods but not the last two. + +The matcher cxxMethodDecl(isExplicitObjectMemberFunction()) +matches int operator-(this A, int) and +void fun(this A &&self), +but not static int operator()(int) or +int operator+(int). Matcher<CXXMethodDecl>isFinal
Matches if the given method or class declaration is final.
 
-Given:
+Given
   class A final {};
 
   struct B {
@@ -3591,7 +4760,13 @@ 

Narrowing Matchers

struct C : B { void f() final; }; -matches A and C::f, but not B, C, or B::f + +The matcher cxxRecordDecl(isFinal()) +matches A, +but does not match B or C. +The matcher cxxMethodDecl(isFinal()) +matches void f() final in C , +but does not match virtual void f() in B .
@@ -3605,8 +4780,10 @@

Narrowing Matchers

A &operator=(A &&); }; -cxxMethodDecl(isMoveAssignmentOperator()) matches the second method but not -the first one. + +The matcher cxxMethodDecl(isMoveAssignmentOperator()) +matches A &operator=(A &&) +but does not match A &operator=(const A &) @@ -3620,9 +4797,11 @@

Narrowing Matchers

}; class B : public A { public: - virtual void x(); + void x() override; }; - matches B::x + +The matcher cxxMethodDecl(isOverride()) + matches void x() override @@ -3634,7 +4813,9 @@

Narrowing Matchers

public: virtual void x() = 0; }; - matches A::x + +The matcher cxxMethodDecl(isPure()) +matches virtual void x() = 0 @@ -3647,7 +4828,10 @@

Narrowing Matchers

S(const S &) = default; // #2 S(S &&) = delete; // #3 }; -cxxConstructorDecl(isUserProvided()) will match #1, but not #2 or #3. + +The matcher cxxConstructorDecl(isUserProvided()) +will match S(), but not S &) = default} or +&&) = delete} @@ -3655,16 +4839,23 @@

Narrowing Matchers

Matches declarations of virtual methods and C++ base specifers that specify
 virtual inheritance.
 
-Example:
+Given
   class A {
    public:
     virtual void x(); // matches x
   };
 
-Example:
-  class Base {};
-  class DirectlyDerived : virtual Base {}; // matches Base
-  class IndirectlyDerived : DirectlyDerived, Base {}; // matches Base
+The matcher cxxMethodDecl(isVirtual())
+matches x.
+
+Given
+  struct Base {};
+  struct DirectlyDerived : virtual Base {}; // matches Base
+  struct IndirectlyDerived : DirectlyDerived, Base {}; // matches Base
+
+The matcher
+cxxRecordDecl(hasDirectBase(cxxBaseSpecifier(isVirtual())))
+matches DirectlyDerived.
 
 Usable as: Matcher<CXXMethodDecl>, Matcher<CXXBaseSpecifier>
 
@@ -3682,17 +4873,22 @@

Narrowing Matchers

public: void x(); }; - matches A::x but not B::x + +The matcher cxxMethodDecl(isVirtualAsWritten()) +matches virtual void x() of A, +but does not match x()} of B . Matcher<CXXNewExpr>isArray
Matches array new expressions.
 
-Given:
+Given
+  struct MyClass { int x; };
   MyClass *p1 = new MyClass[10];
-cxxNewExpr(isArray())
-  matches the expression 'new MyClass[10]'.
+
+The matcher cxxNewExpr(isArray())
+matches new MyClass[10].
 
@@ -3700,9 +4896,26 @@

Narrowing Matchers

Matches operator expressions (binary or unary) that have any of the
 specified names.
 
+It provides a compact way of writing if an operator has any of the specified
+names:
+The matcher
    hasAnyOperatorName("+", "-")
- Is equivalent to
-   anyOf(hasOperatorName("+"), hasOperatorName("-"))
+Is equivalent to
+   hasOperatorName("-"))}
+
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+void bar(bool a, bool b) {
+  a && b;
+ }
+
+The matcher binaryOperator(hasAnyOperatorName("||", "&&"))
+matches a || b and a && b.
+The matcher unaryOperator(hasAnyOperatorName("-", "!"))
+matches !(a || b).
 
@@ -3713,6 +4926,30 @@

Narrowing Matchers

"operator" prefix: e.g. "<<". hasAnyOverloadedOperatorName("+", "-") + +Given + struct Point { double x; double y; }; + Point operator+(const Point&, const Point&); + Point operator-(const Point&, const Point&); + + Point sub(Point a, Point b) { + return b - a; + } + + +The matcher functionDecl(hasAnyOverloadedOperatorName("+", "-")), +which is equivalent to +functionDecl(anyOf(hasAnyOverloadedOperatorName("+"), +hasOverloadedOperatorName("-"))), +matches Point operator+(const Point&, const Point&) and +Point operator-(const Point&, const Point&). +The matcher +cxxOperatorCallExpr(hasAnyOverloadedOperatorName("+", "-")), +which is equivalent to +cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("+"), +hasOverloadedOperatorName("-"))), +matches b - a. + Is equivalent to anyOf(hasOverloadedOperatorName("+"), hasOverloadedOperatorName("-")) @@ -3722,15 +4959,22 @@

Narrowing Matchers

Matches the operator Name of operator expressions and fold expressions
 (binary or unary).
 
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
-  !(a || b)
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
   }
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
 
@@ -3740,16 +4984,19 @@

Narrowing Matchers

Matches overloaded operator names specified in strings without the "operator" prefix: e.g. "<<". -Given: - class A { int operator*(); }; +Given + struct A { int operator*(); }; const A &operator<<(const A &a, const A &b); - A a; - a << a; // <-- This matches + void f(A a) { + a << a; // <-- This matches + } -cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))) matches the -specified line and + +The matcher cxxOperatorCallExpr(hasOverloadedOperatorName("<<")) +matches a << a. +The matcher cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*"))) -matches the declaration of A. +matches struct A { int operator*(); }. Usable as: Matcher<CXXOperatorCallExpr>, Matcher<FunctionDecl> @@ -3758,47 +5005,104 @@

Narrowing Matchers

Matcher<CXXOperatorCallExpr>isAssignmentOperator
Matches all kinds of assignment operators.
 
-Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+Given
+void foo(int a, int b) {
   if (a == b)
     a += b;
+}
+The matcher binaryOperator(isAssignmentOperator())
+matches a += b.
 
-Example 2: matches s1 = s2
-           (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+Given
   struct S { S& operator=(const S&); };
   void x() { S s1, s2; s1 = s2; }
+
+The matcher cxxOperatorCallExpr(isAssignmentOperator())
+matches s1 = s2.
 
Matcher<CXXOperatorCallExpr>isComparisonOperator
Matches comparison operators.
 
-Example 1: matches a == b (matcher = binaryOperator(isComparisonOperator()))
+Given
+void foo(int a, int b) {
   if (a == b)
     a += b;
+}
+The matcher binaryOperator(isComparisonOperator())
+matches a == b
 
-Example 2: matches s1 < s2
-           (matcher = cxxOperatorCallExpr(isComparisonOperator()))
+Given
   struct S { bool operator<(const S& other); };
   void x(S s1, S s2) { bool b1 = s1 < s2; }
+
+The matcher cxxOperatorCallExpr(isComparisonOperator())
+matches s1 < s2
 
Matcher<CXXRecordDecl>hasDefinition
Matches a class declaration that is defined.
 
-Example matches x (matcher = cxxRecordDecl(hasDefinition()))
+Given
 class x {};
 class y;
+
+The matcher cxxRecordDecl(hasDefinition())
+matches class x {}
 
Matcher<CXXRecordDecl>isDerivedFromstd::string BaseName
Overloaded method as shortcut for isDerivedFrom(hasName(...)).
+
+Matches C++ classes that are directly or indirectly derived from a class
+matching Base, or Objective-C classes that directly or indirectly
+subclass a class matching Base.
+
+Note that a class is not considered to be derived from itself.
+
+Example matches Y, Z, C (Base == hasName("X"))
+  class X {};
+  class Y : public X {};  // directly derived
+  class Z : public Y {};  // indirectly derived
+  typedef X A;
+  typedef A B;
+  class C : public B {};  // derived from a typedef of X
+
+  class Foo {};
+  typedef Foo Alias;
+  class Bar : public Alias {};  // derived from Alias, which is a
+                                // typedef of Foo
+
+
+The matcher cxxRecordDecl(isDerivedFrom("X"))
+matches Y, Z and C.
+The matcher cxxRecordDecl(isDerivedFrom("Foo"))
+matches Bar.
+
+In the following example, Bar matches isDerivedFrom(hasName("NSObject"))
+  @interface NSObject @end
+  @interface Bar : NSObject @end
+
+
+Usable as: Matcher<CXXRecordDecl>, Matcher<ObjCInterfaceDecl>
 
Matcher<CXXRecordDecl>isDirectlyDerivedFromstd::string BaseName
Overloaded method as shortcut for isDirectlyDerivedFrom(hasName(...)).
+
+Given
+  struct Base {};
+  struct DirectlyDerived : public Base {};
+  struct IndirectlyDerived : public DirectlyDerived {};
+
+
+The matcher cxxRecordDecl(isDirectlyDerivedFrom("Base"))
+matches DirectlyDerived, but not
+IndirectlyDerived.
 
@@ -3809,8 +5113,9 @@

Narrowing Matchers

Given template<typename T> void A(T t) { } template<> void A(int N) { } -functionDecl(isExplicitTemplateSpecialization()) - matches the specialization A<int>(). + +The matcher functionDecl(isExplicitTemplateSpecialization()) + matches the specialization template<> void A(int N) { }. Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> @@ -3819,7 +5124,7 @@

Narrowing Matchers

Matcher<CXXRecordDecl>isFinal
Matches if the given method or class declaration is final.
 
-Given:
+Given
   class A final {};
 
   struct B {
@@ -3829,24 +5134,46 @@ 

Narrowing Matchers

struct C : B { void f() final; }; -matches A and C::f, but not B, C, or B::f + +The matcher cxxRecordDecl(isFinal()) +matches A, +but does not match B or C. +The matcher cxxMethodDecl(isFinal()) +matches void f() final in C , +but does not match virtual void f() in B .
Matcher<CXXRecordDecl>isLambda
Matches the generated class of lambda expressions.
 
-Given:
+Given
   auto x = []{};
 
-cxxRecordDecl(isLambda()) matches the implicit class declaration of
-decltype(x)
+
+The matcher varDecl(hasType(cxxRecordDecl(isLambda())))
+matches auto x = []{}.
 
Matcher<CXXRecordDecl>isSameOrDerivedFromstd::string BaseName -
Overloaded method as shortcut for
+
Similar to isDerivedFrom(), but also matches classes that directly
+match Base.
+Overloaded method as shortcut for
 isSameOrDerivedFrom(hasName(...)).
+
+Given
+  class X {};
+  class Y : public X {};  // directly derived
+  class Z : public Y {};  // indirectly derived
+  typedef X A;
+  typedef A B;
+  class C : public B {};  // derived from a typedef of X
+
+The matcher
+cxxRecordDecl(isSameOrDerivedFrom("X"), isDefinition())
+matches class X {}, class Y : public X {},
+class Z : public Y {} and class C : public B {}.
 
@@ -3855,18 +5182,36 @@

Narrowing Matchers

member variable template instantiations. Given - template <typename T> class X {}; class A {}; X<A> x; -or - template <typename T> class X {}; class A {}; template class X<A>; -or - template <typename T> class X {}; class A {}; extern template class X<A>; -cxxRecordDecl(hasName("::X"), isTemplateInstantiation()) - matches the template instantiation of X<A>. + template <typename T> class X {}; + class A {}; + X<A> x; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches class X<class A>. + template <typename T> class X {}; + class A {}; + template class X<A>; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches template class X<A> + template <typename T> class X {}; + class A {}; + extern template class X<A>; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches extern template class X<A> But given - template <typename T> class X {}; class A {}; - template <> class X<A> {}; X<A> x; -cxxRecordDecl(hasName("::X"), isTemplateInstantiation()) + template <typename T> class X {}; + class A {}; + template <> class X<A> {}; + X<A> x; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) does not match, as X<A> is an explicit template specialization. Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> @@ -3877,9 +5222,26 @@

Narrowing Matchers

Matches operator expressions (binary or unary) that have any of the
 specified names.
 
+It provides a compact way of writing if an operator has any of the specified
+names:
+The matcher
    hasAnyOperatorName("+", "-")
- Is equivalent to
-   anyOf(hasOperatorName("+"), hasOperatorName("-"))
+Is equivalent to
+   hasOperatorName("-"))}
+
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+void bar(bool a, bool b) {
+  a && b;
+ }
+
+The matcher binaryOperator(hasAnyOperatorName("||", "&&"))
+matches a || b and a && b.
+The matcher unaryOperator(hasAnyOperatorName("-", "!"))
+matches !(a || b).
 
@@ -3887,43 +5249,62 @@

Narrowing Matchers

Matches the operator Name of operator expressions and fold expressions
 (binary or unary).
 
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
-  !(a || b)
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
   }
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
 
Matcher<CXXRewrittenBinaryOperator>isAssignmentOperator
Matches all kinds of assignment operators.
 
-Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+Given
+void foo(int a, int b) {
   if (a == b)
     a += b;
+}
+The matcher binaryOperator(isAssignmentOperator())
+matches a += b.
 
-Example 2: matches s1 = s2
-           (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+Given
   struct S { S& operator=(const S&); };
   void x() { S s1, s2; s1 = s2; }
+
+The matcher cxxOperatorCallExpr(isAssignmentOperator())
+matches s1 = s2.
 
Matcher<CXXRewrittenBinaryOperator>isComparisonOperator
Matches comparison operators.
 
-Example 1: matches a == b (matcher = binaryOperator(isComparisonOperator()))
+Given
+void foo(int a, int b) {
   if (a == b)
     a += b;
+}
+The matcher binaryOperator(isComparisonOperator())
+matches a == b
 
-Example 2: matches s1 < s2
-           (matcher = cxxOperatorCallExpr(isComparisonOperator()))
+Given
   struct S { bool operator<(const S& other); };
   void x(S s1, S s2) { bool b1 = s1 < s2; }
+
+The matcher cxxOperatorCallExpr(isComparisonOperator())
+matches s1 < s2
 
@@ -3931,12 +5312,15 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has at least
 the specified number of arguments (including absent default arguments).
 
-Example matches f(0, 0) and g(0, 0, 0)
-(matcher = callExpr(argumentCountAtLeast(2)))
+Given
   void f(int x, int y);
   void g(int x, int y, int z);
-  f(0, 0);
-  g(0, 0, 0);
+  void foo() {
+    f(0, 0);
+    g(0, 0, 0);
+  }
+The matcher callExpr(argumentCountAtLeast(2))
+matches f(0, 0) and g(0, 0, 0)
 
@@ -3944,9 +5328,13 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has
 a specific number of arguments (including absent default arguments).
 
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+Given
   void f(int x, int y);
-  f(0, 0);
+  void foo() {
+    f(0, 0);
+  }
+The matcher callExpr(argumentCountIs(2))
+matches f(0, 0)
 
@@ -3954,12 +5342,15 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has at least
 the specified number of arguments (including absent default arguments).
 
-Example matches f(0, 0) and g(0, 0, 0)
-(matcher = callExpr(argumentCountAtLeast(2)))
+Given
   void f(int x, int y);
   void g(int x, int y, int z);
-  f(0, 0);
-  g(0, 0, 0);
+  void foo() {
+    f(0, 0);
+    g(0, 0, 0);
+  }
+The matcher callExpr(argumentCountAtLeast(2))
+matches f(0, 0) and g(0, 0, 0)
 
@@ -3967,16 +5358,20 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has
 a specific number of arguments (including absent default arguments).
 
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+Given
   void f(int x, int y);
-  f(0, 0);
+  void foo() {
+    f(0, 0);
+  }
+The matcher callExpr(argumentCountIs(2))
+matches f(0, 0)
 
Matcher<CallExpr>usesADL
Matches call expressions which were resolved using ADL.
 
-Example matches y(x) but not y(42) or NS::y(x).
+Given
   namespace NS {
     struct X {};
     void y(X);
@@ -3992,15 +5387,20 @@ 

Narrowing Matchers

using NS::y; y(x); // Found by both unqualified lookup and ADL, doesn't match } + + +The matcher callExpr(usesADL()) +matches y(x), but not y(42) or NS::y(x).
Matcher<CastExpr>hasCastKindCastKind Kind
Matches casts that has a given cast kind.
 
-Example: matches the implicit cast around 0
-(matcher = castExpr(hasCastKind(CK_NullToPointer)))
+Given
   int *p = 0;
+The matcher castExpr(hasCastKind(CK_NullToPointer))
+matches the implicit cast around 0
 
 If the matcher is use from clang-query, CastKind parameter
 should be passed as a quoted string. e.g., hasCastKind("CK_NullToPointer").
@@ -4015,22 +5415,27 @@ 

Narrowing Matchers

Matches literals that are equal to the given value of type ValueT.
 
 Given
+void f(char, bool, double, int);
+void foo() {
   f('false, 3.14, 42);
-characterLiteral(equals(0))
-  matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
-  match false
-floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
-  match 3.14
-integerLiteral(equals(42))
-  matches 42
+}
+
+The matcher characterLiteral(equals(0U)) matches 'The matchers cxxBoolLiteral(equals(false)) and
+cxxBoolLiteral(equals(0)) match false.
+The matcher floatLiteral(equals(3.14)) matches 3.14.
+The matcher integerLiteral(equals(42)) matches 42.
 
 Note that you cannot directly match a negative numeric literal because the
 minus sign is not part of the literal: It is a unary operator whose operand
 is the positive numeric literal. Instead, you must use a unaryOperator()
 matcher to match the minus sign:
 
-unaryOperator(hasOperatorName("-"),
-              hasUnaryOperand(integerLiteral(equals(13))))
+Given
+  int val = -1;
+
+The matcher unaryOperator(hasOperatorName("-"),
+              hasUnaryOperand(integerLiteral(equals(1))))
+matches -1.
 
 Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteralExpr>,
            Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
@@ -4051,8 +5456,10 @@ 

Narrowing Matchers

Given template<typename T> struct C {}; C<int> c; + +The matcher classTemplateSpecializationDecl(templateArgumentCountIs(1)) - matches C<int>. +matches struct C<int>.
@@ -4061,9 +5468,11 @@

Narrowing Matchers

child statements. Example: Given +void foo() { { for (;;) {} } -compoundStmt(statementCountIs(0))) - matches '{}' +} +The matcher compoundStmt(statementCountIs(0)) +{} but does not match the outer compound statement.
@@ -4078,10 +5487,11 @@

Narrowing Matchers

char *s = "abcd"; wchar_t *ws = L"abcd"; char *w = "a"; -constantArrayType(hasSize(42)) - matches "int a[42]" and "int b[2 * 21]" -stringLiteral(hasSize(4)) - matches "abcd", L"abcd" + +The matcher constantArrayType(hasSize(42)) +matches int[42] twice. +The matcher stringLiteral(hasSize(4)) +matches "abcd" and L"abcd".
@@ -4089,12 +5499,15 @@

Narrowing Matchers

Matches declaration statements that contain a specific number of
 declarations.
 
-Example: Given
-  int a, b;
-  int c;
-  int d = 2, e;
-declCountIs(2)
-  matches 'int a, b;' and 'int d = 2, e;', but not 'int c;'.
+Given
+  void foo() {
+    int a, b;
+    int c;
+    int d = 2, e;
+  }
+The matcher declStmt(declCountIs(2))
+matches int a, b; and int d = 2, e;,
+but does not match int c;
 
@@ -4105,10 +5518,11 @@

Narrowing Matchers

Given class X { int a; int b; }; -cxxRecordDecl( + +The matcher cxxRecordDecl( has(fieldDecl(hasName("a"), hasType(type().bind("t")))), has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t")))))) - matches the class X, as a and b have the same type. + matches X, as a and b have the same type. Note that when multiple matches are involved via forEach* matchers, equalsBoundNodes acts as a filter. @@ -4121,7 +5535,7 @@

Narrowing Matchers

-Matcher<Decl>equalsNodeconst Decl* Other +Matcher<Decl>equalsNodeconst Decl * Other
Matches if a node equals another node.
 
 Decl has pointer identity in the AST.
@@ -4132,10 +5546,13 @@ 

Narrowing Matchers

Matches declaration that has a given attribute.
 
 Given
-  __attribute__((device)) void f() { ... }
-decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of
-f. If the matcher is used from clang-query, attr::Kind parameter should be
-passed as a quoted string. e.g., hasAttr("attr::CUDADevice").
+  __attribute__((device)) void f() {}
+
+The matcher decl(hasAttr(clang::attr::CUDADevice))
+matches f.
+If the matcher is used from clang-query, attr::Kind
+parameter should be passed as a quoted string. e.g.,
+hasAttr("attr::CUDADevice").
 
@@ -4144,6 +5561,15 @@

Narrowing Matchers

Does not match if only part of the statement is expanded from that macro or if different parts of the statement are expanded from different appearances of the macro. + +Given + #define A 0 + #define B A + int c = B; + +The matcher integerLiteral(isExpandedFromMacro("A")) +matches the literal expanded at the initializer B of the variable +c .
@@ -4151,12 +5577,25 @@

Narrowing Matchers

Matches AST nodes that were expanded within files whose name is
 partially matching a given regex.
 
-Example matches Y but not X
-    (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
-  #include "ASTMatcher.h"
-  class X {};
-ASTMatcher.h:
-  class Y {};
+Given the headers Y.h
+  #pragma once
+  typedef int my_y_int;
+and X.h
+  #pragma once
+  typedef int my_x_int;
+and the source code
+  #include "X.h"
+  #include "Y.h"
+  typedef int my_main_file_int;
+  my_main_file_int a = 0;
+  my_x_int b = 1;
+  my_y_int c = 2;
+
+The matcher
+typedefDecl(isExpansionInFileMatching("Y.h"))
+matches typedef int my_y_int,
+but does not match typedef int my_main_file_int or
+typedef int my_x_int.
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -4169,12 +5608,18 @@ 

Narrowing Matchers

Matcher<Decl>isExpansionInMainFile
Matches AST nodes that were expanded within the main-file.
 
-Example matches X but not Y
-  (matcher = cxxRecordDecl(isExpansionInMainFile())
-  #include <Y.h>
-  class X {};
-Y.h:
-  class Y {};
+Given the header Y.h
+  #pragma once
+  typedef int my_header_int;
+and the source file
+  #include "Y.h"
+  typedef int my_main_file_int;
+  my_main_file_int a = 0;
+  my_header_int b = 1;
+
+The matcher typedefDecl(isExpansionInMainFile())
+matches typedef int my_main_file_int,
+but does not match typedef int my_header_int.
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -4183,12 +5628,17 @@

Narrowing Matchers

Matcher<Decl>isExpansionInSystemHeader
Matches AST nodes that were expanded within system-header-files.
 
-Example matches Y but not X
-    (matcher = cxxRecordDecl(isExpansionInSystemHeader())
+Given the header SystemHeader.h
+  #pragma once
+  int header();
+and the source code
   #include <SystemHeader.h>
-  class X {};
-SystemHeader.h:
-  class Y {};
+  static int main_file();
+
+
+The matcher functionDecl(isExpansionInSystemHeader())
+matches int header(),
+but does not match static int main_file().
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -4197,6 +5647,20 @@

Narrowing Matchers

Matcher<Decl>isImplicit
Matches an entity that has been implicitly added by the compiler (e.g.
 implicit default/copy constructors).
+
+Given
+  struct S {};
+  void f(S obj) {
+    S copy = obj;
+    [&](){ return copy; };
+  }
+
+
+The matcher cxxConstructorDecl(isImplicit(), isCopyConstructor())
+matches the implicit copy constructor of S.
+The matcher lambdaExpr(forEachLambdaCapture(
+    lambdaCapture(isImplicit()))) matches [&](){ return copy; },
+because it implicitly captures copy .
 
@@ -4214,11 +5678,14 @@

Narrowing Matchers

namespace { class vector {}; // #2 namespace foo { - class vector{}; // #3 + class vector {}; // #3 } } -cxxRecordDecl(hasName("vector"), isInAnonymousNamespace()) will match -#1, #2 and #3. + +The matcher cxxRecordDecl(hasName("vector"), + isInAnonymousNamespace()) +matches vector, +twice per declaration at #1, #2 and #3.
@@ -4241,7 +5708,9 @@

Narrowing Matchers

} } } -cxxRecordDecl(hasName("vector"), isInStdNamespace()) will match only #1. + +The matcher cxxRecordDecl(hasName("vector"), isInStdNamespace()) +matches class vector {} inside of namespace std. @@ -4251,10 +5720,14 @@

Narrowing Matchers

Given template<typename T> void A(T t) { T i; } - A(0); - A(0U); -functionDecl(isInstantiated()) - matches 'A(int) {...};' and 'A(unsigned) {...}'. + void foo() { + A(0); + A(0U); + } + +The matcher functionDecl(isInstantiated()) +matches the two instantiations of void A(T t) { T i; } that +are generated for int , and for int}. @@ -4262,16 +5735,25 @@

Narrowing Matchers

Matches private C++ declarations and C++ base specifers that specify private
 inheritance.
 
-Examples:
+Given
   class C {
   public:    int a;
   protected: int b;
-  private:   int c; // fieldDecl(isPrivate()) matches 'c'
+  private:   int c;
   };
 
+The matcher fieldDecl(isPrivate())
+matches c.
+
   struct Base {};
-  struct Derived1 : private Base {}; // matches 'Base'
-  class Derived2 : Base {}; // matches 'Base'
+  struct Derived1 : private Base {}; // Base
+  class Derived2 : Base {}; // Base
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isPrivate()).bind("base")))
+matches Derived1 and Derived2, with
+cxxBaseSpecifier(isPrivate()) matching
+Base.
 
@@ -4279,15 +5761,24 @@

Narrowing Matchers

Matches protected C++ declarations and C++ base specifers that specify
 protected inheritance.
 
-Examples:
+Given
   class C {
   public:    int a;
-  protected: int b; // fieldDecl(isProtected()) matches 'b'
+  protected: int b;
   private:   int c;
   };
 
+The matcher fieldDecl(isProtected())
+matches b.
+
   class Base {};
-  class Derived : protected Base {}; // matches 'Base'
+  class Derived : protected Base {};
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isProtected()).bind("base")))
+matches Derived, with
+cxxBaseSpecifier(isProtected()) matching
+Base.
 
@@ -4295,16 +5786,26 @@

Narrowing Matchers

Matches public C++ declarations and C++ base specifers that specify public
 inheritance.
 
-Examples:
+Given
   class C {
-  public:    int a; // fieldDecl(isPublic()) matches 'a'
+  public:    int a;
   protected: int b;
   private:   int c;
   };
 
+The matcher fieldDecl(isPublic())
+matches a.
+
+Given
   class Base {};
-  class Derived1 : public Base {}; // matches 'Base'
-  struct Derived2 : Base {}; // matches 'Base'
+  class Derived1 : public Base {};
+  struct Derived2 : Base {};
+
+The matcher
+cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(isPublic()).bind("base")))
+matches Derived1 and Derived2,
+with cxxBaseSpecifier(isPublic()) matching
+public Base and Base.
 
@@ -4313,20 +5814,24 @@

Narrowing Matchers

a specific number of designators. Example: Given - point ptarray[10] = { [2].y = 1.0, [0].x = 1.0 }; - point ptarray2[10] = { [2].y = 1.0, [2].x = 0.0, [0].x = 1.0 }; -designatorCountIs(2) - matches '{ [2].y = 1.0, [0].x = 1.0 }', - but not '{ [2].y = 1.0, [2].x = 0.0, [0].x = 1.0 }'. + struct point2 { double x; double y; }; + struct point2 ptarray[10] = { [0].x = 1.0 }; + struct point2 pt = { .x = 2.0 }; + +The matcher designatedInitExpr(designatorCountIs(2)) +matches [0].x = 1.0, but not .x = 2.0. Matcher<EnumDecl>isScoped
Matches C++11 scoped enum declaration.
 
-Example matches Y (matcher = enumDecl(isScoped()))
+Given
 enum X {};
 enum class Y {};
+
+The matcher enumDecl(isScoped())
+matches enum class Y {}
 
@@ -4340,8 +5845,12 @@

Narrowing Matchers

sizeof is known (std::size_t) and therefore the size of the outer sizeof is known. template<typename T> - void f(T x, T y) { sizeof(sizeof(T() + T()); } -expr(isInstantiationDependent()) matches sizeof(sizeof(T() + T()) + void f(T x, T y) { sizeof(T() + T()); } + +The matcher expr(isInstantiationDependent()) +matches sizeof(T() + T()), +(T() + T()), +T() + T() and T(). @@ -4355,7 +5864,9 @@

Narrowing Matchers

void add(T x, int y) { x + y; } -expr(isTypeDependent()) matches x + y + +The matcher expr(isTypeDependent()) +matches x + y and x. @@ -4366,7 +5877,9 @@

Narrowing Matchers

For example, the array bound of "Chars" in the following example is value-dependent. template<int Size> int f() { return Size; } -expr(isValueDependent()) matches return Size + +The matcher expr(isValueDependent()) +matches the return value Size. @@ -4374,16 +5887,22 @@

Narrowing Matchers

Matches expressions that resolve to a null pointer constant, such as
 GNU's __null, C++11's nullptr, or C's NULL macro.
 
-Given:
+Given
+  #define NULL 0
   void *v1 = NULL;
   void *v2 = nullptr;
   void *v3 = __null; // GNU extension
   char *cp = (char *)0;
   int *ip = 0;
   int i = 0;
-expr(nullPointerConstant())
-  matches the initializer for v1, v2, v3, cp, and ip. Does not match the
-  initializer for i.
+
+The matcher expr(nullPointerConstant())
+matches the initializer NULL of v1,
+matches the initializer nullptr of v2,
+matches the initializer __null of v3,
+matches the initializer 0 of cp and
+matches the initializer 0 of ip,
+but does not match the initializer i of i.
 
@@ -4397,8 +5916,10 @@

Narrowing Matchers

int b : 4; int c : 2; }; -fieldDecl(hasBitWidth(2)) - matches 'int a;' and 'int c;' but not 'int b;'. + +The matcher fieldDecl(hasBitWidth(2)) +matches a and c, +but not b. @@ -4410,8 +5931,10 @@

Narrowing Matchers

int a : 2; int b; }; -fieldDecl(isBitField()) - matches 'int a;' but not 'int b;'. + +The matcher fieldDecl(isBitField()) +matches a, +but does not match b. @@ -4419,22 +5942,27 @@

Narrowing Matchers

Matches literals that are equal to the given value of type ValueT.
 
 Given
+void f(char, bool, double, int);
+void foo() {
   f('false, 3.14, 42);
-characterLiteral(equals(0))
-  matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
-  match false
-floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
-  match 3.14
-integerLiteral(equals(42))
-  matches 42
+}
+
+The matcher characterLiteral(equals(0U)) matches 'The matchers cxxBoolLiteral(equals(false)) and
+cxxBoolLiteral(equals(0)) match false.
+The matcher floatLiteral(equals(3.14)) matches 3.14.
+The matcher integerLiteral(equals(42)) matches 42.
 
 Note that you cannot directly match a negative numeric literal because the
 minus sign is not part of the literal: It is a unary operator whose operand
 is the positive numeric literal. Instead, you must use a unaryOperator()
 matcher to match the minus sign:
 
-unaryOperator(hasOperatorName("-"),
-              hasUnaryOperand(integerLiteral(equals(13))))
+Given
+  int val = -1;
+
+The matcher unaryOperator(hasOperatorName("-"),
+              hasUnaryOperand(integerLiteral(equals(1))))
+matches -1.
 
 Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteralExpr>,
            Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
@@ -4452,6 +5980,30 @@ 

Narrowing Matchers

"operator" prefix: e.g. "<<". hasAnyOverloadedOperatorName("+", "-") + +Given + struct Point { double x; double y; }; + Point operator+(const Point&, const Point&); + Point operator-(const Point&, const Point&); + + Point sub(Point a, Point b) { + return b - a; + } + + +The matcher functionDecl(hasAnyOverloadedOperatorName("+", "-")), +which is equivalent to +functionDecl(anyOf(hasAnyOverloadedOperatorName("+"), +hasOverloadedOperatorName("-"))), +matches Point operator+(const Point&, const Point&) and +Point operator-(const Point&, const Point&). +The matcher +cxxOperatorCallExpr(hasAnyOverloadedOperatorName("+", "-")), +which is equivalent to +cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("+"), +hasOverloadedOperatorName("-"))), +matches b - a. + Is equivalent to anyOf(hasOverloadedOperatorName("+"), hasOverloadedOperatorName("-"))
@@ -4460,17 +6012,32 @@

Narrowing Matchers

Matcher<FunctionDecl>hasDynamicExceptionSpec
Matches functions that have a dynamic exception specification.
 
-Given:
-  void f();
-  void g() noexcept;
-  void h() noexcept(true);
-  void i() noexcept(false);
-  void j() throw();
-  void k() throw(int);
-  void l() throw(...);
-functionDecl(hasDynamicExceptionSpec()) and
-  functionProtoType(hasDynamicExceptionSpec())
-  match the declarations of j, k, and l, but not f, g, h, or i.
+Given
+  void f(int);
+  void g(int) noexcept;
+  void h(int) noexcept(true);
+  void i(int) noexcept(false);
+  void j(int) throw();
+  void k(int) throw(int);
+  void l(int) throw(...);
+
+The matcher functionDecl(hasDynamicExceptionSpec())
+matches the declarations void j(int) throw(),
+void k(int) throw(int)
+and void l(int) throw(...),
+but does not match void f(int), void g(int) noexcept,
+void h(int) noexcept(true)
+or void i(int) noexcept(true).
+The matcher
+functionProtoType(hasDynamicExceptionSpec()) matches
+the type void (int) throw() of j ,
+the type void (int) throw(int) of k and
+the type void (int) throw(...) of l .
+It does not match
+the type void (int) noexcept of f ,
+the type void (int) noexcept of g ,
+the type void (int) noexcept(int) of h or
+the type void (int) noexcept(...) of i .
 
@@ -4480,16 +6047,19 @@

Narrowing Matchers

Matches overloaded operator names specified in strings without the "operator" prefix: e.g. "<<". -Given: - class A { int operator*(); }; +Given + struct A { int operator*(); }; const A &operator<<(const A &a, const A &b); - A a; - a << a; // <-- This matches + void f(A a) { + a << a; // <-- This matches + } + -cxxOperatorCallExpr(hasOverloadedOperatorName("<<"))) matches the -specified line and +The matcher cxxOperatorCallExpr(hasOverloadedOperatorName("<<")) +matches a << a. +The matcher cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*"))) -matches the declaration of A. +matches struct A { int operator*(); }. Usable as: Matcher<CXXOperatorCallExpr>, Matcher<FunctionDecl> @@ -4498,9 +6068,12 @@

Narrowing Matchers

Matcher<FunctionDecl>hasTrailingReturn
Matches a function declared with a trailing return type.
 
-Example matches Y (matcher = functionDecl(hasTrailingReturn()))
+Given
 int X() {}
 auto Y() -> int {}
+
+The matcher functionDecl(hasTrailingReturn())
+matches auto Y() -> int {}.
 
@@ -4508,15 +6081,18 @@

Narrowing Matchers

Matches consteval function declarations and if consteval/if ! consteval
 statements.
 
-Given:
+Given
   consteval int a();
   void b() { if consteval {} }
   void c() { if ! consteval {} }
   void d() { if ! consteval {} else {} }
-functionDecl(isConsteval())
-  matches the declaration of "int a()".
-ifStmt(isConsteval())
-  matches the if statement in "void b()", "void c()", "void d()".
+
+The matcher functionDecl(isConsteval())
+matches a.
+The matcher ifStmt(isConsteval())
+matches the if statements
+if consteval {}, if ! consteval {} and
+if ! consteval {} else {}.
 
@@ -4524,27 +6100,30 @@

Narrowing Matchers

Matches constexpr variable and function declarations,
        and if constexpr.
 
-Given:
+Given
   constexpr int foo = 42;
   constexpr int bar();
   void baz() { if constexpr(1 > 0) {} }
-varDecl(isConstexpr())
-  matches the declaration of foo.
-functionDecl(isConstexpr())
-  matches the declaration of bar.
-ifStmt(isConstexpr())
-  matches the if statement in baz.
+
+The matcher varDecl(isConstexpr())
+matches foo.
+The matcher functionDecl(isConstexpr())
+matches bar.
+The matcher ifStmt(isConstexpr())
+matches if constexpr(1 > 0) {}.
 
Matcher<FunctionDecl>isDefaulted
Matches defaulted function declarations.
 
-Given:
+Given
   class A { ~A(); };
   class B { ~B() = default; };
-functionDecl(isDefaulted())
-  matches the declaration of ~B, but not ~A.
+
+The matcher functionDecl(isDefaulted())
+  matches ~B() = default,
+but does not match ~A().
 
@@ -4558,6 +6137,14 @@

Narrowing Matchers

extern int vb; // Doesn't match, as it doesn't define the variable. void fa() {} void fb(); // Doesn't match, as it has no body. + +The matcher tagDecl(isDefinition()) +matches A +The matcher varDecl(isDefinition()) +matches va +The matcher functionDecl(isDefinition()) +matches fa + @interface X - (void)ma; // Doesn't match, interface is declaration. @end @@ -4565,6 +6152,9 @@

Narrowing Matchers

- (void)ma {} @end +The matcher objcMethodDecl(isDefinition()) +matches - (void)ma {} + Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>, Matcher<ObjCMethodDecl> @@ -4573,11 +6163,13 @@

Narrowing Matchers

Matcher<FunctionDecl>isDeleted
Matches deleted function declarations.
 
-Given:
+Given
   void Func();
   void DeletedFunc() = delete;
-functionDecl(isDeleted())
-  matches the declaration of DeletedFunc, but not Func.
+
+The matcher functionDecl(isDeleted())
+matches DeletedFunc,
+but does not match Func.
 
@@ -4588,8 +6180,9 @@

Narrowing Matchers

Given template<typename T> void A(T t) { } template<> void A(int N) { } -functionDecl(isExplicitTemplateSpecialization()) - matches the specialization A<int>(). + +The matcher functionDecl(isExplicitTemplateSpecialization()) + matches the specialization template<> void A(int N) { }. Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> @@ -4598,17 +6191,21 @@

Narrowing Matchers

Matcher<FunctionDecl>isExternC
Matches extern "C" function or variable declarations.
 
-Given:
+Given
   extern "C" void f() {}
   extern "C" { void g() {} }
   void h() {}
   extern "C" int x = 1;
   extern "C" int y = 2;
   int z = 3;
-functionDecl(isExternC())
-  matches the declaration of f and g, but not the declaration of h.
-varDecl(isExternC())
-  matches the declaration of x and y, but not the declaration of z.
+
+The matcher functionDecl(isExternC())
+matches f
+and g.
+The matcher varDecl(isExternC())
+matches x
+and y,
+but does not match z.
 
@@ -4623,15 +6220,22 @@

Narrowing Matchers

inline namespace m {} } inline int Foo = 5; -functionDecl(isInline()) will match ::f(). -namespaceDecl(isInline()) will match n::m. -varDecl(isInline()) will match Foo; + +The matcher functionDecl(isInline()) matches f. +The matcher namespaceDecl(isInline()) matches m. +The matcher varDecl(isInline()) matches Foo Matcher<FunctionDecl>isMain
Determines whether the function is "main", which is the entry point
 into an executable program.
+
+Given
+  void f();
+  int main() {}
+
+The matcher functionDecl(isMain()) matches int main() {}.
 
@@ -4643,23 +6247,38 @@

Narrowing Matchers

[[noreturn]] void a(); __attribute__((noreturn)) void b(); struct c { [[noreturn]] c(); }; -functionDecl(isNoReturn()) - matches all of those except - void nope(); + +The matcher functionDecl(isNoReturn()) +match a, b +and c +but do not match nope Matcher<FunctionDecl>isNoThrow
Matches functions that have a non-throwing exception specification.
 
-Given:
-  void f();
-  void g() noexcept;
-  void h() throw();
-  void i() throw(int);
-  void j() noexcept(false);
-functionDecl(isNoThrow()) and functionProtoType(isNoThrow())
-  match the declarations of g, and h, but not f, i or j.
+Given
+  void f(int);
+  void g(int) noexcept;
+  void h(int) noexcept(false);
+  void i(int) throw();
+  void j(int) throw(int);
+
+The matcher functionDecl(isNoThrow())
+matches the declaration void g(int) noexcept
+and void i(int) throw(),
+but does not match void f(int),
+void h(int) noexcept(false)
+or void j(int) throw(int).
+The matcher
+functionProtoType(isNoThrow())
+matches the type void (int) throw() of i
+and the type void (int) noexcept of g,
+but does not match
+the type void (int) of f ,
+the type void (int) noexcept(false) of h or
+the type void (int) throw(int) of j .
 
@@ -4667,15 +6286,15 @@

Narrowing Matchers

Matches variable/function declarations that have "static" storage
 class specifier ("static" keyword) written in the source.
 
-Given:
+Given
   static void f() {}
   static int i = 0;
   extern int j;
   int k;
-functionDecl(isStaticStorageClass())
-  matches the function declaration f.
-varDecl(isStaticStorageClass())
-  matches the variable declaration i.
+The matcher functionDecl(isStaticStorageClass())
+  matches f
+The matcher varDecl(isStaticStorageClass())
+  matches i
 
@@ -4684,18 +6303,36 @@

Narrowing Matchers

member variable template instantiations. Given - template <typename T> class X {}; class A {}; X<A> x; -or - template <typename T> class X {}; class A {}; template class X<A>; -or - template <typename T> class X {}; class A {}; extern template class X<A>; -cxxRecordDecl(hasName("::X"), isTemplateInstantiation()) - matches the template instantiation of X<A>. + template <typename T> class X {}; + class A {}; + X<A> x; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches class X<class A>. + template <typename T> class X {}; + class A {}; + template class X<A>; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches template class X<A> + template <typename T> class X {}; + class A {}; + extern template class X<A>; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches extern template class X<A> But given - template <typename T> class X {}; class A {}; - template <> class X<A> {}; X<A> x; -cxxRecordDecl(hasName("::X"), isTemplateInstantiation()) + template <typename T> class X {}; + class A {}; + template <> class X<A> {}; + X<A> x; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) does not match, as X<A> is an explicit template specialization. Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> @@ -4711,17 +6348,25 @@

Narrowing Matchers

void g(int); template <typename... Ts> void h(Ts...); void i(); + +The matcher functionDecl(isVariadic()) +matches void f(...), +but does not match void g(int), +template <typename... Ts> void h(Ts...), +or void i(). Matcher<FunctionDecl>isWeak
Matches weak function declarations.
 
-Given:
-  void foo() __attribute__((__weakref__("__foo")));
-  void bar();
-functionDecl(isWeak())
-  matches the weak declaration "foo", but not "bar".
+Given
+  static void f();
+  void g() __attribute__((weak));
+The matcher functionDecl(isWeak())
+  matches the weak declaration
+void g() __attribute__((weak)),
+but does not match static void foo_v1().
 
@@ -4735,43 +6380,71 @@

Narrowing Matchers

void h(int i, int j); void j(int i); void k(int x, int y, int z, ...); -functionDecl(parameterCountIs(2)) - matches g and h -functionProtoType(parameterCountIs(2)) - matches g and h -functionProtoType(parameterCountIs(3)) - matches k +The matcher functionDecl(parameterCountIs(2)) +matches g and h +The matcher functionProtoType(parameterCountIs(1)) +matches the type void (int) of f and j. +The matcher functionProtoType(parameterCountIs(3)) matches the +type void (int, int, int, ...) of k. Matcher<FunctionProtoType>hasDynamicExceptionSpec
Matches functions that have a dynamic exception specification.
 
-Given:
-  void f();
-  void g() noexcept;
-  void h() noexcept(true);
-  void i() noexcept(false);
-  void j() throw();
-  void k() throw(int);
-  void l() throw(...);
-functionDecl(hasDynamicExceptionSpec()) and
-  functionProtoType(hasDynamicExceptionSpec())
-  match the declarations of j, k, and l, but not f, g, h, or i.
+Given
+  void f(int);
+  void g(int) noexcept;
+  void h(int) noexcept(true);
+  void i(int) noexcept(false);
+  void j(int) throw();
+  void k(int) throw(int);
+  void l(int) throw(...);
+
+The matcher functionDecl(hasDynamicExceptionSpec())
+matches the declarations void j(int) throw(),
+void k(int) throw(int)
+and void l(int) throw(...),
+but does not match void f(int), void g(int) noexcept,
+void h(int) noexcept(true)
+or void i(int) noexcept(true).
+The matcher
+functionProtoType(hasDynamicExceptionSpec()) matches
+the type void (int) throw() of j ,
+the type void (int) throw(int) of k and
+the type void (int) throw(...) of l .
+It does not match
+the type void (int) noexcept of f ,
+the type void (int) noexcept of g ,
+the type void (int) noexcept(int) of h or
+the type void (int) noexcept(...) of i .
 
Matcher<FunctionProtoType>isNoThrow
Matches functions that have a non-throwing exception specification.
 
-Given:
-  void f();
-  void g() noexcept;
-  void h() throw();
-  void i() throw(int);
-  void j() noexcept(false);
-functionDecl(isNoThrow()) and functionProtoType(isNoThrow())
-  match the declarations of g, and h, but not f, i or j.
+Given
+  void f(int);
+  void g(int) noexcept;
+  void h(int) noexcept(false);
+  void i(int) throw();
+  void j(int) throw(int);
+
+The matcher functionDecl(isNoThrow())
+matches the declaration void g(int) noexcept
+and void i(int) throw(),
+but does not match void f(int),
+void h(int) noexcept(false)
+or void j(int) throw(int).
+The matcher
+functionProtoType(isNoThrow())
+matches the type void (int) throw() of i
+and the type void (int) noexcept of g,
+but does not match
+the type void (int) of f ,
+the type void (int) noexcept(false) of h or
+the type void (int) throw(int) of j .
 
@@ -4785,12 +6458,12 @@

Narrowing Matchers

void h(int i, int j); void j(int i); void k(int x, int y, int z, ...); -functionDecl(parameterCountIs(2)) - matches g and h -functionProtoType(parameterCountIs(2)) - matches g and h -functionProtoType(parameterCountIs(3)) - matches k +The matcher functionDecl(parameterCountIs(2)) +matches g and h +The matcher functionProtoType(parameterCountIs(1)) +matches the type void (int) of f and j. +The matcher functionProtoType(parameterCountIs(3)) matches the +type void (int, int, int, ...) of k. @@ -4798,15 +6471,18 @@

Narrowing Matchers

Matches consteval function declarations and if consteval/if ! consteval
 statements.
 
-Given:
+Given
   consteval int a();
   void b() { if consteval {} }
   void c() { if ! consteval {} }
   void d() { if ! consteval {} else {} }
-functionDecl(isConsteval())
-  matches the declaration of "int a()".
-ifStmt(isConsteval())
-  matches the if statement in "void b()", "void c()", "void d()".
+
+The matcher functionDecl(isConsteval())
+matches a.
+The matcher ifStmt(isConsteval())
+matches the if statements
+if consteval {}, if ! consteval {} and
+if ! consteval {} else {}.
 
@@ -4814,16 +6490,17 @@

Narrowing Matchers

Matches constexpr variable and function declarations,
        and if constexpr.
 
-Given:
+Given
   constexpr int foo = 42;
   constexpr int bar();
   void baz() { if constexpr(1 > 0) {} }
-varDecl(isConstexpr())
-  matches the declaration of foo.
-functionDecl(isConstexpr())
-  matches the declaration of bar.
-ifStmt(isConstexpr())
-  matches the if statement in baz.
+
+The matcher varDecl(isConstexpr())
+matches foo.
+The matcher functionDecl(isConstexpr())
+matches bar.
+The matcher ifStmt(isConstexpr())
+matches if constexpr(1 > 0) {}.
 
@@ -4835,22 +6512,27 @@

Narrowing Matchers

Matches literals that are equal to the given value of type ValueT.
 
 Given
+void f(char, bool, double, int);
+void foo() {
   f('false, 3.14, 42);
-characterLiteral(equals(0))
-  matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
-  match false
-floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
-  match 3.14
-integerLiteral(equals(42))
-  matches 42
+}
+
+The matcher characterLiteral(equals(0U)) matches 'The matchers cxxBoolLiteral(equals(false)) and
+cxxBoolLiteral(equals(0)) match false.
+The matcher floatLiteral(equals(3.14)) matches 3.14.
+The matcher integerLiteral(equals(42)) matches 42.
 
 Note that you cannot directly match a negative numeric literal because the
 minus sign is not part of the literal: It is a unary operator whose operand
 is the positive numeric literal. Instead, you must use a unaryOperator()
 matcher to match the minus sign:
 
-unaryOperator(hasOperatorName("-"),
-              hasUnaryOperand(integerLiteral(equals(13))))
+Given
+  int val = -1;
+
+The matcher unaryOperator(hasOperatorName("-"),
+              hasUnaryOperand(integerLiteral(equals(1))))
+matches -1.
 
 Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteralExpr>,
            Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
@@ -4876,14 +6558,30 @@ 

Narrowing Matchers

return l(); } }; + +The matcher lambdaExpr(hasAnyCapture(lambdaCapture(capturesThis()))) - matches `[this]() { return cc; }`. +matches [this]() { return cc; }.
Matcher<LambdaCapture>isImplicit
Matches an entity that has been implicitly added by the compiler (e.g.
 implicit default/copy constructors).
+
+Given
+  struct S {};
+  void f(S obj) {
+    S copy = obj;
+    [&](){ return copy; };
+  }
+
+
+The matcher cxxConstructorDecl(isImplicit(), isCopyConstructor())
+matches the implicit copy constructor of S.
+The matcher lambdaExpr(forEachLambdaCapture(
+    lambdaCapture(isImplicit()))) matches [&](){ return copy; },
+because it implicitly captures copy .
 
@@ -4902,14 +6600,25 @@

Narrowing Matchers

}; template <class T> class Z { - void x() { this->m; } + void x() { + this->m; + this->t; + this->t->m; + } + int m; + T* t; }; -memberExpr(isArrow()) - matches this->x, x, y.x, a, this->b -cxxDependentScopeMemberExpr(isArrow()) - matches this->m -unresolvedMemberExpr(isArrow()) - matches this->f<T>, f<T> + +The matcher memberExpr(isArrow()) +matches this->x, x, a, +this->b, this->m and two times this->t, +once for the standalone member expression, and once for the member +expression that later accesses m . +Additionally, it does not match this->t->t. +The matcher cxxDependentScopeMemberExpr(isArrow()) +matches this->t->m, but not this->m or this->t. +The matcher unresolvedMemberExpr(isArrow()) +matches this->f<T>, f<T> @@ -4917,29 +6626,43 @@

Narrowing Matchers

Matches NamedDecl nodes that have any of the specified names.
 
 This matcher is only provided as a performance optimization of hasName.
-    hasAnyName(a, b, c)
- is equivalent to, but faster than
-    anyOf(hasName(a), hasName(b), hasName(c))
+
+Given
+  void f(int a, int b);
+
+The matcher namedDecl(hasAnyName("a", "b")),
+which is equivalent to the matcher
+namedDecl(hasAnyName("a", "b")),
+matches int a and int b, but not
+void f(int a, int b).
 
Matcher<NamedDecl>hasExternalFormalLinkage
Matches a declaration that has external formal linkage.
 
-Example matches only z (matcher = varDecl(hasExternalFormalLinkage()))
+Given
 void f() {
-  int x;
-  static int y;
+  int a;
+  static int b;
 }
-int z;
+int c;
+static int d;
+The matcher varDecl(hasExternalFormalLinkage())
+matches int c,
+but not int a, static int b or int d.
 
-Example matches f() because it has external formal linkage despite being
-unique to the translation unit as though it has internal likage
-(matcher = functionDecl(hasExternalFormalLinkage()))
+Given
+  namespace {
+    void f() {}
+  }
+  void g() {}
+  static void h() {}
 
-namespace {
-void f() {}
-}
+
+The matcher functionDecl(hasExternalFormalLinkage())
+matches void g() {}, but not void f() {} or
+static void h() {}.
 
@@ -4950,11 +6673,22 @@

Narrowing Matchers

with '<enclosing>::'. Does not match typedefs of an underlying type with the given name. -Example matches X (Name == "X") +Given class X; -Example matches X (Name is one of "::a::b::X", "a::b::X", "b::X", "X") + +The matcher namedDecl(hasName("X")) +matches class X. + +Given namespace a { namespace b { class X; } } + + +The matchers namedDecl(hasName("::a::b::X")), +namedDecl(hasName("a::b::X")), +namedDecl(hasName("b::X")) and +namedDecl(hasName("X")) +match class X. @@ -4966,12 +6700,13 @@

Narrowing Matchers

prefixing the name with '<enclosing>::'. Does not match typedefs of an underlying type with the given name. -Example matches X (regexp == "::X") - class X; - -Example matches X (regexp is one of "::X", "^foo::.*X", among others) +Given namespace foo { namespace bar { class X; } } + +The matcher namedDecl(matchesName("^::foo:.*X")) +matches class X. + If the matcher is used in clang-query, RegexFlags parameter should be passed as a quoted string. e.g: "NoFlags". Flags can be combined with '|' example "IgnoreCase | BasicRegex" @@ -4985,7 +6720,9 @@

Narrowing Matchers

namespace n { namespace {} // #1 } -namespaceDecl(isAnonymous()) will match #1 but not ::n. + +The matcher namespaceDecl(isAnonymous()) +matches namespace {}, but not namespace n. @@ -5000,9 +6737,10 @@

Narrowing Matchers

inline namespace m {} } inline int Foo = 5; -functionDecl(isInline()) will match ::f(). -namespaceDecl(isInline()) will match n::m. -varDecl(isInline()) will match Foo; + +The matcher functionDecl(isInline()) matches f. +The matcher namespaceDecl(isInline()) matches m. +The matcher varDecl(isInline()) matches Foo @@ -5011,15 +6749,23 @@

Narrowing Matchers

specified. Given + void foo() { + #pragma omp parallel + ; + #pragma omp parallel default(none) + ; + #pragma omp parallel default(shared) + ; + #pragma omp parallel default(private) + ; + #pragma omp parallel default(firstprivate) + ; + } - #pragma omp parallel - #pragma omp parallel default(none) - #pragma omp parallel default(shared) - #pragma omp parallel default(private) - #pragma omp parallel default(firstprivate) -``ompDefaultClause(isFirstPrivateKind())`` matches only -``default(firstprivate)``. +The matcher +ompExecutableDirective(hasAnyClause(ompDefaultClause(isFirstPrivateKind()))) +matches #pragma omp parallel default(firstprivate). @@ -5027,14 +6773,23 @@

Narrowing Matchers

Matches if the OpenMP ``default`` clause has ``none`` kind specified.
 
 Given
+  void foo() {
+    #pragma omp parallel
+      ;
+    #pragma omp parallel default(none)
+      ;
+    #pragma omp parallel default(shared)
+      ;
+    #pragma omp parallel default(private)
+      ;
+    #pragma omp parallel default(firstprivate)
+      ;
+  }
 
-  #pragma omp parallel
-  #pragma omp parallel default(none)
-  #pragma omp parallel default(shared)
-  #pragma omp parallel default(private)
-  #pragma omp parallel default(firstprivate)
 
-``ompDefaultClause(isNoneKind())`` matches only ``default(none)``.
+The matcher
+ompExecutableDirective(hasAnyClause(ompDefaultClause(isNoneKind())))
+matches only #pragma omp parallel default(none).
 
@@ -5043,15 +6798,23 @@

Narrowing Matchers

specified. Given - - #pragma omp parallel + void foo() { + #pragma omp parallel + ; #pragma omp parallel default(none) + ; #pragma omp parallel default(shared) + ; #pragma omp parallel default(private) + ; #pragma omp parallel default(firstprivate) + ; + } + -``ompDefaultClause(isPrivateKind())`` matches only -``default(private)``. +The matcher +ompExecutableDirective(hasAnyClause(ompDefaultClause(isPrivateKind()))) +matches #pragma omp parallel default(private). @@ -5059,14 +6822,23 @@

Narrowing Matchers

Matches if the OpenMP ``default`` clause has ``shared`` kind specified.
 
 Given
-
-  #pragma omp parallel
-  #pragma omp parallel default(none)
+  void foo() {
+    #pragma omp parallel
+      ;
+    #pragma omp parallel default(none)
+      ;
   #pragma omp parallel default(shared)
+      ;
   #pragma omp parallel default(private)
+      ;
   #pragma omp parallel default(firstprivate)
+      ;
+  }
 
-``ompDefaultClause(isSharedKind())`` matches only ``default(shared)``.
+
+The matcher
+ompExecutableDirective(hasAnyClause(ompDefaultClause(isSharedKind())))
+matches #pragma omp parallel default(shared).
 
@@ -5075,13 +6847,21 @@

Narrowing Matchers

clause kind. Given + void foo() { + #pragma omp parallel + ; + #pragma omp parallel for + for (int i = 0; i < 10; ++i) {} + #pragma omp for + for (int i = 0; i < 10; ++i) {} + } - #pragma omp parallel - #pragma omp parallel for - #pragma omp for -`ompExecutableDirective(isAllowedToContainClause(OMPC_default))`` matches -``omp parallel`` and ``omp parallel for``. +The matcher +ompExecutableDirective(isAllowedToContainClauseKind( +OpenMPClauseKind::OMPC_default)) +matches #pragma omp parallel +and #pragma omp parallel for. If the matcher is use from clang-query, ``OpenMPClauseKind`` parameter should be passed as a quoted string. e.g., @@ -5094,29 +6874,89 @@

Narrowing Matchers

i.e., directives that can't have a structured block. Given + void foo() { + #pragma omp parallel + { + #pragma omp taskyield + } + } - #pragma omp parallel - {} - #pragma omp taskyield -``ompExecutableDirective(isStandaloneDirective()))`` matches -``omp taskyield``. +The matcher ompExecutableDirective(isStandaloneDirective()) +matches #pragma omp taskyield. Matcher<ObjCInterfaceDecl>isDerivedFromstd::string BaseName
Overloaded method as shortcut for isDerivedFrom(hasName(...)).
+
+Matches C++ classes that are directly or indirectly derived from a class
+matching Base, or Objective-C classes that directly or indirectly
+subclass a class matching Base.
+
+Note that a class is not considered to be derived from itself.
+
+Example matches Y, Z, C (Base == hasName("X"))
+  class X {};
+  class Y : public X {};  // directly derived
+  class Z : public Y {};  // indirectly derived
+  typedef X A;
+  typedef A B;
+  class C : public B {};  // derived from a typedef of X
+
+  class Foo {};
+  typedef Foo Alias;
+  class Bar : public Alias {};  // derived from Alias, which is a
+                                // typedef of Foo
+
+
+The matcher cxxRecordDecl(isDerivedFrom("X"))
+matches Y, Z and C.
+The matcher cxxRecordDecl(isDerivedFrom("Foo"))
+matches Bar.
+
+In the following example, Bar matches isDerivedFrom(hasName("NSObject"))
+  @interface NSObject @end
+  @interface Bar : NSObject @end
+
+
+Usable as: Matcher<CXXRecordDecl>, Matcher<ObjCInterfaceDecl>
 
Matcher<ObjCInterfaceDecl>isDirectlyDerivedFromstd::string BaseName
Overloaded method as shortcut for isDirectlyDerivedFrom(hasName(...)).
+
+Given
+  struct Base {};
+  struct DirectlyDerived : public Base {};
+  struct IndirectlyDerived : public DirectlyDerived {};
+
+
+The matcher cxxRecordDecl(isDirectlyDerivedFrom("Base"))
+matches DirectlyDerived, but not
+IndirectlyDerived.
 
Matcher<ObjCInterfaceDecl>isSameOrDerivedFromstd::string BaseName -
Overloaded method as shortcut for
+
Similar to isDerivedFrom(), but also matches classes that directly
+match Base.
+Overloaded method as shortcut for
 isSameOrDerivedFrom(hasName(...)).
+
+Given
+  class X {};
+  class Y : public X {};  // directly derived
+  class Z : public Y {};  // indirectly derived
+  typedef X A;
+  typedef A B;
+  class C : public B {};  // derived from a typedef of X
+
+The matcher
+cxxRecordDecl(isSameOrDerivedFrom("X"), isDefinition())
+matches class X {}, class Y : public X {},
+class Z : public Y {} and class C : public B {}.
 
@@ -5124,12 +6964,15 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has at least
 the specified number of arguments (including absent default arguments).
 
-Example matches f(0, 0) and g(0, 0, 0)
-(matcher = callExpr(argumentCountAtLeast(2)))
+Given
   void f(int x, int y);
   void g(int x, int y, int z);
-  f(0, 0);
-  g(0, 0, 0);
+  void foo() {
+    f(0, 0);
+    g(0, 0, 0);
+  }
+The matcher callExpr(argumentCountAtLeast(2))
+matches f(0, 0) and g(0, 0, 0)
 
@@ -5137,9 +6980,13 @@

Narrowing Matchers

Checks that a call expression or a constructor call expression has
 a specific number of arguments (including absent default arguments).
 
-Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+Given
   void f(int x, int y);
-  f(0, 0);
+  void foo() {
+    f(0, 0);
+  }
+The matcher callExpr(argumentCountIs(2))
+matches f(0, 0)
 
@@ -5147,24 +6994,27 @@

Narrowing Matchers

Matches when at least one of the supplied string equals to the
 Selector.getAsString()
 
- matcher = objCMessageExpr(hasSelector("methodA:", "methodB:"));
- matches both of the expressions below:
     [myObj methodA:argA];
     [myObj methodB:argB];
+
+ The matcher objCMessageExpr(hasSelector("methodA:", "methodB:"));
+ matches [myObj methodA:argA]; and [myObj methodB:argB];
 
Matcher<ObjCMessageExpr>hasKeywordSelector
Matches when the selector is a keyword selector
 
-objCMessageExpr(hasKeywordSelector()) matches the generated setFrame
-message expression in
-
+Given
   UIWebView *webView = ...;
   CGRect bodyFrame = webView.frame;
   bodyFrame.size.height = self.bodyContentHeight;
   webView.frame = bodyFrame;
   //     ^---- matches here
+
+
+The matcher objCMessageExpr(hasKeywordSelector()) matches the
+generated setFrame message expression in
 
@@ -5179,56 +7029,68 @@

Narrowing Matchers

Matcher<ObjCMessageExpr>hasSelectorstd::string BaseName
Matches when BaseName == Selector.getAsString()
 
- matcher = objCMessageExpr(hasSelector("loadHTMLString:baseURL:"));
- matches the outer message expr in the code below, but NOT the message
- invocation for self.bodyView.
     [self.bodyView loadHTMLString:html baseURL:NULL];
+
+The matcher
+objCMessageExpr(hasSelector("loadHTMLString:baseURL:")); matches
+the outer message expr in the code below, but NOT the message invocation
+for self.bodyView.
 
Matcher<ObjCMessageExpr>hasUnarySelector
Matches when the selector is a Unary Selector
 
- matcher = objCMessageExpr(matchesSelector(hasUnarySelector());
- matches self.bodyView in the code below, but NOT the outer message
- invocation of "loadHTMLString:baseURL:".
+Given
     [self.bodyView loadHTMLString:html baseURL:NULL];
+
+
+ The matcher objCMessageExpr(matchesSelector(hasUnarySelector());
+ matches self.bodyView, but does not match the outer message
+ invocation of "loadHTMLString:baseURL:".
 
Matcher<ObjCMessageExpr>isClassMessage
Returns true when the Objective-C message is sent to a class.
 
-Example
-matcher = objcMessageExpr(isClassMessage())
-matches
+Given
   [NSString stringWithFormat:@"format"];
-but not
   NSString *x = @"hello";
   [x containsString:@"h"];
+
+The matcher objcMessageExpr(isClassMessage())
+matches [NSString stringWithFormat:@"format"];
+but does not match [[x containsString:@"h"]
 
Matcher<ObjCMessageExpr>isInstanceMessage
Returns true when the Objective-C message is sent to an instance.
 
-Example
-matcher = objcMessageExpr(isInstanceMessage())
-matches
+Given
   NSString *x = @"hello";
   [x containsString:@"h"];
-but not
   [NSString stringWithFormat:@"format"];
+
+The matcher objcMessageExpr(isInstanceMessage())
+matches [x containsString:@"h"];
+but does not match [NSString stringWithFormat:@"format"];
 
Matcher<ObjCMessageExpr>matchesSelectorStringRef RegExp, Regex::RegexFlags Flags = NoFlags
Matches ObjC selectors whose name contains
 a substring matched by the given RegExp.
- matcher = objCMessageExpr(matchesSelector("loadHTMLStringmatches the outer message expr in the code below, but NOT the message
- invocation for self.bodyView.
+
+Given
     [self.bodyView loadHTMLString:html baseURL:NULL];
 
+
+The matcher
+objCMessageExpr(matchesSelector("loadHTMLStringmatches the outer message expr in the code below, but NOT the message
+invocation for self.bodyView.
+
 If the matcher is used in clang-query, RegexFlags parameter
 should be passed as a quoted string. e.g: "NoFlags".
 Flags can be combined with '|' example "IgnoreCase | BasicRegex"
@@ -5238,25 +7100,26 @@ 

Narrowing Matchers

Matcher<ObjCMessageExpr>numSelectorArgsunsigned N
Matches when the selector has the specified number of arguments
 
- matcher = objCMessageExpr(numSelectorArgs(0));
- matches self.bodyView in the code below
-
- matcher = objCMessageExpr(numSelectorArgs(2));
- matches the invocation of "loadHTMLString:baseURL:" but not that
- of self.bodyView
     [self.bodyView loadHTMLString:html baseURL:NULL];
+
+The matcher objCMessageExpr(numSelectorArgs(0))
+matches self.bodyView.
+The matcher objCMessageExpr(numSelectorArgs(2))
+matches the invocation of loadHTMLString:baseURL:
+but does not match self.bodyView
 
Matcher<ObjCMethodDecl>isClassMethod
Returns true when the Objective-C method declaration is a class method.
 
-Example
-matcher = objcMethodDecl(isClassMethod())
-matches
+Given
 @interface I + (void)foo; @end
-but not
 @interface I - (void)bar; @end
+
+The matcher objcMethodDecl(isClassMethod())
+matches @interface I + (void)foo; @end
+but does not match interface I + (void)foo; @end
 
@@ -5270,6 +7133,14 @@

Narrowing Matchers

extern int vb; // Doesn't match, as it doesn't define the variable. void fa() {} void fb(); // Doesn't match, as it has no body. + +The matcher tagDecl(isDefinition()) +matches A +The matcher varDecl(isDefinition()) +matches va +The matcher functionDecl(isDefinition()) +matches fa + @interface X - (void)ma; // Doesn't match, interface is declaration. @end @@ -5277,6 +7148,9 @@

Narrowing Matchers

- (void)ma {} @end +The matcher objcMethodDecl(isDefinition()) +matches - (void)ma {} + Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>, Matcher<ObjCMethodDecl>
@@ -5285,33 +7159,39 @@

Narrowing Matchers

Matcher<ObjCMethodDecl>isInstanceMethod
Returns true when the Objective-C method declaration is an instance method.
 
-Example
-matcher = objcMethodDecl(isInstanceMethod())
-matches
+Given
 @interface I - (void)bar; @end
-but not
 @interface I + (void)foo; @end
+
+The matcher objcMethodDecl(isInstanceMethod())
+matches @interface I - (void)bar; @end
+but does not match @interface I - (void)foo; @end
+
 
Matcher<ParmVarDecl>hasDefaultArgument
Matches a declaration that has default arguments.
 
-Example matches y (matcher = parmVarDecl(hasDefaultArgument()))
-void x(int val) {}
-void y(int val = 0) {}
+Given
+  void x(int val) {}
+  void y(int val = 0) {}
+
+
+The matcher parmVarDecl(hasDefaultArgument())
+matches int val = 0.
 
 Deprecated. Use hasInitializer() instead to be able to
 match on the contents of the default argument.  For example:
 
-void x(int val = 7) {}
-void y(int val = 42) {}
-parmVarDecl(hasInitializer(integerLiteral(equals(42))))
-  matches the parameter of y
+Given
+  void x(int val = 7) {}
+  void y(int val = 42) {}
+
 
-A matcher such as
-  parmVarDecl(hasInitializer(anything()))
-is equivalent to parmVarDecl(hasDefaultArgument()).
+The matcher
+parmVarDecl(hasInitializer(integerLiteral(equals(42)))),
+matches int val = 42.
 
@@ -5326,9 +7206,9 @@

Narrowing Matchers

void f(int a, int b, int c) { } -``parmVarDecl(isAtPosition(0))`` matches ``int a``. - -``parmVarDecl(isAtPosition(1))`` matches ``int b``. +The matcher parmVarDecl(isAtPosition(0)) matches +a. The matcher parmVarDecl(isAtPosition(1)) +matches b.
@@ -5338,8 +7218,9 @@

Narrowing Matchers

Given class Y { public: void x(); }; void z() { Y* y; y->x(); } -cxxMemberCallExpr(on(hasType(asString("class Y *")))) - matches y->x() + +The matcher cxxMemberCallExpr(on(hasType(asString("Y *")))) +matches y->x() @@ -5350,10 +7231,11 @@

Narrowing Matchers

Given class X { int a; int b; }; -cxxRecordDecl( + +The matcher cxxRecordDecl( has(fieldDecl(hasName("a"), hasType(type().bind("t")))), has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t")))))) - matches the class X, as a and b have the same type. + matches X, as a and b have the same type. Note that when multiple matches are involved via forEach* matchers, equalsBoundNodes acts as a filter. @@ -5372,12 +7254,15 @@

Narrowing Matchers

Given typedef const int const_int; - const_int i; - int *const j; + const_int i = 0; + int *const j = nullptr; int *volatile k; int m; -varDecl(hasType(hasLocalQualifiers())) matches only j and k. -i is const-qualified but the qualifier is not local. + + +The matcher varDecl(hasType(hasLocalQualifiers())) matches only +j and k. is +const-qualified but the qualifier is not local. @@ -5388,9 +7273,11 @@

Narrowing Matchers

void a(char); void b(wchar_t); void c(double); + + +The matcher functionDecl(hasAnyParameter(hasType(isAnyCharacter()))) -matches "a(char)", "b(wchar_t)", but not "c(double)". - +a, b, but not Matcher<QualType>isAnyPointer @@ -5406,8 +7293,9 @@

Narrowing Matchers

Foo *f; int j; -varDecl(hasType(isAnyPointer())) - matches "int *i" and "Foo *f", but not "int j". + +The matcher varDecl(hasType(isAnyPointer())) +int *i and Foo *f, but not int j. @@ -5421,9 +7309,11 @@

Narrowing Matchers

void c(const int); void d(const int*); void e(int const) {}; +The matcher functionDecl(hasAnyParameter(hasType(isConstQualified()))) - matches "void b(int const)", "void c(const int)" and - "void e(int const) {}". It does not match d as there + matches b, c and + e. + It does not match as there is no top-level const on the parameter type "const int *". @@ -5435,8 +7325,8 @@

Narrowing Matchers

void a(int); void b(long); void c(double); -functionDecl(hasAnyParameter(hasType(isInteger()))) -matches "a(int)", "b(long)", but not "c(double)". +The matcher functionDecl(hasAnyParameter(hasType(isInteger()))) +a, b, but not c. @@ -5447,8 +7337,9 @@

Narrowing Matchers

void a(int); void b(unsigned long); void c(double); -functionDecl(hasAnyParameter(hasType(isSignedInteger()))) -matches "a(int)", but not "b(unsigned long)" and "c(double)". +The matcher +functionDecl(hasAnyParameter(hasType(isSignedInteger()))) matches +a, but not and not @@ -5459,8 +7350,10 @@

Narrowing Matchers

void a(int); void b(unsigned long); void c(double); +The matcher functionDecl(hasAnyParameter(hasType(isUnsignedInteger()))) -matches "b(unsigned long)", but not "a(int)" and "c(double)". +matches b, +but does not match a and c. @@ -5474,9 +7367,11 @@

Narrowing Matchers

void c(volatile int); void d(volatile int*); void e(int volatile) {}; +The matcher functionDecl(hasAnyParameter(hasType(isVolatileQualified()))) - matches "void b(int volatile)", "void c(volatile int)" and - "void e(int volatile) {}". It does not match d as there + matches b, c and + e. + It does not match as there is no top-level volatile on the parameter type "volatile int *". @@ -5488,10 +7383,11 @@

Narrowing Matchers

Given class X { int a; int b; }; -cxxRecordDecl( + +The matcher cxxRecordDecl( has(fieldDecl(hasName("a"), hasType(type().bind("t")))), has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t")))))) - matches the class X, as a and b have the same type. + matches X, as a and b have the same type. Note that when multiple matches are involved via forEach* matchers, equalsBoundNodes acts as a filter. @@ -5504,7 +7400,7 @@

Narrowing Matchers

-Matcher<Stmt>equalsNodeconst Stmt* Other +Matcher<Stmt>equalsNodeconst Stmt * Other
Matches if a node equals another node.
 
 Stmt has pointer identity in the AST.
@@ -5516,6 +7412,15 @@ 

Narrowing Matchers

Does not match if only part of the statement is expanded from that macro or if different parts of the statement are expanded from different appearances of the macro. + +Given + #define A 0 + #define B A + int c = B; + +The matcher integerLiteral(isExpandedFromMacro("A")) +matches the literal expanded at the initializer B of the variable +c .
@@ -5523,12 +7428,25 @@

Narrowing Matchers

Matches AST nodes that were expanded within files whose name is
 partially matching a given regex.
 
-Example matches Y but not X
-    (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
-  #include "ASTMatcher.h"
-  class X {};
-ASTMatcher.h:
-  class Y {};
+Given the headers Y.h
+  #pragma once
+  typedef int my_y_int;
+and X.h
+  #pragma once
+  typedef int my_x_int;
+and the source code
+  #include "X.h"
+  #include "Y.h"
+  typedef int my_main_file_int;
+  my_main_file_int a = 0;
+  my_x_int b = 1;
+  my_y_int c = 2;
+
+The matcher
+typedefDecl(isExpansionInFileMatching("Y.h"))
+matches typedef int my_y_int,
+but does not match typedef int my_main_file_int or
+typedef int my_x_int.
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -5541,12 +7459,18 @@ 

Narrowing Matchers

Matcher<Stmt>isExpansionInMainFile
Matches AST nodes that were expanded within the main-file.
 
-Example matches X but not Y
-  (matcher = cxxRecordDecl(isExpansionInMainFile())
-  #include <Y.h>
-  class X {};
-Y.h:
-  class Y {};
+Given the header Y.h
+  #pragma once
+  typedef int my_header_int;
+and the source file
+  #include "Y.h"
+  typedef int my_main_file_int;
+  my_main_file_int a = 0;
+  my_header_int b = 1;
+
+The matcher typedefDecl(isExpansionInMainFile())
+matches typedef int my_main_file_int,
+but does not match typedef int my_header_int.
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -5555,12 +7479,17 @@

Narrowing Matchers

Matcher<Stmt>isExpansionInSystemHeader
Matches AST nodes that were expanded within system-header-files.
 
-Example matches Y but not X
-    (matcher = cxxRecordDecl(isExpansionInSystemHeader())
+Given the header SystemHeader.h
+  #pragma once
+  int header();
+and the source code
   #include <SystemHeader.h>
-  class X {};
-SystemHeader.h:
-  class Y {};
+  static int main_file();
+
+
+The matcher functionDecl(isExpansionInSystemHeader())
+matches int header(),
+but does not match static int main_file().
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -5571,14 +7500,18 @@

Narrowing Matchers

Given int j; - template<typename T> void A(T t) { T i; j += 42;} - A(0); - A(0U); -declStmt(isInTemplateInstantiation()) - matches 'int i;' and 'unsigned i'. -unless(stmt(isInTemplateInstantiation())) - will NOT match j += 42; as it's shared between the template definition and - instantiation. + template<typename T> void A(T t) { T i; } + void foo() { + A(0); + A(0U); + } + +The matcher declStmt(isInTemplateInstantiation()) +matches T i; twice, once for int and once for +int}. +The matcher declStmt(unless(isInTemplateInstantiation())) will +match T i; once inside the template definition, but not for any of +the instantiated bodies.
@@ -5592,21 +7525,28 @@

Narrowing Matchers

char *s = "abcd"; wchar_t *ws = L"abcd"; char *w = "a"; -constantArrayType(hasSize(42)) - matches "int a[42]" and "int b[2 * 21]" -stringLiteral(hasSize(4)) - matches "abcd", L"abcd" + +The matcher constantArrayType(hasSize(42)) +matches int[42] twice. +The matcher stringLiteral(hasSize(4)) +matches "abcd" and L"abcd". Matcher<TagDecl>isClass
Matches TagDecl object that are spelled with "class."
 
-Example matches C, but not S, U or E.
+Given
   struct S {};
   class C {};
   union U {};
-  enum E {};
+  enum E { Ok };
+
+The matcher tagDecl(isClass())
+matches class C,
+but does not match struct S,
+union U
+or enum E.
 
@@ -5620,6 +7560,14 @@

Narrowing Matchers

extern int vb; // Doesn't match, as it doesn't define the variable. void fa() {} void fb(); // Doesn't match, as it has no body. + +The matcher tagDecl(isDefinition()) +matches A +The matcher varDecl(isDefinition()) +matches va +The matcher functionDecl(isDefinition()) +matches fa + @interface X - (void)ma; // Doesn't match, interface is declaration. @end @@ -5627,6 +7575,9 @@

Narrowing Matchers

- (void)ma {} @end +The matcher objcMethodDecl(isDefinition()) +matches - (void)ma {} + Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>, Matcher<ObjCMethodDecl> @@ -5635,11 +7586,16 @@

Narrowing Matchers

Matcher<TagDecl>isEnum
Matches TagDecl object that are spelled with "enum."
 
-Example matches E, but not C, S or U.
+Given
   struct S {};
   class C {};
   union U {};
-  enum E {};
+  enum E { Ok };
+
+The matcher tagDecl(isEnum())
+matches enum E { Ok },
+but does not match struct S {},
+class C {} or union U {}.
 
@@ -5650,18 +7606,30 @@

Narrowing Matchers

struct S {}; class C {}; union U {}; - enum E {}; + enum E { Ok }; + +The matcher tagDecl(isStruct()) +matches struct S, +but does not match class C, +union U +or enum E. Matcher<TagDecl>isUnion
Matches TagDecl object that are spelled with "union."
 
-Example matches U, but not C, S or E.
+Given
   struct S {};
   class C {};
   union U {};
-  enum E {};
+  enum E { Ok };
+
+The matcher tagDecl(isUnion())
+matches union U,
+does not match struct S,
+class C
+or enum E.
 
@@ -5675,9 +7643,12 @@

Narrowing Matchers

Given template<int T> struct C {}; C<42> c; -classTemplateSpecializationDecl( + +The matcher classTemplateSpecializationDecl( hasAnyTemplateArgument(equalsIntegralValue("42"))) - matches the implicit instantiation of C in C<42>. +matches the implicitly declared specialization +struct C<42> from the instantiation for the type of the +variable c . @@ -5687,10 +7658,12 @@

Narrowing Matchers

Given template<int T> struct C {}; C<42> c; -classTemplateSpecializationDecl( + +The matcher classTemplateSpecializationDecl( hasAnyTemplateArgument(isIntegral())) - matches the implicit instantiation of C in C<42> - with isIntegral() matching 42. +matches the implicitly declared specialization +struct C<42> from the instantiation for the type of the +variable c . @@ -5700,8 +7673,10 @@

Narrowing Matchers

Given template<typename T> struct C {}; C<int> c; + +The matcher classTemplateSpecializationDecl(templateArgumentCountIs(1)) - matches C<int>. +matches struct C<int>. @@ -5710,6 +7685,15 @@

Narrowing Matchers

Does not match if only part of the statement is expanded from that macro or if different parts of the statement are expanded from different appearances of the macro. + +Given + #define A 0 + #define B A + int c = B; + +The matcher integerLiteral(isExpandedFromMacro("A")) +matches the literal expanded at the initializer B of the variable +c . @@ -5717,12 +7701,25 @@

Narrowing Matchers

Matches AST nodes that were expanded within files whose name is
 partially matching a given regex.
 
-Example matches Y but not X
-    (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*"))
-  #include "ASTMatcher.h"
-  class X {};
-ASTMatcher.h:
-  class Y {};
+Given the headers Y.h
+  #pragma once
+  typedef int my_y_int;
+and X.h
+  #pragma once
+  typedef int my_x_int;
+and the source code
+  #include "X.h"
+  #include "Y.h"
+  typedef int my_main_file_int;
+  my_main_file_int a = 0;
+  my_x_int b = 1;
+  my_y_int c = 2;
+
+The matcher
+typedefDecl(isExpansionInFileMatching("Y.h"))
+matches typedef int my_y_int,
+but does not match typedef int my_main_file_int or
+typedef int my_x_int.
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -5735,12 +7732,18 @@ 

Narrowing Matchers

Matcher<TypeLoc>isExpansionInMainFile
Matches AST nodes that were expanded within the main-file.
 
-Example matches X but not Y
-  (matcher = cxxRecordDecl(isExpansionInMainFile())
-  #include <Y.h>
-  class X {};
-Y.h:
-  class Y {};
+Given the header Y.h
+  #pragma once
+  typedef int my_header_int;
+and the source file
+  #include "Y.h"
+  typedef int my_main_file_int;
+  my_main_file_int a = 0;
+  my_header_int b = 1;
+
+The matcher typedefDecl(isExpansionInMainFile())
+matches typedef int my_main_file_int,
+but does not match typedef int my_header_int.
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -5749,12 +7752,17 @@

Narrowing Matchers

Matcher<TypeLoc>isExpansionInSystemHeader
Matches AST nodes that were expanded within system-header-files.
 
-Example matches Y but not X
-    (matcher = cxxRecordDecl(isExpansionInSystemHeader())
+Given the header SystemHeader.h
+  #pragma once
+  int header();
+and the source code
   #include <SystemHeader.h>
-  class X {};
-SystemHeader.h:
-  class Y {};
+  static int main_file();
+
+
+The matcher functionDecl(isExpansionInSystemHeader())
+matches int header(),
+but does not match static int main_file().
 
 Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
 
@@ -5765,8 +7773,9 @@

Narrowing Matchers

Given struct S { bool func(); }; -functionDecl(returns(booleanType())) - matches "bool func();" + +The matcher functionDecl(returns(booleanType())) +func
@@ -5777,10 +7786,11 @@

Narrowing Matchers

Given class X { int a; int b; }; -cxxRecordDecl( + +The matcher cxxRecordDecl( has(fieldDecl(hasName("a"), hasType(type().bind("t")))), has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t")))))) - matches the class X, as a and b have the same type. + matches X, as a and b have the same type. Note that when multiple matches are involved via forEach* matchers, equalsBoundNodes acts as a filter. @@ -5793,7 +7803,7 @@

Narrowing Matchers

-Matcher<Type>equalsNodeconst Type* Other +Matcher<Type>equalsNodeconst Type * Other
Matches if a node equals another node.
 
 Type has pointer identity in the AST.
@@ -5806,8 +7816,9 @@ 

Narrowing Matchers

Given int i; float f; -realFloatingPointType() - matches "float f" but not "int i" +The matcher type(realFloatingPointType()) +matches float +but does not match int.
@@ -5816,8 +7827,10 @@

Narrowing Matchers

Given struct S { void func(); }; -functionDecl(returns(voidType())) - matches "void func();" + + +The matcher functionDecl(returns(voidType())) +func @@ -5826,9 +7839,10 @@

Narrowing Matchers

Given int x; - int s = sizeof(x) + alignof(x) -unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf)) - matches sizeof(x) + int s = sizeof(x) + alignof(x); + +The matcher unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf)) +matches sizeof(x) If the matcher is use from clang-query, UnaryExprOrTypeTrait parameter should be passed as a quoted string. e.g., ofKind("UETT_SizeOf"). @@ -5839,9 +7853,26 @@

Narrowing Matchers

Matches operator expressions (binary or unary) that have any of the
 specified names.
 
+It provides a compact way of writing if an operator has any of the specified
+names:
+The matcher
    hasAnyOperatorName("+", "-")
- Is equivalent to
-   anyOf(hasOperatorName("+"), hasOperatorName("-"))
+Is equivalent to
+   hasOperatorName("-"))}
+
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+void bar(bool a, bool b) {
+  a && b;
+ }
+
+The matcher binaryOperator(hasAnyOperatorName("||", "&&"))
+matches a || b and a && b.
+The matcher unaryOperator(hasAnyOperatorName("-", "!"))
+matches !(a || b).
 
@@ -5849,15 +7880,22 @@

Narrowing Matchers

Matches the operator Name of operator expressions and fold expressions
 (binary or unary).
 
-Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
-  !(a || b)
+Given
+void foo(bool a, bool b) {
+  !(a || b);
+ }
+
+The matcher binaryOperator(hasOperatorName("||"))
+matches a || b
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(hasOperatorName("+")))
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
   }
+
+The matcher cxxFoldExpr(hasOperatorName("+"))
+ matches (0 + ... + args).
 
@@ -5876,40 +7914,57 @@

Narrowing Matchers

}; template <class T> class Z { - void x() { this->m; } + void x() { + this->m; + this->t; + this->t->m; + } + int m; + T* t; }; -memberExpr(isArrow()) - matches this->x, x, y.x, a, this->b -cxxDependentScopeMemberExpr(isArrow()) - matches this->m -unresolvedMemberExpr(isArrow()) - matches this->f<T>, f<T> + +The matcher memberExpr(isArrow()) +matches this->x, x, a, +this->b, this->m and two times this->t, +once for the standalone member expression, and once for the member +expression that later accesses m . +Additionally, it does not match this->t->t. +The matcher cxxDependentScopeMemberExpr(isArrow()) +matches this->t->m, but not this->m or this->t. +The matcher unresolvedMemberExpr(isArrow()) +matches this->f<T>, f<T> Matcher<VarDecl>hasAutomaticStorageDuration
Matches a variable declaration that has automatic storage duration.
 
-Example matches x, but not y, z, or a.
-(matcher = varDecl(hasAutomaticStorageDuration())
+Given
 void f() {
   int x;
   static int y;
   thread_local int z;
 }
 int a;
+
+The matcher varDecl(hasAutomaticStorageDuration())
+matches x
+but does not match y, z or
+a
 
Matcher<VarDecl>hasGlobalStorage
Matches a variable declaration that does not have local storage.
 
-Example matches y and z (matcher = varDecl(hasGlobalStorage())
+Given
 void f() {
   int x;
   static int y;
 }
 int z;
+The matcher varDecl(hasGlobalStorage())
+matches y and z
 
@@ -5917,12 +7972,14 @@

Narrowing Matchers

Matches a variable declaration that has function scope and is a
 non-static local variable.
 
-Example matches x (matcher = varDecl(hasLocalStorage())
+Given
 void f() {
   int x;
   static int y;
 }
 int z;
+The matcher varDecl(hasLocalStorage())
+matches x
 
@@ -5939,22 +7996,28 @@

Narrowing Matchers

int a; static int b; extern int c; -varDecl(hasStaticStorageDuration()) - matches the function declaration y, a, b and c. + +The matcher varDecl(hasStaticStorageDuration()) +matches y, a, b and +c Matcher<VarDecl>hasThreadStorageDuration
Matches a variable declaration that has thread storage duration.
 
-Example matches z, but not x, z, or a.
-(matcher = varDecl(hasThreadStorageDuration())
+Given
 void f() {
   int x;
   static int y;
   thread_local int z;
 }
 int a;
+
+The matcher varDecl(hasThreadStorageDuration())
+matches z
+but does not match x, z or
+a
 
@@ -5962,29 +8025,34 @@

Narrowing Matchers

Matches constexpr variable and function declarations,
        and if constexpr.
 
-Given:
+Given
   constexpr int foo = 42;
   constexpr int bar();
   void baz() { if constexpr(1 > 0) {} }
-varDecl(isConstexpr())
-  matches the declaration of foo.
-functionDecl(isConstexpr())
-  matches the declaration of bar.
-ifStmt(isConstexpr())
-  matches the if statement in baz.
+
+The matcher varDecl(isConstexpr())
+matches foo.
+The matcher functionDecl(isConstexpr())
+matches bar.
+The matcher ifStmt(isConstexpr())
+matches if constexpr(1 > 0) {}.
 
Matcher<VarDecl>isConstinit
Matches constinit variable declarations.
 
-Given:
+Given
   constinit int foo = 42;
   constinit const char* bar = "bar";
   int baz = 42;
   [[clang::require_constant_initialization]] int xyz = 42;
-varDecl(isConstinit())
-  matches the declaration of `foo` and `bar`, but not `baz` and `xyz`.
+
+The matcher varDecl(isConstinit())
+matches the declaration of foo
+and bar,
+but does not match baz or
+xyz.
 
@@ -5998,6 +8066,14 @@

Narrowing Matchers

extern int vb; // Doesn't match, as it doesn't define the variable. void fa() {} void fb(); // Doesn't match, as it has no body. + +The matcher tagDecl(isDefinition()) +matches A +The matcher varDecl(isDefinition()) +matches va +The matcher functionDecl(isDefinition()) +matches fa + @interface X - (void)ma; // Doesn't match, interface is declaration. @end @@ -6005,6 +8081,9 @@

Narrowing Matchers

- (void)ma {} @end +The matcher objcMethodDecl(isDefinition()) +matches - (void)ma {} + Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>, Matcher<ObjCMethodDecl> @@ -6014,12 +8093,15 @@

Narrowing Matchers

Matches a variable declaration that is an exception variable from
 a C++ catch block, or an Objective-C statement.
 
-Example matches x (matcher = varDecl(isExceptionVariable())
+Given
 void f(int y) {
   try {
   } catch (int x) {
   }
 }
+
+The matcher varDecl(isExceptionVariable())
+matches x
 
@@ -6030,8 +8112,9 @@

Narrowing Matchers

Given template<typename T> void A(T t) { } template<> void A(int N) { } -functionDecl(isExplicitTemplateSpecialization()) - matches the specialization A<int>(). + +The matcher functionDecl(isExplicitTemplateSpecialization()) + matches the specialization template<> void A(int N) { }. Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> @@ -6040,17 +8123,21 @@

Narrowing Matchers

Matcher<VarDecl>isExternC
Matches extern "C" function or variable declarations.
 
-Given:
+Given
   extern "C" void f() {}
   extern "C" { void g() {} }
   void h() {}
   extern "C" int x = 1;
   extern "C" int y = 2;
   int z = 3;
-functionDecl(isExternC())
-  matches the declaration of f and g, but not the declaration of h.
-varDecl(isExternC())
-  matches the declaration of x and y, but not the declaration of z.
+
+The matcher functionDecl(isExternC())
+matches f
+and g.
+The matcher varDecl(isExternC())
+matches x
+and y,
+but does not match z.
 
@@ -6058,8 +8145,11 @@

Narrowing Matchers

Matches a variable serving as the implicit variable for a lambda init-
 capture.
 
-Example matches x (matcher = varDecl(isInitCapture()))
-auto f = [x=3]() { return x; };
+Given
+auto f = [x = 3]() { return x; };
+
+The matcher varDecl(isInitCapture())
+matches x = 3.
 
@@ -6074,21 +8164,24 @@

Narrowing Matchers

inline namespace m {} } inline int Foo = 5; -functionDecl(isInline()) will match ::f(). -namespaceDecl(isInline()) will match n::m. -varDecl(isInline()) will match Foo; + +The matcher functionDecl(isInline()) matches f. +The matcher namespaceDecl(isInline()) matches m. +The matcher varDecl(isInline()) matches Foo Matcher<VarDecl>isStaticLocal
Matches a static variable with local scope.
 
-Example matches y (matcher = varDecl(isStaticLocal()))
+Given
 void f() {
   int x;
   static int y;
 }
 static int z;
+The matcher varDecl(isStaticLocal())
+matches y
 
@@ -6096,15 +8189,15 @@

Narrowing Matchers

Matches variable/function declarations that have "static" storage
 class specifier ("static" keyword) written in the source.
 
-Given:
+Given
   static void f() {}
   static int i = 0;
   extern int j;
   int k;
-functionDecl(isStaticStorageClass())
-  matches the function declaration f.
-varDecl(isStaticStorageClass())
-  matches the variable declaration i.
+The matcher functionDecl(isStaticStorageClass())
+  matches f
+The matcher varDecl(isStaticStorageClass())
+  matches i
 
@@ -6113,18 +8206,36 @@

Narrowing Matchers

member variable template instantiations. Given - template <typename T> class X {}; class A {}; X<A> x; -or - template <typename T> class X {}; class A {}; template class X<A>; -or - template <typename T> class X {}; class A {}; extern template class X<A>; -cxxRecordDecl(hasName("::X"), isTemplateInstantiation()) - matches the template instantiation of X<A>. + template <typename T> class X {}; + class A {}; + X<A> x; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches class X<class A>. + template <typename T> class X {}; + class A {}; + template class X<A>; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches template class X<A> + template <typename T> class X {}; + class A {}; + extern template class X<A>; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) +matches extern template class X<A> But given - template <typename T> class X {}; class A {}; - template <> class X<A> {}; X<A> x; -cxxRecordDecl(hasName("::X"), isTemplateInstantiation()) + template <typename T> class X {}; + class A {}; + template <> class X<A> {}; + X<A> x; + +The matcher cxxRecordDecl(hasName("::X"), +isTemplateInstantiation()) does not match, as X<A> is an explicit template specialization. Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl> @@ -6151,10 +8262,9 @@

AST Traversal Matchers

Matcher<*>binaryOperationMatcher<*>...Matcher<*>
Matches nodes which can be used with binary operators.
 
-The code
-  var1 != var2;
-might be represented in the clang AST as a binaryOperator, a
-cxxOperatorCallExpr or a cxxRewrittenBinaryOperator, depending on
+A comparison of two expressions might be represented in the clang AST as a
+binaryOperator, a cxxOperatorCallExpr or a
+cxxRewrittenBinaryOperator, depending on
 
 * whether the types of var1 and var2 are fundamental (binaryOperator) or at
   least one is a class type (cxxOperatorCallExpr)
@@ -6168,12 +8278,6 @@ 

AST Traversal Matchers

compatible. Given - binaryOperation( - hasOperatorName("!="), - hasLHS(expr().bind("lhs")), - hasRHS(expr().bind("rhs")) - ) -matches each use of "!=" in: struct S{ bool operator!=(const S&) const; }; @@ -6187,25 +8291,28 @@

AST Traversal Matchers

template<typename T> void templ() { - 1 != 2; + 3 != 4; T() != S(); } struct HasOpEq { - bool operator==(const HasOpEq &) const; + friend bool + operator==(const HasOpEq &, const HasOpEq&) noexcept = default; }; void inverse() { - HasOpEq s1; - HasOpEq s2; - if (s1 != s2) + HasOpEq e1; + HasOpEq e2; + if (e1 != e2) return; } struct HasSpaceship { - bool operator<=>(const HasOpEq &) const; + friend bool + operator<=>(const HasSpaceship &, + const HasSpaceship&) noexcept = default; }; void use_spaceship() @@ -6215,6 +8322,15 @@

AST Traversal Matchers

if (s1 != s2) return; } + + +The matcher binaryOperation( + hasOperatorName("!="), + hasLHS(expr().bind("lhs")), + hasRHS(expr().bind("rhs")) + ) +matches 1 != 2, S() != S(), 3 != 4, +T() != S(), e1 != e2 and s1 != s2.
@@ -6224,14 +8340,18 @@

AST Traversal Matchers

Unlike anyOf, eachOf will generate a match result for each matching submatcher. -For example, in: - class A { int a; int b; }; -The matcher: - cxxRecordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")), - has(fieldDecl(hasName("b")).bind("v")))) -will generate two results binding "v", the first of which binds -the field declaration of a, the second the field declaration of -b. +Given + void f(int a, int b); + + +The matcher functionDecl(hasAnyParameter( +eachOf(parmVarDecl(hasName("a")).bind("v"), + parmVarDecl(hasName("b")).bind("v")))) +matches void f(int a, int b), +with parmVarDecl(hasName("a")) matching a +for one match, +and with parmVarDecl(hasName("b")) matching +b for the other match. Usable as: Any Matcher @@ -6244,10 +8364,14 @@

AST Traversal Matchers

For example, in: class A { class B {}; class C {}; }; -The matcher: - cxxRecordDecl(hasName("::A"), + +The matcher +cxxRecordDecl(hasName("::A"), findAll(cxxRecordDecl(isDefinition()).bind("m"))) -will generate results for A, B and C. +matches A three times, +with cxxRecordDecl(isDefinition()).bind("m") +matching A, +B and C. Usable as: Any Matcher @@ -6257,24 +8381,71 @@

AST Traversal Matchers

Matches AST nodes that have descendant AST nodes that match the
 provided matcher.
 
-Example matches X, A, A::X, B, B::C, B::C::X
-  (matcher = cxxRecordDecl(forEachDescendant(cxxRecordDecl(hasName("X")))))
+Given
   class X {};
   class A { class X {}; };  // Matches A, because A::X is a class of name
                             // X inside A.
   class B { class C { class X {}; }; };
 
+The matcher
+cxxRecordDecl(forEachDescendant(cxxRecordDecl(hasName("X"))))
+matches X, A,
+B, class B::C
+and class B::C::X
+
 DescendantT must be an AST base type.
 
 As opposed to 'hasDescendant', 'forEachDescendant' will cause a match for
 each result that matches instead of only on the first one.
 
 Note: Recursively combined ForEachDescendant can cause many matches:
-  cxxRecordDecl(forEachDescendant(cxxRecordDecl(
-    forEachDescendant(cxxRecordDecl())
-  )))
-will match 10 times (plus injected class name matches) on:
-  class A { class B { class C { class D { class E {}; }; }; }; };
+  struct A {
+    struct B {
+      struct C {};
+      struct D {};
+    };
+  };
+
+
+The matcher cxxRecordDecl(forEachDescendant(cxxRecordDecl(
+    forEachDescendant(cxxRecordDecl().bind("inner"))
+  ).bind("middle")))
+will match 9 times:
+It matches the definition of A with the definition of
+B in the middle and the injected class name of
+B as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+C in the middle and the definition of
+B as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+C in the middle and the injected class name of
+B as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+B in the middle and the definition of
+D as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+B in the middle and the injected class name of
+D as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+C in the middle and the injected class name of
+C as the innermost cxxRecordDecl.
+
+It matches the definition of A with the definition of
+D in the middle and the injected class name of
+D as the innermost cxxRecordDecl.
+
+It matches the definition of B with the definition of
+C in the middle and the injected class name of
+C as the innermost cxxRecordDecl.
+
+It matches the definition of B with the definition of
+D in the middle and the injected class name of
+D as the innermost cxxRecordDecl.
 
 Usable as: Any Matcher
 
@@ -6284,17 +8455,22 @@

AST Traversal Matchers

Matches AST nodes that have child AST nodes that match the
 provided matcher.
 
-Example matches X, Y, Y::X, Z::Y, Z::Y::X
-  (matcher = cxxRecordDecl(forEach(cxxRecordDecl(hasName("X")))
+Given
   class X {};
   class Y { class X {}; };  // Matches Y, because Y::X is a class of name X
                             // inside Y.
   class Z { class Y { class X {}; }; };  // Does not match Z.
 
+The matcher cxxRecordDecl(forEach(cxxRecordDecl(hasName("X"))))
+matches class X,
+class Y,
+class Y::X,
+class Z::Y::X and class Z::Y
+
 ChildT must be an AST base type.
 
 As opposed to 'has', 'forEach' will cause a match for each result that
-matches instead of only on the first one.
+  matches instead of only on the first one.
 
 Usable as: Any Matcher
 
@@ -6307,7 +8483,10 @@

AST Traversal Matchers

Given void f() { if (true) { int x = 42; } } void g() { for (;;) { int x = 43; } } -expr(integerLiteral(hasAncestor(ifStmt()))) matches 42, but not 43. + +The matcher expr(integerLiteral(hasAncestor(ifStmt()))) +matches 42 +but does not match 43 Usable as: Any Matcher @@ -6317,12 +8496,16 @@

AST Traversal Matchers

Matches AST nodes that have descendant AST nodes that match the
 provided matcher.
 
-Example matches X, Y, Z
-    (matcher = cxxRecordDecl(hasDescendant(cxxRecordDecl(hasName("X")))))
+Given
   class X {};  // Matches X, because X::X is a class of name X inside X.
   class Y { class X {}; };
   class Z { class Y { class X {}; }; };
 
+The matcher
+cxxRecordDecl(hasDescendant(cxxRecordDecl(hasName("X"))))
+matches class X {}, class Y { class X {}; }
+and class Z { class Y { class X {}; }; }.
+
 DescendantT must be an AST base type.
 
 Usable as: Any Matcher
@@ -6333,19 +8516,29 @@ 

AST Traversal Matchers

Matches AST nodes that have child AST nodes that match the
 provided matcher.
 
-Example matches X, Y
-  (matcher = cxxRecordDecl(has(cxxRecordDecl(hasName("X")))
+Given
   class X {};  // Matches X, because X::X is a class of name X inside X.
   class Y { class X {}; };
   class Z { class Y { class X {}; }; };  // Does not match Z.
 
+The matcher cxxRecordDecl(has(cxxRecordDecl(hasName("X"))))
+matches class X {} three times,
+and class Y { class X {}; } two times.
+
 ChildT must be an AST base type.
 
 Usable as: Any Matcher
 Note that has is direct matcher, so it also matches things like implicit
 casts and paren casts. If you are matching with expr then you should
-probably consider using ignoringParenImpCasts like:
-has(ignoringParenImpCasts(expr())).
+probably consider using ignoringParenImpCasts:
+
+Given
+  int x =0;
+  double y = static_cast<double>(x);
+
+The matcher
+cxxStaticCastExpr(has(ignoringParenImpCasts(declRefExpr()))).
+matches static_cast<double>(x)
 
@@ -6355,7 +8548,9 @@

AST Traversal Matchers

Given void f() { for (;;) { int x = 42; if (true) { int x = 43; } } } -compoundStmt(hasParent(ifStmt())) matches "{ int x = 43; }". + +The matcher compoundStmt(hasParent(ifStmt())) +matches { int x = 43; } Usable as: Any Matcher
@@ -6369,7 +8564,7 @@

AST Traversal Matchers

which should match both are typically duplicated. This matcher removes the need for duplication. -Given code +Given struct ConstructorTakesInt { ConstructorTakesInt(int i) {} @@ -6389,9 +8584,11 @@

AST Traversal Matchers

ConstructorTakesInt cti(42); } + The matcher -invocation(hasArgument(0, integerLiteral(equals(42)))) -matches the expression in both doCall and doConstruct +expr(invocation(hasArgument(0, integerLiteral(equals(42))))) +matches the expressions callTakesInt(42) +and cti(42). @@ -6402,18 +8599,12 @@

AST Traversal Matchers

Useful when additional information which may or may not present about a main matching node is desired. -For example, in: - class Foo { - int bar; - } -The matcher: - cxxRecordDecl( - optionally(has( - fieldDecl(hasName("bar")).bind("var") - ))).bind("record") -will produce a result binding for both "record" and "var". -The matcher will produce a "record" binding for even if there is no data -member named "bar" in that class. +Given + int a = 0; + int b; + +The matcher varDecl(optionally(hasInitializer(expr()))) +matches int a = 0 and int b. Usable as: Any Matcher @@ -6428,10 +8619,10 @@

AST Traversal Matchers

int i = 3.0; } The matcher - traverse(TK_IgnoreUnlessSpelledInSource, +traverse(TK_IgnoreUnlessSpelledInSource, varDecl(hasInitializer(floatLiteral().bind("init"))) ) -matches the variable declaration with "init" bound to the "3.0". + matches int i = 3.0 with "init" bound to 3.0. @@ -6439,8 +8630,13 @@

AST Traversal Matchers

Matches the condition expression of an if statement, for loop,
 switch statement or conditional operator.
 
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
   if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
 
@@ -6449,8 +8645,19 @@

AST Traversal Matchers

(binary or ternary). Example matches b - condition ? a : b - condition ?: b + void foo(bool condition, int a, int b) { + condition ? a : b; + condition ?: b; + } + +The matcher +conditionalOperator(hasFalseExpression(expr().bind("false"))) +matches condition ? a : b, +with expr() matching b. +The matcher +binaryConditionalOperator(hasFalseExpression(expr().bind("false"))) +matches condition ?: b, +with expr() matching b. @@ -6458,16 +8665,31 @@

AST Traversal Matchers

Matches the true branch expression of a conditional operator.
 
 Example 1 (conditional ternary operator): matches a
-  condition ? a : b
+Given
+  void foo(bool condition, int a, int b) {
+    condition ? a : b;
+  }
+
+The matcher
+conditionalOperator(hasTrueExpression(expr().bind("true")))
+matches condition ? a : b,
+with expr() matching a.
 
 Example 2 (conditional binary operator): matches opaqueValueExpr(condition)
-  condition ?: b
+Given
+  void foo(bool condition, int a, int b) {
+    condition ?: b;
+  }
+
+The matcher binaryConditionalOperator(hasTrueExpression(expr()))
+matches condition ?: b,
+with expr() matching conditoin.
 
Matcher<AddrLabelExpr>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -6477,17 +8699,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -6505,7 +8735,7 @@

AST Traversal Matchers

Given int i[5]; void f() { i[1] = 42; } -arraySubscriptExpression(hasBase(implicitCastExpr( +The matcher arraySubscriptExpr(hasBase(implicitCastExpr( hasSourceExpression(declRefExpr())))) matches i[1] with the declRefExpr() matching i
@@ -6517,7 +8747,7 @@

AST Traversal Matchers

Given int i[5]; void f() { i[1] = 42; } -arraySubscriptExpression(hasIndex(integerLiteral())) +The matcher arraySubscriptExpr(hasIndex(integerLiteral())) matches i[1] with the integerLiteral() matching 1 @@ -6525,16 +8755,30 @@

AST Traversal Matchers

Matcher<ArraySubscriptExpr>hasLHSMatcher<Expr> InnerMatcher
Matches the left hand side of binary operator expressions.
 
-Example matches a (matcher = binaryOperator(hasLHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
 
Matcher<ArraySubscriptExpr>hasRHSMatcher<Expr> InnerMatcher
Matches the right hand side of binary operator expressions.
 
-Example matches b (matcher = binaryOperator(hasRHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
 
@@ -6546,8 +8790,10 @@

AST Traversal Matchers

struct A {}; A a[7]; int b[7]; -arrayType(hasElementType(builtinType())) - matches "int b[7]" + + +The matcher arrayType(hasElementType(builtinType())) +int[7] Usable as: Matcher<ArrayType>, Matcher<ComplexType> @@ -6559,8 +8805,8 @@

AST Traversal Matchers

Given _Atomic(int) i; _Atomic(float) f; -atomicType(hasValueType(isInteger())) - matches "_Atomic(int) i" +The matcher atomicType(hasValueType(isInteger())) +_Atomic(int). Usable as: Matcher<AtomicType> @@ -6575,8 +8821,10 @@

AST Traversal Matchers

Given auto a = 1; auto b = 2.0; -autoType(hasDeducedType(isInteger())) - matches "auto a" + +The matcher +varDecl(hasType(autoType(hasDeducedType(isInteger())))) +matches auto a = 1, but does not match auto b = 2.0. Usable as: Matcher<AutoType> @@ -6588,21 +8836,54 @@

AST Traversal Matchers

Given namespace X { void b(); } using X::b; -usingDecl(hasAnyUsingShadowDecl(hasName("b")))) - matches using X::b + +The matcher usingDecl(hasAnyUsingShadowDecl(hasName("b"))) + matches using X::b + Matcher<BinaryOperator>hasEitherOperandMatcher<Expr> InnerMatcher
Matches if either the left hand side or the right hand side of a
 binary operator or fold expression matches.
+
+Given
+  struct S {};
+  bool operator ==(const S&, const S&);
+
+  void f(int a, const S&lhs, const S&rhs) {
+      a + 0;
+      lhs == rhs;
+      lhs != rhs;
+  }
+
+  template <typename ...Ts>
+  auto sum(Ts... args) {
+    return (0 + ... + args);
+  }
+
+
+The matcher binaryOperator(hasEitherOperand(integerLiteral()))
+matches a + 0.
+The matcher cxxOperatorCallExpr(hasEitherOperand(declRefExpr(to(
+parmVarDecl(hasName("lhs")))))) matches lhs == rhs and
+lhs != rhs.
+The matcher cxxFoldExpr(hasEitherOperand(integerLiteral()))
+matches (0 + ... + args).
 
Matcher<BinaryOperator>hasLHSMatcher<Expr> InnerMatcher
Matches the left hand side of binary operator expressions.
 
-Example matches a (matcher = binaryOperator(hasLHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
 
@@ -6610,27 +8891,40 @@

AST Traversal Matchers

Matches if both matchers match with opposite sides of the binary operator
 or fold expression.
 
-Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1),
-                                             integerLiteral(equals(2)))
-  1 + 2 // Match
-  2 + 1 // Match
-  1 + 1 // No match
-  2 + 2 // No match
+Given
+void foo() {
+  1 + 2; // Match
+  2 + 1; // Match
+  1 + 1; // No match
+  2 + 2; // No match
+}
+The matcher binaryOperator(hasOperands(integerLiteral(equals(1)),
+                                            integerLiteral(equals(2))))
+matches 1 + 2 and 2 + 1,
+but does not match 1 + 1
+or 2 + 2.
 
Matcher<BinaryOperator>hasRHSMatcher<Expr> InnerMatcher
Matches the right hand side of binary operator expressions.
 
-Example matches b (matcher = binaryOperator(hasRHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
 
Matcher<BindingDecl>forDecompositionMatcher<ValueDecl> InnerMatcher
Matches the DecompositionDecl the binding belongs to.
 
-For example, in:
+Given
 void foo()
 {
     int arr[3];
@@ -6638,10 +8932,10 @@ 

AST Traversal Matchers

f = 42; } -The matcher: - bindingDecl(hasName("f"), - forDecomposition(decompositionDecl()) -matches 'f' in 'auto &[f, s, t]'. + +The matcher bindingDecl(hasName("f"), + forDecomposition(decompositionDecl())) +matches f in 'auto &[f, s, t]'.
@@ -6653,23 +8947,26 @@

AST Traversal Matchers

Given class X { void f(int x, int y, int z) {} }; -cxxMethodDecl(hasAnyParameter(hasName("y"))) - matches f(int x, int y, int z) {} + +The matcher cxxMethodDecl(hasAnyParameter(hasName("y"))) + matches f with hasAnyParameter(...) matching int y For ObjectiveC, given @interface I - (void) f:(int) y; @end + the matcher objcMethodDecl(hasAnyParameter(hasName("y"))) -matches the declaration of method f with hasParameter + matches the declaration of method f with hasParameter matching y. For blocks, given b = ^(int y) { printf("%d", y) }; + the matcher blockDecl(hasAnyParameter(hasName("y"))) -matches the declaration of the block b with hasParameter + matches the declaration of the block b with hasParameter matching y. @@ -6680,15 +8977,18 @@

AST Traversal Matchers

Given class X { void f(int x) {} }; -cxxMethodDecl(hasParameter(0, hasType(varDecl()))) - matches f(int x) {} + +The matcher +cxxMethodDecl(hasParameter(0, hasType(asString("int")))) +matches f with hasParameter(...) - matching int x +matching int x. For ObjectiveC, given @interface I - (void) f:(int) y; @end -the matcher objcMethodDecl(hasParameter(0, hasName("y"))) + +The matcher objcMethodDecl(hasParameter(0, hasName("y"))) matches the declaration of method f with hasParameter matching y. @@ -6697,19 +8997,26 @@

AST Traversal Matchers

Matcher<BlockDecl>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -6728,10 +9035,14 @@ 

AST Traversal Matchers

Given int *a; - int const *b; - float const *f; -pointerType(pointee(isConstQualified(), isInteger())) - matches "int const *b" + const int *b; + int * const c = nullptr; + const float *f; + +The matcher pointerType(pointee(isConstQualified(), isInteger())) +matches const int *, +but does not match int * const +or const float *. Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>, Matcher<PointerType>, Matcher<ReferenceType> @@ -6741,19 +9052,26 @@

AST Traversal Matchers

Matcher<CXXBaseSpecifier>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -6776,21 +9094,31 @@ 

AST Traversal Matchers

X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the declaration of x. -Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) - and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) - and friend class X (matcher = friendDecl(hasType("X")) - and public virtual X (matcher = cxxBaseSpecifier(hasType( - cxxRecordDecl(hasName("X")))) class X {}; void y(X &x) { x; X z; } class Y { friend class X; }; class Z : public virtual X {}; -Example matches class Derived -(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) +The matcher expr(hasType(cxxRecordDecl(hasName("X")))) +matches x and z. +The matcher varDecl(hasType(cxxRecordDecl(hasName("X")))) +matches z. +The matcher friendDecl(hasType(asString("class X"))) +matches friend class X. +The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType( +asString("X"))).bind("b"))) matches +class Z : public virtual X {}, +with cxxBaseSpecifier(...) +matching public virtual X. + +Given class Base {}; class Derived : Base {}; +The matcher +cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))) +matches class Derived : Base {}. + Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>, Matcher<CXXBaseSpecifier>
@@ -6800,17 +9128,25 @@

AST Traversal Matchers

Matches if the expression's or declaration's type matches a type
 matcher.
 
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
-            and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
-            and U (matcher = typedefDecl(hasType(asString("int")))
-            and friend class X (matcher = friendDecl(hasType("X"))
-            and public virtual X (matcher = cxxBaseSpecifier(hasType(
-                                              asString("class X")))
+Exmaple
  class X {};
  void y(X &x) { x; X z; }
  typedef int U;
  class Y { friend class X; };
  class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
 
@@ -6820,8 +9156,10 @@

AST Traversal Matchers

Given void f(int i); int y; - f(y); -callExpr( + void foo() { + f(y); + } +The matcher callExpr( forEachArgumentWithParam( declRefExpr(to(varDecl(hasName("y")))), parmVarDecl(hasType(isInteger())) @@ -6844,14 +9182,15 @@

AST Traversal Matchers

Given void f(int i); - int y; - f(y); - void (*f_ptr)(int) = f; - f_ptr(y); -callExpr( + void foo(int y) { + f(y); + void (*f_ptr)(int) = f; + f_ptr(y); + } +The matcher callExpr( forEachArgumentWithParamType( declRefExpr(to(varDecl(hasName("y")))), - qualType(isInteger()).bind("type) + qualType(isInteger()).bind("type") )) matches f(y) and f_ptr(y) with declRefExpr(...) @@ -6866,17 +9205,19 @@

AST Traversal Matchers

expression, or an ObjC-message-send expression. Given - void x(int, int, int) { int y; x(1, y, 42); } -callExpr(hasAnyArgument(declRefExpr())) - matches x(1, y, 42) -with hasAnyArgument(...) + void x(int, int, int) { int y = 42; x(1, y, 42); } +The matcher +callExpr(hasAnyArgument(ignoringImplicit(declRefExpr()))) matches +x(1, y, 42) with hasAnyArgument(...) matching y For ObjectiveC, given @interface I - (void) f:(int) y; @end void foo(I *i) { [i f:12]; } + +The matcher objcMessageExpr(hasAnyArgument(integerLiteral(equals(12)))) - matches [i f:12] +matches [i f:12]
@@ -6884,15 +9225,17 @@

AST Traversal Matchers

Matches the n'th argument of a call expression or a constructor
 call expression.
 
-Example matches y in x(y)
-    (matcher = callExpr(hasArgument(0, declRefExpr())))
+Given
   void x(int) { int y; x(y); }
+The matcher callExpr(hasArgument(0, declRefExpr().bind("arg")))
+matches x(y),
+with declRefExpr() matching y.
 
Matcher<CXXConstructExpr>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -6902,17 +9245,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -6929,10 +9280,12 @@

AST Traversal Matchers

Given class A { A() : i(42), j(42) {} int i; int j; }; -cxxConstructorDecl(forEachConstructorInitializer( - forField(decl().bind("x")) -)) - will trigger two matches, binding for 'i' and 'j' respectively. + +The matcher cxxConstructorDecl(forEachConstructorInitializer( + forField(fieldDecl().bind("x")))) +matches the constructor of A twice, with +fieldDecl() matching i and +j respectively.
@@ -6944,10 +9297,11 @@

AST Traversal Matchers

Foo() : foo_(1) { } int foo_; }; -cxxRecordDecl(has(cxxConstructorDecl( + +The matcher cxxRecordDecl(has(cxxConstructorDecl( hasAnyConstructorInitializer(anything()) ))) - record matches Foo, hasAnyConstructorInitializer matches foo_(1) +matches Foo, hasAnyConstructorInitializer matches foo_(1) @@ -6959,9 +9313,11 @@

AST Traversal Matchers

Foo() : foo_(1) { } int foo_; }; + +The matcher cxxRecordDecl(has(cxxConstructorDecl(hasAnyConstructorInitializer( forField(hasName("foo_")))))) - matches Foo +matches Foo with forField matching foo_ @@ -6969,19 +9325,26 @@

AST Traversal Matchers

Matcher<CXXCtorInitializer>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -7002,9 +9365,11 @@ 

AST Traversal Matchers

Foo() : foo_(1) { } int foo_; }; + +The matcher cxxRecordDecl(has(cxxConstructorDecl(hasAnyConstructorInitializer( withInitializer(integerLiteral(equals(1))))))) - matches Foo +matches Foo with withInitializer matching (1)
@@ -7019,11 +9384,14 @@

AST Traversal Matchers

int m; int f(X x) { x.m; return m; } }; + + +The matcher memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X"))))) - matches `x.m`, but not `m`; however, -memberExpr(hasObjectExpression(hasType(pointsTo( - cxxRecordDecl(hasName("X")))))) - matches `m` (aka. `this->m`), but not `x.m`. +matches x.m, but not m; however, +The matcher memberExpr(hasObjectExpression(hasType(pointsTo( +cxxRecordDecl(hasName("X")))))) +matches m (aka. this->m), but not x.m. @@ -7033,12 +9401,20 @@

AST Traversal Matchers

Given class Y { void x() { this->x(); x(); Y y; y.x(); } }; void f() { f(); } -callExpr(callee(expr())) - matches this->x(), x(), y.x(), f() -with callee(...) - matching this->x, x, y.x, f respectively + +The matcher callExpr(callee(expr().bind("callee"))) +matches this->x(), x(), y.x(), f() +with expr() inside of callee +matching this->x, x, +y.x, f respectively Given + struct Dummy {}; + // makes sure there is a callee, otherwise there would be no callee, + // just a builtin operator + Dummy operator+(Dummy, Dummy); + // not defining a '*' operator + template <typename... Args> auto sum(Args... args) { return (0 + ... + args); @@ -7048,10 +9424,14 @@

AST Traversal Matchers

auto multiply(Args... args) { return (args * ... * 1); } -cxxFoldExpr(callee(expr())) - matches (args * ... * 1) -with callee(...) - matching * + +The matcher cxxFoldExpr(callee(expr().bind("op"))) +matches (0 + ... + args) +with callee(...) matching *, +but does not match (args * ... * 1). +A CXXFoldExpr only has an UnresolvedLookupExpr as a callee. +When there are no define operators that could be used instead of builtin +ones, then there will be no callee . Note: Callee cannot take the more general internal::Matcher<Expr> because this introduces ambiguous overloads with calls to Callee taking a @@ -7063,16 +9443,37 @@

AST Traversal Matchers

Matcher<CXXFoldExpr>hasEitherOperandMatcher<Expr> InnerMatcher
Matches if either the left hand side or the right hand side of a
 binary operator or fold expression matches.
+
+Given
+  struct S {};
+  bool operator ==(const S&, const S&);
+
+  void f(int a, const S&lhs, const S&rhs) {
+      a + 0;
+      lhs == rhs;
+      lhs != rhs;
+  }
+
+  template <typename ...Ts>
+  auto sum(Ts... args) {
+    return (0 + ... + args);
+  }
+
+
+The matcher binaryOperator(hasEitherOperand(integerLiteral()))
+matches a + 0.
+The matcher cxxOperatorCallExpr(hasEitherOperand(declRefExpr(to(
+parmVarDecl(hasName("lhs")))))) matches lhs == rhs and
+lhs != rhs.
+The matcher cxxFoldExpr(hasEitherOperand(integerLiteral()))
+matches (0 + ... + args).
 
Matcher<CXXFoldExpr>hasFoldInitMatcher<Expr> InnerMacher
Matches the operand that does not contain the parameter pack.
 
-Example matches `(0 + ... + args)` and `(args * ... * 1)`
-    (matcher = cxxFoldExpr(hasFoldInit(expr())))
-  with hasFoldInit(...)
-    matching `0` and `1` respectively
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
@@ -7082,14 +9483,27 @@ 

AST Traversal Matchers

auto multiply(Args... args) { return (args * ... * 1); } + + +The matcher cxxFoldExpr(hasFoldInit(expr().bind("init"))) +matches (0 + ... + args) and (args * ... * 1) +with hasFoldInit(expr().bind("init")) matching +0 and 1.
Matcher<CXXFoldExpr>hasLHSMatcher<Expr> InnerMatcher
Matches the left hand side of binary operator expressions.
 
-Example matches a (matcher = binaryOperator(hasLHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
 
@@ -7097,22 +9511,25 @@

AST Traversal Matchers

Matches if both matchers match with opposite sides of the binary operator
 or fold expression.
 
-Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1),
-                                             integerLiteral(equals(2)))
-  1 + 2 // Match
-  2 + 1 // Match
-  1 + 1 // No match
-  2 + 2 // No match
+Given
+void foo() {
+  1 + 2; // Match
+  2 + 1; // Match
+  1 + 1; // No match
+  2 + 2; // No match
+}
+The matcher binaryOperator(hasOperands(integerLiteral(equals(1)),
+                                            integerLiteral(equals(2))))
+matches 1 + 2 and 2 + 1,
+but does not match 1 + 1
+or 2 + 2.
 
Matcher<CXXFoldExpr>hasPatternMatcher<Expr> InnerMacher
Matches the operand that contains the parameter pack.
 
-Example matches `(0 + ... + args)`
-    (matcher = cxxFoldExpr(hasPattern(expr())))
-  with hasPattern(...)
-    matching `args`
+Given
   template <typename... Args>
   auto sum(Args... args) {
       return (0 + ... + args);
@@ -7122,14 +9539,27 @@ 

AST Traversal Matchers

auto multiply(Args... args) { return (args * ... * 1); } + + +The matcher cxxFoldExpr(hasPattern(expr().bind("pattern"))) +matches (0 + ... + args) and (args * ... * 1), +with hasPattern(expr().bind("pattern")) matching +args two times.
Matcher<CXXFoldExpr>hasRHSMatcher<Expr> InnerMatcher
Matches the right hand side of binary operator expressions.
 
-Example matches b (matcher = binaryOperator(hasRHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
 
@@ -7140,27 +9570,32 @@

AST Traversal Matchers

other declarations of the same function or coroutine. Given +void foo() { for (;;) {} -forStmt(hasBody(compoundStmt())) - matches 'for (;;) {}' +} +The matcher forStmt(hasBody(compoundStmt().bind("body"))) +matches for (;;) {} with compoundStmt() - matching '{}' + matching {} Given void f(); void f() {} -functionDecl(hasBody(compoundStmt())) - matches 'void f() {}' +The matcher functionDecl(hasBody(compoundStmt().bind("compound"))) +f with compoundStmt() - matching '{}' - but does not match 'void f();' +matching {} +but does not match void f(); Matcher<CXXForRangeStmt>hasInitStatementMatcher<Stmt> InnerMatcher
Matches selection statements with initializer.
 
-Given:
+Given
+ struct vec { int* begin(); int* end(); };
+ int foobar();
+ vec& get_range();
  void foo() {
    if (int i = foobar(); i > 0) {}
    switch (int i = foobar(); i) {}
@@ -7171,51 +9606,71 @@ 

AST Traversal Matchers

switch (foobar()) {} for (auto& x : get_range()) {} } -ifStmt(hasInitStatement(anything())) - matches the if statement in foo but not in bar. -switchStmt(hasInitStatement(anything())) - matches the switch statement in foo but not in bar. -cxxForRangeStmt(hasInitStatement(anything())) - matches the range for statement in foo but not in bar. + +The matcher ifStmt(hasInitStatement(anything())) + matches the if statement if (int i = foobar(); i > 0) {} + in foo but not if (foobar() > 0) {} in bar. +The matcher switchStmt(hasInitStatement(anything())) + matches the switch statement switch (int i = foobar(); i) {} + in foo but not switch (foobar()) {} in bar. +The matcher cxxForRangeStmt(hasInitStatement(anything())) + matches the range for statement + for (auto& a = get_range(); auto& x : a) {} in foo + but not for (auto& x : get_range()) {} in bar.
Matcher<CXXForRangeStmt>hasLoopVariableMatcher<VarDecl> InnerMatcher
Matches the initialization statement of a for loop.
 
-Example:
-    forStmt(hasLoopVariable(anything()))
-matches 'int x' in
+Given
+  void foo() {
+    int a[42] = {};
     for (int x : a) { }
+  }
+
+The matcher cxxForRangeStmt(hasLoopVariable(anything()))
+matches for (int x : a) { }
 
Matcher<CXXForRangeStmt>hasRangeInitMatcher<Expr> InnerMatcher
Matches the range initialization statement of a for loop.
 
-Example:
-    forStmt(hasRangeInit(anything()))
-matches 'a' in
+Given
+  void foo() {
+    int a[42] = {};
     for (int x : a) { }
+  }
+
+The matcher cxxForRangeStmt(hasRangeInit(anything()))
+matches for (int x : a) { }
 
Matcher<CXXFunctionalCastExpr>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -7235,13 +9690,16 @@ 

AST Traversal Matchers

Given class Y { public: void m(); }; Y g(); - class X : public Y { void g(); }; + class X : public Y { public: void g(); }; void z(Y y, X x) { y.m(); x.m(); x.g(); (g()).m(); } -cxxMemberCallExpr(onImplicitObjectArgument(hasType( + +The matcher cxxMemberCallExpr(onImplicitObjectArgument(hasType( cxxRecordDecl(hasName("Y"))))) - matches `y.m()`, `x.m()` and (g()).m(), but not `x.g()`. -cxxMemberCallExpr(on(callExpr())) - does not match `(g()).m()`, because the parens are not ignored. +matches y.m(), x.m() and (g()).m() +but does not match x.g(). +The matcher cxxMemberCallExpr(on(callExpr())) +matches (g()).m(), because the parens are ignored. +FIXME: should they be ignored? (ignored bc of `on`) FIXME: Overload to allow directly matching types?
@@ -7256,12 +9714,15 @@

AST Traversal Matchers

Y g(); class X : public Y {}; void z(Y y, X x) { y.m(); (g()).m(); x.m(); } + +The matcher cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y"))))) - matches `y.m()` and `(g()).m()`. + matches y.m() and (g()).m(). +The matcher cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("X"))))) - matches `x.m()`. -cxxMemberCallExpr(on(callExpr())) - matches `(g()).m()`. + matches x.m(). +The matcher cxxMemberCallExpr(on(callExpr())) + matches (g()).m(). FIXME: Overload to allow directly matching types? @@ -7269,24 +9730,35 @@

AST Traversal Matchers

Matcher<CXXMemberCallExpr>thisPointerTypeMatcher<Decl> InnerMatcher
Overloaded to match the type's declaration.
+
+Given
+  class Y { public: void m(); };
+  class X : public Y { public: void g(); };
+  void z() { Y y; y.m(); Y *p; p->m(); X x; x.m(); x.g(); }
+
+The matcher cxxMemberCallExpr(thisPointerType(
+    cxxRecordDecl(hasName("Y"))))
+  matches y.m(), p->m() and x.m().
+The matcher cxxMemberCallExpr(thisPointerType(
+    cxxRecordDecl(hasName("X"))))
+  matches x.g().
 
Matcher<CXXMemberCallExpr>thisPointerTypeMatcher<QualType> InnerMatcher
Matches if the type of the expression's implicit object argument either
-matches the InnerMatcher, or is a pointer to a type that matches the
+  matches the InnerMatcher, or is a pointer to a type that matches the
 InnerMatcher.
 
 Given
-  class Y { public: void m(); };
-  class X : public Y { void g(); };
-  void z() { Y y; y.m(); Y *p; p->m(); X x; x.m(); x.g(); }
-cxxMemberCallExpr(thisPointerType(hasDeclaration(
-    cxxRecordDecl(hasName("Y")))))
-  matches `y.m()`, `p->m()` and `x.m()`.
-cxxMemberCallExpr(thisPointerType(hasDeclaration(
-    cxxRecordDecl(hasName("X")))))
-  matches `x.g()`.
+  class Y { public: void m() const; };
+  class X : public Y { public: void g(); };
+  void z() { const Y y; y.m(); const Y *p; p->m(); X x; x.m(); x.g(); }
+
+The matcher
+cxxMemberCallExpr(thisPointerType(isConstQualified()))
+matches y.m(), x.m() and p->m(),
+but not x.g().
 
@@ -7298,19 +9770,27 @@

AST Traversal Matchers

class A { virtual void f(); }; class B : public A { void f(); }; class C : public B { void f(); }; -cxxMethodDecl(ofClass(hasName("C")), - forEachOverridden(cxxMethodDecl().bind("b"))).bind("d") - matches once, with "b" binding "A::f" and "d" binding "C::f" (Note - that B::f is not overridden by C::f). + +The matcher cxxMethodDecl(ofClass(hasName("C")), + forEachOverridden(cxxMethodDecl().bind("b"))) +matches void f() of C , +with cxxMethodDecl() matching +virtual void f() of A , +but the matcher does not match void f() of B because +it is not overridden by C::f. The check can produce multiple matches in case of multiple inheritance, e.g. class A1 { virtual void f(); }; class A2 { virtual void f(); }; class C : public A1, public A2 { void f(); }; -cxxMethodDecl(ofClass(hasName("C")), - forEachOverridden(cxxMethodDecl().bind("b"))).bind("d") - matches twice, once with "b" binding "A1::f" and "d" binding "C::f", and - once with "b" binding "A2::f" and "d" binding "C::f". + +The matcher cxxMethodDecl(ofClass(hasName("C")), + forEachOverridden(cxxMethodDecl().bind("b"))) +matches void f() of C with the inner +cxxMethodDecl() matching virtual void f() +inside of A1 , and void f() of C with the inner +cxxMethodDecl() matching virtual void f() +inside of A2. @@ -7322,40 +9802,52 @@

AST Traversal Matchers

FIXME: What other kind of declarations would we need to generalize this to? -Example matches A() in the last line - (matcher = cxxConstructExpr(hasDeclaration(cxxMethodDecl( - ofClass(hasName("A")))))) +Given class A { public: A(); + void foo(); }; - A a = A(); + +The matcher cxxMethodDecl(ofClass(hasName("A"))) +matches A() and void foo(). Matcher<CXXNewExpr>hasAnyPlacementArgMatcher<Expr> InnerMatcher
Matches any placement new expression arguments.
 
-Given:
+Given
+  void* operator new(decltype(sizeof(void*)), void*);
+  struct MyClass { int x; };
+  unsigned char Storage[sizeof(MyClass) * 10];
   MyClass *p1 = new (Storage) MyClass();
-cxxNewExpr(hasAnyPlacementArg(anything()))
-  matches the expression 'new (Storage, 16) MyClass()'.
+
+
+The matcher cxxNewExpr(hasAnyPlacementArg(anything()))
+matches new (Storage) MyClass().
 
Matcher<CXXNewExpr>hasArraySizeMatcher<Expr> InnerMatcher
Matches array new expressions with a given array size.
 
-Given:
+Given
+  void* operator new(decltype(sizeof(void*)));
+  struct MyClass { int x; };
   MyClass *p1 = new MyClass[10];
-cxxNewExpr(hasArraySize(integerLiteral(equals(10))))
-  matches the expression 'new MyClass[10]'.
+
+
+The matcher
+cxxNewExpr(hasArraySize(
+            ignoringImplicit(integerLiteral(equals(10)))))
+matches new MyClass[10].
 
Matcher<CXXNewExpr>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -7365,17 +9857,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -7390,29 +9890,42 @@

AST Traversal Matchers

Matcher<CXXNewExpr>hasPlacementArgunsigned Index, Matcher<Expr> InnerMatcher
Matches placement new expression arguments.
 
-Given:
-  MyClass *p1 = new (Storage, 16) MyClass();
-cxxNewExpr(hasPlacementArg(1, integerLiteral(equals(16))))
-  matches the expression 'new (Storage, 16) MyClass()'.
+Given
+  void *operator new(decltype(sizeof(void*)), int, void*);
+  struct MyClass { int x; };
+  unsigned char Storage[sizeof(MyClass) * 10];
+  MyClass *p1 = new (16, Storage) MyClass();
+
+
+The matcher cxxNewExpr(hasPlacementArg(0,
+                      integerLiteral(equals(16))))
+matches new (16, Storage) MyClass().
 
Matcher<CXXNewExpr>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -7428,14 +9941,45 @@ 

AST Traversal Matchers

Matcher<CXXOperatorCallExpr>hasEitherOperandMatcher<Expr> InnerMatcher
Matches if either the left hand side or the right hand side of a
 binary operator or fold expression matches.
+
+Given
+  struct S {};
+  bool operator ==(const S&, const S&);
+
+  void f(int a, const S&lhs, const S&rhs) {
+      a + 0;
+      lhs == rhs;
+      lhs != rhs;
+  }
+
+  template <typename ...Ts>
+  auto sum(Ts... args) {
+    return (0 + ... + args);
+  }
+
+
+The matcher binaryOperator(hasEitherOperand(integerLiteral()))
+matches a + 0.
+The matcher cxxOperatorCallExpr(hasEitherOperand(declRefExpr(to(
+parmVarDecl(hasName("lhs")))))) matches lhs == rhs and
+lhs != rhs.
+The matcher cxxFoldExpr(hasEitherOperand(integerLiteral()))
+matches (0 + ... + args).
 
Matcher<CXXOperatorCallExpr>hasLHSMatcher<Expr> InnerMatcher
Matches the left hand side of binary operator expressions.
 
-Example matches a (matcher = binaryOperator(hasLHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
 
@@ -7443,44 +9987,64 @@

AST Traversal Matchers

Matches if both matchers match with opposite sides of the binary operator
 or fold expression.
 
-Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1),
-                                             integerLiteral(equals(2)))
-  1 + 2 // Match
-  2 + 1 // Match
-  1 + 1 // No match
-  2 + 2 // No match
+Given
+void foo() {
+  1 + 2; // Match
+  2 + 1; // Match
+  1 + 1; // No match
+  2 + 2; // No match
+}
+The matcher binaryOperator(hasOperands(integerLiteral(equals(1)),
+                                            integerLiteral(equals(2))))
+matches 1 + 2 and 2 + 1,
+but does not match 1 + 1
+or 2 + 2.
 
Matcher<CXXOperatorCallExpr>hasRHSMatcher<Expr> InnerMatcher
Matches the right hand side of binary operator expressions.
 
-Example matches b (matcher = binaryOperator(hasRHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
 
Matcher<CXXOperatorCallExpr>hasUnaryOperandMatcher<Expr> InnerMatcher
Matches if the operand of a unary operator matches.
 
-Example matches true (matcher = hasUnaryOperand(
-                                  cxxBoolLiteral(equals(true))))
-  !true
+void foo() {
+  !true;
+}
+
+The matcher
+unaryOperator(hasUnaryOperand(cxxBoolLiteral(equals(true))))
+matches !true.
 
Matcher<CXXRecordDecl>hasAnyBaseMatcher<CXXBaseSpecifier> BaseSpecMatcher
Matches C++ classes that have a direct or indirect base matching BaseSpecMatcher.
 
-Example:
-matcher hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase"))))
-  class Foo;
+Given
+  class Foo {};
   class Bar : Foo {};
   class Baz : Bar {};
-  class SpecialBase;
+  class SpecialBase {};
   class Proxy : SpecialBase {};  // matches Proxy
   class IndirectlyDerived : Proxy {};  //matches IndirectlyDerived
 
+
+The matcher
+cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase")))))
+matches Proxy and IndirectlyDerived
 FIXME: Refactor this and isDerivedFrom to reuse implementation.
 
@@ -7488,26 +10052,31 @@

AST Traversal Matchers

Matcher<CXXRecordDecl>hasDirectBaseMatcher<CXXBaseSpecifier> BaseSpecMatcher
Matches C++ classes that have a direct base matching BaseSpecMatcher.
 
-Example:
-matcher hasDirectBase(hasType(cxxRecordDecl(hasName("SpecialBase"))))
-  class Foo;
+Given
+  class Foo {};
   class Bar : Foo {};
   class Baz : Bar {};
-  class SpecialBase;
+  class SpecialBase {};
   class Proxy : SpecialBase {};  // matches Proxy
   class IndirectlyDerived : Proxy {};  // doesn't match
+
+The matcher
+cxxRecordDecl(hasDirectBase(hasType(cxxRecordDecl(hasName("SpecialBase")))))
+matches Proxy
 
Matcher<CXXRecordDecl>hasMethodMatcher<CXXMethodDecl> InnerMatcher
Matches the first method of a class or struct that satisfies InnerMatcher.
 
-Given:
+Given
   class A { void func(); };
   class B { void member(); };
 
-cxxRecordDecl(hasMethod(hasName("func"))) matches the declaration of
-A but not B.
+
+The matcher cxxRecordDecl(hasMethod(hasName("func")))
+matches the declaration of class A { void func(); }
+but does not match class B { void member(); }
 
@@ -7519,22 +10088,29 @@

AST Traversal Matchers

Note that a class is not considered to be derived from itself. Example matches Y, Z, C (Base == hasName("X")) - class X; + class X {}; class Y : public X {}; // directly derived class Z : public Y {}; // indirectly derived typedef X A; typedef A B; class C : public B {}; // derived from a typedef of X -In the following example, Bar matches isDerivedFrom(hasName("X")): - class Foo; - typedef Foo X; - class Bar : public Foo {}; // derived from a type that X is a typedef of + class Foo {}; + typedef Foo Alias; + class Bar : public Alias {}; + // derived from a type that Alias is a typedef of Foo + + +The matcher cxxRecordDecl(isDerivedFrom(hasName("X"))) +matches Y, Z and C. +The matcher cxxRecordDecl(isDerivedFrom(hasName("Foo"))) +matches Bar. In the following example, Bar matches isDerivedFrom(hasName("NSObject")) @interface NSObject @end @interface Bar : NSObject @end + Usable as: Matcher<CXXRecordDecl>, Matcher<ObjCInterfaceDecl>
@@ -7545,38 +10121,90 @@

AST Traversal Matchers

Note that a class is not considered to be derived from itself. -Example matches Y, C (Base == hasName("X")) - class X; +Given + class X {}; class Y : public X {}; // directly derived class Z : public Y {}; // indirectly derived typedef X A; typedef A B; class C : public B {}; // derived from a typedef of X +The matcher +cxxRecordDecl(isDirectlyDerivedFrom(namedDecl(hasName("X")))) +matches Y and C (Base == hasName("X") + In the following example, Bar matches isDerivedFrom(hasName("X")): - class Foo; + class Foo {}; typedef Foo X; class Bar : public Foo {}; // derived from a type that X is a typedef of + +The matcher cxxRecordDecl(isDerivedFrom(hasName("X"))) +matches Bar
Matcher<CXXRecordDecl>isSameOrDerivedFromMatcher<NamedDecl> Base
Similar to isDerivedFrom(), but also matches classes that directly
 match Base.
+
+Given
+  class X {};
+  class Y : public X {};  // directly derived
+  class Z : public Y {};  // indirectly derived
+  typedef X A;
+  typedef A B;
+  class C : public B {};  // derived from a typedef of X
+
+The matcher
+cxxRecordDecl(isSameOrDerivedFrom(cxxRecordDecl(hasName("X"))),
+isDefinition())
+matches class X {}, class Y : public X {},
+class Z : public Y {} and class C : public B {}.
 
Matcher<CXXRewrittenBinaryOperator>hasEitherOperandMatcher<Expr> InnerMatcher
Matches if either the left hand side or the right hand side of a
 binary operator or fold expression matches.
+
+Given
+  struct S {};
+  bool operator ==(const S&, const S&);
+
+  void f(int a, const S&lhs, const S&rhs) {
+      a + 0;
+      lhs == rhs;
+      lhs != rhs;
+  }
+
+  template <typename ...Ts>
+  auto sum(Ts... args) {
+    return (0 + ... + args);
+  }
+
+
+The matcher binaryOperator(hasEitherOperand(integerLiteral()))
+matches a + 0.
+The matcher cxxOperatorCallExpr(hasEitherOperand(declRefExpr(to(
+parmVarDecl(hasName("lhs")))))) matches lhs == rhs and
+lhs != rhs.
+The matcher cxxFoldExpr(hasEitherOperand(integerLiteral()))
+matches (0 + ... + args).
 
Matcher<CXXRewrittenBinaryOperator>hasLHSMatcher<Expr> InnerMatcher
Matches the left hand side of binary operator expressions.
 
-Example matches a (matcher = binaryOperator(hasLHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasLHS(expr().bind("lhs")))
+matches a || b,
+with expr()
+matching a.
 
@@ -7584,39 +10212,59 @@

AST Traversal Matchers

Matches if both matchers match with opposite sides of the binary operator
 or fold expression.
 
-Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1),
-                                             integerLiteral(equals(2)))
-  1 + 2 // Match
-  2 + 1 // Match
-  1 + 1 // No match
-  2 + 2 // No match
+Given
+void foo() {
+  1 + 2; // Match
+  2 + 1; // Match
+  1 + 1; // No match
+  2 + 2; // No match
+}
+The matcher binaryOperator(hasOperands(integerLiteral(equals(1)),
+                                            integerLiteral(equals(2))))
+matches 1 + 2 and 2 + 1,
+but does not match 1 + 1
+or 2 + 2.
 
Matcher<CXXRewrittenBinaryOperator>hasRHSMatcher<Expr> InnerMatcher
Matches the right hand side of binary operator expressions.
 
-Example matches b (matcher = binaryOperator(hasRHS()))
-  a || b
+Given
+void foo(bool a, bool b) {
+  a || b;
+}
+
+The matcher binaryOperator(hasRHS(expr().bind("rhs")))
+matches a || b,
+with expr()
+matching b.
 
Matcher<CXXTemporaryObjectExpr>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -7634,17 +10282,19 @@ 

AST Traversal Matchers

expression, or an ObjC-message-send expression. Given - void x(int, int, int) { int y; x(1, y, 42); } -callExpr(hasAnyArgument(declRefExpr())) - matches x(1, y, 42) -with hasAnyArgument(...) + void x(int, int, int) { int y = 42; x(1, y, 42); } +The matcher +callExpr(hasAnyArgument(ignoringImplicit(declRefExpr()))) matches +x(1, y, 42) with hasAnyArgument(...) matching y For ObjectiveC, given @interface I - (void) f:(int) y; @end void foo(I *i) { [i f:12]; } + +The matcher objcMessageExpr(hasAnyArgument(integerLiteral(equals(12)))) - matches [i f:12] +matches [i f:12]
@@ -7652,28 +10302,37 @@

AST Traversal Matchers

Matches the n'th argument of a call expression or a constructor
 call expression.
 
-Example matches y in x(y)
-    (matcher = callExpr(hasArgument(0, declRefExpr())))
+Given
   void x(int) { int y; x(y); }
+The matcher callExpr(hasArgument(0, declRefExpr().bind("arg")))
+matches x(y),
+with declRefExpr() matching y.
 
Matcher<CXXUnresolvedConstructExpr>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -7691,19 +10350,23 @@ 

AST Traversal Matchers

given matcher; or 2) if the Obj-C message expression's callee's method declaration matches the given matcher. -Example matches y.x() (matcher = callExpr(callee( - cxxMethodDecl(hasName("x"))))) +Example 1 class Y { public: void x(); }; void z() { Y y; y.x(); } -Example 2. Matches [I foo] with -objcMessageExpr(callee(objcMethodDecl(hasName("foo")))) +The matcher callExpr(callee(cxxMethodDecl(hasName("x")))) +matches y.x() +Example 2 @interface I: NSObject +(void)foo; @end ... [I foo] + +The matcher +objcMessageExpr(callee(objcMethodDecl(hasName("foo")))) +matches [I foo]
@@ -7713,12 +10376,20 @@

AST Traversal Matchers

Given class Y { void x() { this->x(); x(); Y y; y.x(); } }; void f() { f(); } -callExpr(callee(expr())) - matches this->x(), x(), y.x(), f() -with callee(...) - matching this->x, x, y.x, f respectively + +The matcher callExpr(callee(expr().bind("callee"))) +matches this->x(), x(), y.x(), f() +with expr() inside of callee +matching this->x, x, +y.x, f respectively Given + struct Dummy {}; + // makes sure there is a callee, otherwise there would be no callee, + // just a builtin operator + Dummy operator+(Dummy, Dummy); + // not defining a '*' operator + template <typename... Args> auto sum(Args... args) { return (0 + ... + args); @@ -7728,10 +10399,14 @@

AST Traversal Matchers

auto multiply(Args... args) { return (args * ... * 1); } -cxxFoldExpr(callee(expr())) - matches (args * ... * 1) -with callee(...) - matching * + +The matcher cxxFoldExpr(callee(expr().bind("op"))) +matches (0 + ... + args) +with callee(...) matching *, +but does not match (args * ... * 1). +A CXXFoldExpr only has an UnresolvedLookupExpr as a callee. +When there are no define operators that could be used instead of builtin +ones, then there will be no callee . Note: Callee cannot take the more general internal::Matcher<Expr> because this introduces ambiguous overloads with calls to Callee taking a @@ -7746,8 +10421,10 @@

AST Traversal Matchers

Given void f(int i); int y; - f(y); -callExpr( + void foo() { + f(y); + } +The matcher callExpr( forEachArgumentWithParam( declRefExpr(to(varDecl(hasName("y")))), parmVarDecl(hasType(isInteger())) @@ -7770,14 +10447,15 @@

AST Traversal Matchers

Given void f(int i); - int y; - f(y); - void (*f_ptr)(int) = f; - f_ptr(y); -callExpr( + void foo(int y) { + f(y); + void (*f_ptr)(int) = f; + f_ptr(y); + } +The matcher callExpr( forEachArgumentWithParamType( declRefExpr(to(varDecl(hasName("y")))), - qualType(isInteger()).bind("type) + qualType(isInteger()).bind("type") )) matches f(y) and f_ptr(y) with declRefExpr(...) @@ -7792,17 +10470,19 @@

AST Traversal Matchers

expression, or an ObjC-message-send expression. Given - void x(int, int, int) { int y; x(1, y, 42); } -callExpr(hasAnyArgument(declRefExpr())) - matches x(1, y, 42) -with hasAnyArgument(...) + void x(int, int, int) { int y = 42; x(1, y, 42); } +The matcher +callExpr(hasAnyArgument(ignoringImplicit(declRefExpr()))) matches +x(1, y, 42) with hasAnyArgument(...) matching y For ObjectiveC, given @interface I - (void) f:(int) y; @end void foo(I *i) { [i f:12]; } + +The matcher objcMessageExpr(hasAnyArgument(integerLiteral(equals(12)))) - matches [i f:12] +matches [i f:12] @@ -7810,15 +10490,17 @@

AST Traversal Matchers

Matches the n'th argument of a call expression or a constructor
 call expression.
 
-Example matches y in x(y)
-    (matcher = callExpr(hasArgument(0, declRefExpr())))
+Given
   void x(int) { int y; x(y); }
+The matcher callExpr(hasArgument(0, declRefExpr().bind("arg")))
+matches x(y),
+with declRefExpr() matching y.
 
Matcher<CallExpr>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -7828,17 +10510,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -7855,9 +10545,12 @@

AST Traversal Matchers

extension, matches the constant given in the statement. Given - switch (1) { case 1: case 1+1: case 3 ... 4: ; } -caseStmt(hasCaseConstant(integerLiteral())) - matches "case 1:" + void foo() { + switch (1) { case 1: break; case 1+1: break; case 3 ... 4: break; } + } +The matcher +caseStmt(hasCaseConstant(constantExpr(has(integerLiteral())))) +matches case 1: break.
@@ -7865,14 +10558,23 @@

AST Traversal Matchers

Matches if the cast's source expression
 or opaque value's source expression matches the given matcher.
 
-Example 1: matches "a string"
-(matcher = castExpr(hasSourceExpression(cxxConstructExpr())))
-class URL { URL(string); };
-URL url = "a string";
+Given
+ struct URL { URL(const char*); };
+ URL url = "a string";
+
+The matcher castExpr(hasSourceExpression(cxxConstructExpr()))
+matches "a string".
+
+Given
+void foo(bool b) {
+  int a = b ?: 1;
+}
 
-Example 2: matches 'b' (matcher =
-opaqueValueExpr(hasSourceExpression(implicitCastExpr(declRefExpr())))
-int a = b ?: 1;
+The matcher
+opaqueValueExpr(hasSourceExpression(
+              implicitCastExpr(has(
+                implicitCastExpr(has(declRefExpr()))))))
+matches b twice, for the conditiona and the true expression.
 
@@ -7892,13 +10594,22 @@

AST Traversal Matchers

template <typename T, typename U> void f(T&& t, U&& u) {} - bool B = false; - f(R, B); -templateSpecializationType(forEachTemplateArgument(isExpr(expr()))) - matches twice, with expr() matching 'R * 2' and 'R * 4' -functionDecl(forEachTemplateArgument(refersToType(builtinType()))) - matches the specialization f<unsigned, bool> twice, for 'unsigned' - and 'bool' + void foo() { + bool B = false; + f(R, B); + } + +The matcher +templateSpecializationType(forEachTemplateArgument(isExpr(expr().bind("t_arg")))) +matches Matrix<int, R * 2, R * 4> twice, with +expr() matching R * 2 and +R * 4. +The matcher +functionDecl(forEachTemplateArgument(refersToType(qualType().bind("type")))) +matches the specialization of f twice, +with qualType() matching +unsigned and +bool. @@ -7911,9 +10622,11 @@

AST Traversal Matchers

Given template<typename T> class A {}; A<int> a; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( - hasTypeLoc(loc(asString("int"))))))) - matches `A<int> a`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( +hasTypeLoc(loc(asString("int"))))))))) matches A<int> a. @@ -7927,15 +10640,19 @@

AST Traversal Matchers

template<> class A<double> {}; A<int> a; - template<typename T> f() {}; + template<typename T> void f() {}; void func() { f<int>(); }; -classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToType(asString("int")))) - matches the specialization A<int> -functionDecl(hasAnyTemplateArgument(refersToType(asString("int")))) - matches the specialization f<int> +The matcher classTemplateSpecializationDecl( + hasAnyTemplateArgument( + refersToType(asString("int")))) +matches class A<int>. + +The matcher +functionDecl(hasAnyTemplateArgument( + refersToType(asString("int")))) +matches the instantiation of f. @@ -7943,11 +10660,14 @@

AST Traversal Matchers

Matches the specialized template of a specialization declaration.
 
 Given
-  template<typename T> class A {}; #1
-  template<> class A<int> {}; #2
-classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl()))
-  matches '#2' with classTemplateDecl() matching the class template
-  declaration of 'A' at #1.
+  template<typename T> class A {}; // #1
+  template<> class A<int> {}; // #2
+
+The matcher
+classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl().bind("ctd")))
+matches template<> class A<int> {},
+with classTemplateDecl() matching the class template
+declaration template <typename T> class A {}.
 
@@ -7960,9 +10680,12 @@

AST Traversal Matchers

template<typename T, typename U> class A {}; A<double, int> b; A<int, double> c; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, - hasTypeLoc(loc(asString("double"))))))) - matches `A<double, int> b`, but not `A<int, double> c`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, +hasTypeLoc(loc(asString("double"))))))))) +matches A<double, int> b, but not double> c}. @@ -7973,17 +10696,20 @@

AST Traversal Matchers

Given template<typename T, typename U> class A {}; - A<bool, int> b; - A<int, bool> c; + A<double, int> b; + A<int, double> c; template<typename T> void f() {} void func() { f<int>(); }; + +The matcher classTemplateSpecializationDecl(hasTemplateArgument( 1, refersToType(asString("int")))) - matches the specialization A<bool, int> +matches the specialization class A<double, int>. -functionDecl(hasTemplateArgument(0, refersToType(asString("int")))) - matches the specialization f<int> +The matcher functionDecl(hasTemplateArgument(0, + refersToType(asString("int")))) +matches the specialization of f. @@ -7995,8 +10721,10 @@

AST Traversal Matchers

struct A {}; A a[7]; int b[7]; -arrayType(hasElementType(builtinType())) - matches "int b[7]" + + +The matcher arrayType(hasElementType(builtinType())) +int[7] Usable as: Matcher<ArrayType>, Matcher<ComplexType> @@ -8005,19 +10733,26 @@

AST Traversal Matchers

Matcher<CompoundLiteralExpr>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -8035,11 +10770,12 @@ 

AST Traversal Matchers

a given matcher. Also matches StmtExprs that have CompoundStmt as children. Given - { {}; 1+2; } -hasAnySubstatement(compoundStmt()) - matches '{ {}; 1+2; }' +void foo() { { {}; 1+2; } } +The matcher +compoundStmt(hasAnySubstatement(compoundStmt().bind("compound"))) +{ {}; 1+2; } and { { {}; 1+2; } } with compoundStmt() - matching '{}' +matching {} and { {}; 1+2; }.
@@ -8050,25 +10786,35 @@

AST Traversal Matchers

other declarations of the same function or coroutine. Given +void foo() { for (;;) {} -forStmt(hasBody(compoundStmt())) - matches 'for (;;) {}' +} +The matcher forStmt(hasBody(compoundStmt().bind("body"))) +matches for (;;) {} with compoundStmt() - matching '{}' + matching {} Given void f(); void f() {} -functionDecl(hasBody(compoundStmt())) - matches 'void f() {}' +The matcher functionDecl(hasBody(compoundStmt().bind("compound"))) +f with compoundStmt() - matching '{}' - but does not match 'void f();' +matching {} +but does not match void f(); Matcher<DecayedType>hasDecayedTypeMatcher<QualType> InnerType
Matches the decayed type, whoes decayed type matches InnerMatcher
+
+Given
+  void f(int i[]) {
+    i[1] = 0;
+  }
+
+The matcher parmVarDecl(hasType(decayedType()))
+matches int i[].
 
@@ -8081,15 +10827,17 @@

AST Traversal Matchers

Given template<typename T> class A {}; A<int> a; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( - hasTypeLoc(loc(asString("int"))))))) - matches `A<int> a`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( +hasTypeLoc(loc(asString("int"))))))))) matches A<int> a. Matcher<DeclRefExpr>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -8099,17 +10847,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -8130,9 +10886,12 @@

AST Traversal Matchers

template<typename T, typename U> class A {}; A<double, int> b; A<int, double> c; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, - hasTypeLoc(loc(asString("double"))))))) - matches `A<double, int> b`, but not `A<int, double> c`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, +hasTypeLoc(loc(asString("double"))))))))) +matches A<double, int> b, but not double> c}.
@@ -8140,18 +10899,20 @@

AST Traversal Matchers

Matches if a node refers to a declaration through a specific
 using shadow declaration.
 
-Examples:
+Given
   namespace a { int f(); }
   using a::f;
   int x = f();
-declRefExpr(throughUsingDecl(anything()))
-  matches f
+
+The matcher declRefExpr(throughUsingDecl(anything()))
+matches f
 
   namespace a { class X{}; }
   using a::X;
   X x;
-typeLoc(loc(usingType(throughUsingDecl(anything()))))
-  matches X
+
+The matcher typeLoc(loc(usingType(throughUsingDecl(anything()))))
+matches X
 
 Usable as: Matcher<DeclRefExpr>, Matcher<UsingType>
 
@@ -8161,10 +10922,14 @@

AST Traversal Matchers

Matches a DeclRefExpr that refers to a declaration that matches the
 specified matcher.
 
-Example matches x in if(x)
-    (matcher = declRefExpr(to(varDecl(hasName("x")))))
-  bool x;
-  if (x) {}
+Given
+  void foo() {
+    bool x;
+    if (x) {}
+  }
+
+The matcher declRefExpr(to(varDecl(hasName("x"))))
+matches x inside the condition of the if-stmt.
 
@@ -8174,16 +10939,19 @@

AST Traversal Matchers

Note that this does not work for global declarations because the AST breaks up multiple-declaration DeclStmt's into multiple single-declaration DeclStmt's. -Example: Given non-global declarations - int a, b = 0; - int c; - int d = 2, e; -declStmt(containsDeclaration( + +Given non-global declarations + void foo() { + int a, b = 0; + int c; + int d = 2, e; + } +The matcher declStmt(containsDeclaration( 0, varDecl(hasInitializer(anything())))) - matches only 'int d = 2, e;', and -declStmt(containsDeclaration(1, varDecl())) - matches 'int a, b = 0' as well as 'int d = 2, e;' - but 'int c;' is not matched. +matches int d = 2, e;. +The matcher declStmt(containsDeclaration(1, varDecl())) +matches int a, b = 0; and int d = 2, e; +but does not match int c;. @@ -8191,29 +10959,39 @@

AST Traversal Matchers

Matches the Decl of a DeclStmt which has a single declaration.
 
 Given
-  int a, b;
-  int c;
-declStmt(hasSingleDecl(anything()))
-  matches 'int c;' but not 'int a, b;'.
+  void foo() {
+    int a, b;
+    int c;
+  }
+The matcher declStmt(hasSingleDecl(anything()))
+matches int c;
+but does not match int a, b;
 
Matcher<DeclaratorDecl>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -8237,8 +11015,9 @@ 

AST Traversal Matchers

} } -cxxRcordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the -declaration of class D. + +The matcher cxxRecordDecl(hasDeclContext(namedDecl(hasName("M")))) + matches the declaration of D.
@@ -8248,8 +11027,11 @@

AST Traversal Matchers

Given decltype(1) a = 1; decltype(2.0) b = 2.0; -decltypeType(hasUnderlyingType(isInteger())) - matches the type of "a" + + +The matcher decltypeType(hasUnderlyingType(isInteger())) +matches the type decltype(1) of the variable +declaration of a . Usable as: Matcher<DecltypeType>, Matcher<UsingType> @@ -8266,16 +11048,17 @@

AST Traversal Matchers

f = 42; } -The matcher: - decompositionDecl(hasAnyBinding(bindingDecl(hasName("f").bind("fBinding")))) -matches the decomposition decl with 'f' bound to "fBinding". + +The matcher + decompositionDecl(hasAnyBinding(bindingDecl(hasName("f")).bind("fBinding"))) +matches auto &[f, s, t] = arr with 'f' bound to "fBinding". Matcher<DecompositionDecl>hasBindingunsigned N, Matcher<BindingDecl> InnerMatcher
Matches the Nth binding of a DecompositionDecl.
 
-For example, in:
+Given
 void foo()
 {
     int arr[3];
@@ -8283,10 +11066,10 @@ 

AST Traversal Matchers

f = 42; } -The matcher: - decompositionDecl(hasBinding(0, - bindingDecl(hasName("f").bind("fBinding")))) -matches the decomposition decl with 'f' bound to "fBinding". + +The matcher decompositionDecl(hasBinding(0, + bindingDecl(hasName("f")).bind("fBinding"))) +matches auto &[f, s, t] = arr with 'f' bound to "fBinding".
@@ -8297,20 +11080,22 @@

AST Traversal Matchers

other declarations of the same function or coroutine. Given +void foo() { for (;;) {} -forStmt(hasBody(compoundStmt())) - matches 'for (;;) {}' +} +The matcher forStmt(hasBody(compoundStmt().bind("body"))) +matches for (;;) {} with compoundStmt() - matching '{}' + matching {} Given void f(); void f() {} -functionDecl(hasBody(compoundStmt())) - matches 'void f() {}' +The matcher functionDecl(hasBody(compoundStmt().bind("compound"))) +f with compoundStmt() - matching '{}' - but does not match 'void f();' +matching {} +but does not match void f(); @@ -8318,8 +11103,13 @@

AST Traversal Matchers

Matches the condition expression of an if statement, for loop,
 switch statement or conditional operator.
 
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
   if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
 
@@ -8334,14 +11124,16 @@

AST Traversal Matchers

class D {}; class D d; -elaboratedTypeLoc(hasNamedTypeLoc(templateSpecializationTypeLoc())); - matches the `TypeLoc` of the variable declaration of `c`, but not `d`. + +The matcher +elaboratedTypeLoc(hasNamedTypeLoc(templateSpecializationTypeLoc())) + matches class C<int>, but not D} Matcher<ElaboratedType>hasQualifierMatcher<NestedNameSpecifier> InnerMatcher
Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier,
-matches InnerMatcher if the qualifier exists.
+  matches InnerMatcher if the qualifier exists.
 
 Given
   namespace N {
@@ -8351,8 +11143,11 @@ 

AST Traversal Matchers

} N::M::D d; -elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N")))) -matches the type of the variable declaration of d. + +The matcher +elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N"))))) + matches the type N::M::D of the variable declaration + of d.
@@ -8362,20 +11157,20 @@

AST Traversal Matchers

Given namespace N { namespace M { - class D {}; + enum E { Ok }; } } - N::M::D d; + N::M::E e = N::M::Ok; -elaboratedType(namesType(recordType( -hasDeclaration(namedDecl(hasName("D")))))) matches the type of the variable -declaration of d. + +The matcher elaboratedType(namesType(enumType())) +matches the type N::M::E of the declaration of e . Matcher<EnumType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -8385,17 +11180,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -8412,25 +11215,37 @@

AST Traversal Matchers

(Note: Clang's AST refers to other conversions as "casts" too, and calls actual casts "explicit" casts.) + + unsigned int a = (unsigned int)0; + +The matcher explicitCastExpr(hasDestinationType( +qualType(isUnsignedInteger()))) matches (unsigned int)0.
Matcher<ExplicitCastExpr>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -8453,21 +11268,31 @@ 

AST Traversal Matchers

X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the declaration of x. -Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) - and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) - and friend class X (matcher = friendDecl(hasType("X")) - and public virtual X (matcher = cxxBaseSpecifier(hasType( - cxxRecordDecl(hasName("X")))) class X {}; void y(X &x) { x; X z; } class Y { friend class X; }; class Z : public virtual X {}; -Example matches class Derived -(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) +The matcher expr(hasType(cxxRecordDecl(hasName("X")))) +matches x and z. +The matcher varDecl(hasType(cxxRecordDecl(hasName("X")))) +matches z. +The matcher friendDecl(hasType(asString("class X"))) +matches friend class X. +The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType( +asString("X"))).bind("b"))) matches +class Z : public virtual X {}, +with cxxBaseSpecifier(...) +matching public virtual X. + +Given class Base {}; class Derived : Base {}; +The matcher +cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))) +matches class Derived : Base {}. + Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>, Matcher<CXXBaseSpecifier>
@@ -8477,17 +11302,25 @@

AST Traversal Matchers

Matches if the expression's or declaration's type matches a type
 matcher.
 
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
-            and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
-            and U (matcher = typedefDecl(hasType(asString("int")))
-            and friend class X (matcher = friendDecl(hasType("X"))
-            and public virtual X (matcher = cxxBaseSpecifier(hasType(
-                                              asString("class X")))
+Exmaple
  class X {};
  void y(X &x) { x; X z; }
  typedef int U;
  class Y { friend class X; };
  class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
 
@@ -8504,15 +11337,16 @@

AST Traversal Matchers

appear in the C++17 AST. Given - struct H {}; H G(); void f() { H D = G(); } -``varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr())))`` -matches ``H D = G()`` in C++11 through C++17 (and beyond). + +The matcher +varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr()))) +matches H D = G(). @@ -8523,19 +11357,25 @@

AST Traversal Matchers

Parentheses and explicit casts are not discarded. Given int arr[5]; - int a = 0; + const int a = 0; char b = 0; const int c = a; int *d = arr; long e = (long) 0l; -The matchers - varDecl(hasInitializer(ignoringImpCasts(integerLiteral()))) - varDecl(hasInitializer(ignoringImpCasts(declRefExpr()))) -would match the declarations for a, b, c, and d, but not e. -While - varDecl(hasInitializer(integerLiteral())) - varDecl(hasInitializer(declRefExpr())) -only match the declarations for a. +The matcher +varDecl(hasInitializer(ignoringImpCasts(integerLiteral()))) +matches a and b, +but does not match e. +The matcher +varDecl(hasInitializer(ignoringImpCasts(declRefExpr()))) +matches c and d. + +The matcher +varDecl(hasInitializer(integerLiteral())) +matches a, +but does not match b or e. +The matcher varDecl(hasInitializer(declRefExpr())) +does not match c or d. @@ -8544,17 +11384,34 @@

AST Traversal Matchers

nodes are stripped off. Parentheses and explicit casts are not discarded. + Given - class C {}; - C a = C(); - C b; - C c = b; -The matchers - varDecl(hasInitializer(ignoringImplicit(cxxConstructExpr()))) -would match the declarations for a, b, and c. -While - varDecl(hasInitializer(cxxConstructExpr())) -only match the declarations for b and c. + void f(int param) { + int a = 0; + int b = param; + const int c = 0; + const int d = param; + int e = (0U); + int f = (int)0.0; + const int g = ((int)(((0)))); + } + +The matcher +varDecl(hasInitializer(ignoringImplicit(integerLiteral()))) +matches int a = 0 and const int c = 0, +but not int e = (0U) and ((int)(((0))). +The matcher +varDecl(hasInitializer(integerLiteral())) +matches int a = 0 and const int c = 0, +but not int e = (0U) and ((int)(((0))). + +The matcher +varDecl(hasInitializer(ignoringImplicit(declRefExpr()))) +matches int b = param and const int d = param. +The matcher +varDecl(hasInitializer(declRefExpr())) +matches neither int b = param nor const int d = param, +because an l-to-r-value cast happens. @@ -8568,12 +11425,14 @@

AST Traversal Matchers

char b = (0); void* c = reinterpret_cast<char*>(0); char d = char(0); + The matcher - varDecl(hasInitializer(ignoringParenCasts(integerLiteral()))) -would match the declarations for a, b, c, and d. -while - varDecl(hasInitializer(integerLiteral())) -only match the declaration for a. +varDecl(hasInitializer(ignoringParenCasts(integerLiteral()))) +matches a, b, c +and d. +The matcher +varDecl(hasInitializer(integerLiteral())) +matches a. @@ -8589,14 +11448,21 @@

AST Traversal Matchers

const int c = a; int *d = (arr); long e = ((long) 0l); -The matchers - varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral()))) - varDecl(hasInitializer(ignoringParenImpCasts(declRefExpr()))) -would match the declarations for a, b, c, and d, but not e. -while - varDecl(hasInitializer(integerLiteral())) - varDecl(hasInitializer(declRefExpr())) -would only match the declaration for a. + +The matcher +varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral()))) +matches a and b, +but does not match e. +The matcher +varDecl(hasInitializer(ignoringParenImpCasts(declRefExpr()))) +matches c and d. + +The matcher +varDecl(hasInitializer(integerLiteral())) +matches a, +but does not match b or e. +The matcher varDecl(hasInitializer(declRefExpr())) +does not match c, or d. @@ -8606,8 +11472,9 @@

AST Traversal Matchers

Given const char* str = ("my-string"); The matcher - implicitCastExpr(hasSourceExpression(ignoringParens(stringLiteral()))) -would match the implicit cast resulting from the assignment. +implicitCastExpr(hasSourceExpression(ignoringParens(stringLiteral()))) +would match the implicit cast resulting from the assignment +("my-string"). @@ -8620,10 +11487,14 @@

AST Traversal Matchers

int b = 3; int c; }; + +The matcher fieldDecl(hasInClassInitializer(integerLiteral(equals(2)))) - matches 'int a;' but not 'int b;'. -fieldDecl(hasInClassInitializer(anything())) - matches 'int a;' and 'int b;' but not 'int c;'. +matches a, +but does not match b. +The matcher fieldDecl(hasInClassInitializer(anything())) +matches a and b, +but does not match c. @@ -8634,20 +11505,22 @@

AST Traversal Matchers

other declarations of the same function or coroutine. Given +void foo() { for (;;) {} -forStmt(hasBody(compoundStmt())) - matches 'for (;;) {}' +} +The matcher forStmt(hasBody(compoundStmt().bind("body"))) +matches for (;;) {} with compoundStmt() - matching '{}' + matching {} Given void f(); void f() {} -functionDecl(hasBody(compoundStmt())) - matches 'void f() {}' +The matcher functionDecl(hasBody(compoundStmt().bind("compound"))) +f with compoundStmt() - matching '{}' - but does not match 'void f();' +matching {} +but does not match void f(); @@ -8655,28 +11528,38 @@

AST Traversal Matchers

Matches the condition expression of an if statement, for loop,
 switch statement or conditional operator.
 
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
   if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
 
Matcher<ForStmt>hasIncrementMatcher<Stmt> InnerMatcher
Matches the increment statement of a for loop.
 
-Example:
-    forStmt(hasIncrement(unaryOperator(hasOperatorName("++"))))
-matches '++x' in
-    for (x; x < N; ++x) { }
+Given
+void foo(int N) {
+    for (int x = 0; x < N; ++x) { }
+}
+The matcher
+forStmt(hasIncrement(unaryOperator(hasOperatorName("++"))))
+matches for (int x = 0; x < N; ++x) { }
 
Matcher<ForStmt>hasLoopInitMatcher<Stmt> InnerMatcher
Matches the initialization statement of a for loop.
 
-Example:
-    forStmt(hasLoopInit(declStmt()))
-matches 'int x = 0' in
+Given
+void foo(int N) {
     for (int x = 0; x < N; ++x) { }
+}
+The matcher forStmt(hasLoopInit(declStmt()))
+matches for (int x = 0; x < N; ++x) { }
 
@@ -8690,21 +11573,31 @@

AST Traversal Matchers

X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the declaration of x. -Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) - and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) - and friend class X (matcher = friendDecl(hasType("X")) - and public virtual X (matcher = cxxBaseSpecifier(hasType( - cxxRecordDecl(hasName("X")))) class X {}; void y(X &x) { x; X z; } class Y { friend class X; }; class Z : public virtual X {}; -Example matches class Derived -(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) +The matcher expr(hasType(cxxRecordDecl(hasName("X")))) +matches x and z. +The matcher varDecl(hasType(cxxRecordDecl(hasName("X")))) +matches z. +The matcher friendDecl(hasType(asString("class X"))) +matches friend class X. +The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType( +asString("X"))).bind("b"))) matches +class Z : public virtual X {}, +with cxxBaseSpecifier(...) +matching public virtual X. + +Given class Base {}; class Derived : Base {}; +The matcher +cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))) +matches class Derived : Base {}. + Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>, Matcher<CXXBaseSpecifier> @@ -8714,17 +11607,25 @@

AST Traversal Matchers

Matches if the expression's or declaration's type matches a type
 matcher.
 
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
-            and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
-            and U (matcher = typedefDecl(hasType(asString("int")))
-            and friend class X (matcher = friendDecl(hasType("X"))
-            and public virtual X (matcher = cxxBaseSpecifier(hasType(
-                                              asString("class X")))
+Exmaple
  class X {};
  void y(X &x) { x; X z; }
  typedef int U;
  class Y { friend class X; };
  class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
 
@@ -8744,13 +11645,22 @@

AST Traversal Matchers

template <typename T, typename U> void f(T&& t, U&& u) {} - bool B = false; - f(R, B); -templateSpecializationType(forEachTemplateArgument(isExpr(expr()))) - matches twice, with expr() matching 'R * 2' and 'R * 4' -functionDecl(forEachTemplateArgument(refersToType(builtinType()))) - matches the specialization f<unsigned, bool> twice, for 'unsigned' - and 'bool' + void foo() { + bool B = false; + f(R, B); + } + +The matcher +templateSpecializationType(forEachTemplateArgument(isExpr(expr().bind("t_arg")))) +matches Matrix<int, R * 2, R * 4> twice, with +expr() matching R * 2 and +R * 4. +The matcher +functionDecl(forEachTemplateArgument(refersToType(qualType().bind("type")))) +matches the specialization of f twice, +with qualType() matching +unsigned and +bool. @@ -8763,12 +11673,12 @@

AST Traversal Matchers

void f(); void f() {} void g(); -functionDecl(hasAnyBody(compoundStmt())) - matches both 'void f();' - and 'void f() {}' +The matcher functionDecl(hasAnyBody(compoundStmt())) + matches f + and f with compoundStmt() - matching '{}' - but does not match 'void g();' + matching {} + but does not match void g(); @@ -8780,23 +11690,26 @@

AST Traversal Matchers

Given class X { void f(int x, int y, int z) {} }; -cxxMethodDecl(hasAnyParameter(hasName("y"))) - matches f(int x, int y, int z) {} + +The matcher cxxMethodDecl(hasAnyParameter(hasName("y"))) + matches f with hasAnyParameter(...) matching int y For ObjectiveC, given @interface I - (void) f:(int) y; @end + the matcher objcMethodDecl(hasAnyParameter(hasName("y"))) -matches the declaration of method f with hasParameter + matches the declaration of method f with hasParameter matching y. For blocks, given b = ^(int y) { printf("%d", y) }; + the matcher blockDecl(hasAnyParameter(hasName("y"))) -matches the declaration of the block b with hasParameter + matches the declaration of the block b with hasParameter matching y. @@ -8810,9 +11723,11 @@

AST Traversal Matchers

Given template<typename T> class A {}; A<int> a; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( - hasTypeLoc(loc(asString("int"))))))) - matches `A<int> a`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( +hasTypeLoc(loc(asString("int"))))))))) matches A<int> a. @@ -8826,15 +11741,19 @@

AST Traversal Matchers

template<> class A<double> {}; A<int> a; - template<typename T> f() {}; + template<typename T> void f() {}; void func() { f<int>(); }; -classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToType(asString("int")))) - matches the specialization A<int> -functionDecl(hasAnyTemplateArgument(refersToType(asString("int")))) - matches the specialization f<int> +The matcher classTemplateSpecializationDecl( + hasAnyTemplateArgument( + refersToType(asString("int")))) +matches class A<int>. + +The matcher +functionDecl(hasAnyTemplateArgument( + refersToType(asString("int")))) +matches the instantiation of f. @@ -8845,20 +11764,22 @@

AST Traversal Matchers

other declarations of the same function or coroutine. Given +void foo() { for (;;) {} -forStmt(hasBody(compoundStmt())) - matches 'for (;;) {}' +} +The matcher forStmt(hasBody(compoundStmt().bind("body"))) +matches for (;;) {} with compoundStmt() - matching '{}' + matching {} Given void f(); void f() {} -functionDecl(hasBody(compoundStmt())) - matches 'void f() {}' +The matcher functionDecl(hasBody(compoundStmt().bind("compound"))) +f with compoundStmt() - matching '{}' - but does not match 'void f();' +matching {} +but does not match void f(); @@ -8873,15 +11794,27 @@

AST Traversal Matchers

explicit S(double); // #2 operator int(); // #3 explicit operator bool(); // #4 - explicit(false) S(bool) // # 7 - explicit(true) S(char) // # 8 - explicit(b) S(S) // # 9 + explicit(false) S(bool); // # 7 + explicit(true) S(char); // # 8 + explicit(b) S(float); // # 9 }; - S(int) -> S<true> // #5 - explicit S(double) -> S<false> // #6 -cxxConstructorDecl(hasExplicitSpecifier(constantExpr())) will match #7, #8 and #9, but not #1 or #2. -cxxConversionDecl(hasExplicitSpecifier(constantExpr())) will not match #3 or #4. -cxxDeductionGuideDecl(hasExplicitSpecifier(constantExpr())) will not match #5 or #6. + S(int) -> S<true>; // #5 + explicit S(double) -> S<false>; // #6 + +The matcher +cxxConstructorDecl(hasExplicitSpecifier(constantExpr())) matches +explicit(false) S(bool) and explicit(true) S(char), +but does not match explicit(b) S(float), S(int) or +explicit S(double). +The matcher +cxxConversionDecl(hasExplicitSpecifier(constantExpr())) does not +match operator int() or explicit operator bool(). +Matcher +The matcher +cxxDeductionGuideDecl(hasExplicitSpecifier(declRefExpr())) +matches the implicitly generated deduction guide +auto (float) -> S<b> of the constructor +S(float)}. @@ -8891,15 +11824,18 @@

AST Traversal Matchers

Given class X { void f(int x) {} }; -cxxMethodDecl(hasParameter(0, hasType(varDecl()))) - matches f(int x) {} + +The matcher +cxxMethodDecl(hasParameter(0, hasType(asString("int")))) +matches f with hasParameter(...) - matching int x +matching int x. For ObjectiveC, given @interface I - (void) f:(int) y; @end -the matcher objcMethodDecl(hasParameter(0, hasName("y"))) + +The matcher objcMethodDecl(hasParameter(0, hasName("y"))) matches the declaration of method f with hasParameter matching y. @@ -8911,9 +11847,9 @@

AST Traversal Matchers

Given int f() { return 5; } void g() {} -functionDecl(hasReturnTypeLoc(loc(asString("int")))) - matches the declaration of `f`, but not `g`. - +The matcher functionDecl(hasReturnTypeLoc(loc(asString("int")))) + matches the declaration of f, but not + Matcher<FunctionDecl>hasTemplateArgumentLocunsigned Index, Matcher<TemplateArgumentLoc> InnerMatcher @@ -8925,9 +11861,12 @@

AST Traversal Matchers

template<typename T, typename U> class A {}; A<double, int> b; A<int, double> c; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, - hasTypeLoc(loc(asString("double"))))))) - matches `A<double, int> b`, but not `A<int, double> c`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, +hasTypeLoc(loc(asString("double"))))))))) +matches A<double, int> b, but not double> c}. @@ -8938,27 +11877,31 @@

AST Traversal Matchers

Given template<typename T, typename U> class A {}; - A<bool, int> b; - A<int, bool> c; + A<double, int> b; + A<int, double> c; template<typename T> void f() {} void func() { f<int>(); }; + +The matcher classTemplateSpecializationDecl(hasTemplateArgument( 1, refersToType(asString("int")))) - matches the specialization A<bool, int> +matches the specialization class A<double, int>. -functionDecl(hasTemplateArgument(0, refersToType(asString("int")))) - matches the specialization f<int> +The matcher functionDecl(hasTemplateArgument(0, + refersToType(asString("int")))) +matches the specialization of f. Matcher<FunctionDecl>returnsMatcher<QualType> InnerMatcher
Matches the return type of a function declaration.
 
-Given:
+Given
   class X { int f() { return 1; } };
-cxxMethodDecl(returns(asString("int")))
-  matches int f() { return 1; }
+
+The matcher cxxMethodDecl(returns(asString("int")))
+  matches f
 
@@ -8966,8 +11909,13 @@

AST Traversal Matchers

Matches the condition expression of an if statement, for loop,
 switch statement or conditional operator.
 
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
   if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
 
@@ -8975,25 +11923,37 @@

AST Traversal Matchers

Matches the condition variable statement in an if statement.
 
 Given
+struct A {};
+A* GetAPointer();
+void foo() {
   if (A* a = GetAPointer()) {}
-hasConditionVariableStatement(...)
-  matches 'A* a = GetAPointer()'.
+}
+
+The matcher ifStmt(hasConditionVariableStatement(declStmt()))
+if (A* a = GetAPointer()) {}
 
Matcher<IfStmt>hasElseMatcher<Stmt> InnerMatcher
Matches the else-statement of an if statement.
 
-Examples matches the if statement
-  (matcher = ifStmt(hasElse(cxxBoolLiteral(equals(true)))))
+Given
+void foo() {
   if (false) false; else true;
+}
+
+The matcher ifStmt(hasElse(cxxBoolLiteral(equals(true))))
+if (false) false; else true
 
Matcher<IfStmt>hasInitStatementMatcher<Stmt> InnerMatcher
Matches selection statements with initializer.
 
-Given:
+Given
+ struct vec { int* begin(); int* end(); };
+ int foobar();
+ vec& get_range();
  void foo() {
    if (int i = foobar(); i > 0) {}
    switch (int i = foobar(); i) {}
@@ -9004,48 +11964,77 @@ 

AST Traversal Matchers

switch (foobar()) {} for (auto& x : get_range()) {} } -ifStmt(hasInitStatement(anything())) - matches the if statement in foo but not in bar. -switchStmt(hasInitStatement(anything())) - matches the switch statement in foo but not in bar. -cxxForRangeStmt(hasInitStatement(anything())) - matches the range for statement in foo but not in bar. + +The matcher ifStmt(hasInitStatement(anything())) + matches the if statement if (int i = foobar(); i > 0) {} + in foo but not if (foobar() > 0) {} in bar. +The matcher switchStmt(hasInitStatement(anything())) + matches the switch statement switch (int i = foobar(); i) {} + in foo but not switch (foobar()) {} in bar. +The matcher cxxForRangeStmt(hasInitStatement(anything())) + matches the range for statement + for (auto& a = get_range(); auto& x : a) {} in foo + but not for (auto& x : get_range()) {} in bar.
Matcher<IfStmt>hasThenMatcher<Stmt> InnerMatcher
Matches the then-statement of an if statement.
 
-Examples matches the if statement
-  (matcher = ifStmt(hasThen(cxxBoolLiteral(equals(true)))))
+Given
+void foo() {
   if (false) true; else false;
+}
+
+The matcher ifStmt(hasThen(cxxBoolLiteral(equals(true))))
+if (false) true; else false
 
Matcher<ImplicitCastExpr>hasImplicitDestinationTypeMatcher<QualType> InnerMatcher
Matches implicit casts whose destination type matches a given
 matcher.
+
+Given
+  unsigned int a = 0;
+
+The matcher
+implicitCastExpr(hasImplicitDestinationType(
+qualType(isUnsignedInteger()))) matches 0.
 
Matcher<InitListExpr>hasInitunsigned N, Matcher<Expr> InnerMatcher
Matches the n'th item of an initializer list expression.
 
-Example matches y.
-    (matcher = initListExpr(hasInit(0, expr())))
-  int x{y}.
+Given
+  int y = 42;
+  int x{y};
+
+The matcher initListExpr(hasInit(0, expr()))
+matches {y}.
 
Matcher<InitListExpr>hasSyntacticFormMatcher<Expr> InnerMatcher
Matches the syntactic form of init list expressions
 (if expression have it).
+
+Given
+  int a[] = { 1, 2 };
+  struct B { int x, y; };
+  struct B b = { 5, 6 };
+
+
+The matcher
+initListExpr(hasSyntacticForm(expr().bind("syntactic")))
+matches { 1, 2 } and { 5, 6 }.
 
Matcher<InjectedClassNameType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -9055,17 +12044,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -9079,7 +12076,7 @@

AST Traversal Matchers

Matcher<LabelStmt>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -9089,17 +12086,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -9122,9 +12127,13 @@

AST Traversal Matchers

auto f = [x](){}; auto g = [x = 1](){}; } -In the matcher -lambdaExpr(hasAnyCapture(lambdaCapture(capturesVar(hasName("x")))), -capturesVar(hasName("x")) matches `x` and `x = 1`. + +The matcher +lambdaExpr(hasAnyCapture( + lambdaCapture(capturesVar(hasName("x"))).bind("capture"))) +matches [x](){} and [x = 1](){}, with +lambdaCapture(capturesVar(hasName("x"))).bind("capture") +matching x and x = 1.
@@ -9133,13 +12142,18 @@

AST Traversal Matchers

Given int main() { - int x, y; + int x; + int y; float z; auto f = [=]() { return x + y + z; }; } -lambdaExpr(forEachLambdaCapture( - lambdaCapture(capturesVar(varDecl(hasType(isInteger())))))) -will trigger two matches, binding for 'x' and 'y' respectively. + +The matcher lambdaExpr(forEachLambdaCapture( + lambdaCapture(capturesVar( + varDecl(hasType(isInteger())).bind("captured"))))) +matches [=]() { return x + y + z; } two times, +with varDecl(hasType(isInteger())) matching +int x and int y.
@@ -9151,15 +12165,16 @@

AST Traversal Matchers

int t = 5; auto f = [=](){ return t; }; } -lambdaExpr(hasAnyCapture(lambdaCapture())) and -lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl(hasName("t"))))) - both match `[=](){ return t; }`. + +The matcher lambdaExpr(hasAnyCapture(lambdaCapture())) and +lambdaExpr(hasAnyCapture(lambdaCapture(capturesVar(hasName("t"))))) + both match [=](){ return t; }. Matcher<MemberExpr>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -9169,17 +12184,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -9201,11 +12224,14 @@

AST Traversal Matchers

int m; int f(X x) { x.m; return m; } }; + + +The matcher memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X"))))) - matches `x.m`, but not `m`; however, -memberExpr(hasObjectExpression(hasType(pointsTo( - cxxRecordDecl(hasName("X")))))) - matches `m` (aka. `this->m`), but not `x.m`. +matches x.m, but not m; however, +The matcher memberExpr(hasObjectExpression(hasType(pointsTo( +cxxRecordDecl(hasName("X")))))) +matches m (aka. this->m), but not x.m.
@@ -9214,13 +12240,14 @@

AST Traversal Matchers

given matcher. Given - struct { int first, second; } first, second; - int i(second.first); - int j(first.second); -memberExpr(member(hasName("first"))) - matches second.first - but not first.second (because the member name there is "second"). - + struct { int first = 0, second = 1; } first, second; + int i = second.first; + int j = first.second; + + +The matcher memberExpr(member(hasName("first"))) +matches second.first +but not Matcher<MemberPointerType>pointeeMatcher<Type> @@ -9229,10 +12256,14 @@

AST Traversal Matchers

Given int *a; - int const *b; - float const *f; -pointerType(pointee(isConstQualified(), isInteger())) - matches "int const *b" + const int *b; + int * const c = nullptr; + const float *f; + +The matcher pointerType(pointee(isConstQualified(), isInteger())) +matches const int *, +but does not match int * const +or const float *. Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>, Matcher<PointerType>, Matcher<ReferenceType> @@ -9246,9 +12277,10 @@

AST Traversal Matchers

Given namespace N { template<class T> void f(T t); } template <class T> void g() { using N::f; f(T()); } -unresolvedLookupExpr(hasAnyDeclaration( + +The matcher unresolvedLookupExpr(hasAnyDeclaration( namedDecl(hasUnderlyingDecl(hasName("::N::f"))))) - matches the use of f in g() . + matches f in g(). @@ -9258,14 +12290,29 @@

AST Traversal Matchers

Given struct A { struct B { struct C {}; }; }; A::B::C c; -nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString("struct A"))))) - matches "A::" + +The matcher +nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString( +"struct A"))))) matches A::B::. -Matcher<NestedNameSpecifierLoc>locMatcher<NestedNameSpecifier> InnerMatcher -
Matches NestedNameSpecifierLocs for which the given inner
-NestedNameSpecifier-matcher matches.
+Matcher<NestedNameSpecifierLoc>locMatcher<NestedNameSpecifier> InnerMatcher
+
Matches NestedNameSpecifierLocs for which the given inner
+NestedNameSpecifier-matcher matches.
+
+Given
+  namespace ns {
+    struct A { static void f(); };
+    void A::f() {}
+    void g() { A::f(); }
+  }
+  ns::A a;
+
+
+The matcher nestedNameSpecifierLoc(loc(specifiesType(
+hasDeclaration(namedDecl(hasName("A")))))) matches A::
+twice.
 
@@ -9276,9 +12323,10 @@

AST Traversal Matchers

Given struct A { struct B { struct C {}; }; }; A::B::C c; -nestedNameSpecifierLoc(specifiesTypeLoc(loc(type( + +The matcher nestedNameSpecifierLoc(specifiesTypeLoc(loc(qualType( hasDeclaration(cxxRecordDecl(hasName("A"))))))) - matches "A::" +matches A::
@@ -9288,8 +12336,10 @@

AST Traversal Matchers

Given struct A { struct B { struct C {}; }; }; A::B::C c; -nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A")))) and - matches "A::" + +The matcher +nestedNameSpecifier(hasPrefix(specifiesType(asString( +"struct A")))) matches struct A::B @@ -9300,8 +12350,10 @@

AST Traversal Matchers

Given namespace ns { struct A {}; } ns::A a; -nestedNameSpecifier(specifiesNamespace(hasName("ns"))) - matches "ns::" + +The matcher +nestedNameSpecifier(specifiesNamespace(hasName("ns"))) matches +ns. @@ -9312,10 +12364,11 @@

AST Traversal Matchers

Given struct A { struct B { struct C {}; }; }; A::B::C c; -nestedNameSpecifier(specifiesType( + +The matcher nestedNameSpecifier(specifiesType( hasDeclaration(cxxRecordDecl(hasName("A"))) )) - matches "A::" +matches A. @@ -9323,12 +12376,16 @@

AST Traversal Matchers

Matches any clause in an OpenMP directive.
 
 Given
-
+  void foo() {
   #pragma omp parallel
+    ;
   #pragma omp parallel default(none)
+    ;
+  }
 
-``ompExecutableDirective(hasAnyClause(anything()))`` matches
-``omp parallel default(none)``.
+
+The matcher ompExecutableDirective(hasAnyClause(anything()))
+matches #pragma omp parallel default(none).
 
@@ -9339,13 +12396,18 @@

AST Traversal Matchers

If it is, it will never match. Given + void foo() { + #pragma omp parallel + ; + #pragma omp parallel + {} + } - #pragma omp parallel - ; - #pragma omp parallel - {} -``ompExecutableDirective(hasStructuredBlock(nullStmt()))`` will match ``;`` +The matcher +ompExecutableDirective(hasStructuredBlock(nullStmt().bind("stmt"))) +matches #pragma omp parallel, +with stmtt() matching {}. @@ -9357,22 +12419,29 @@

AST Traversal Matchers

Note that a class is not considered to be derived from itself. Example matches Y, Z, C (Base == hasName("X")) - class X; + class X {}; class Y : public X {}; // directly derived class Z : public Y {}; // indirectly derived typedef X A; typedef A B; class C : public B {}; // derived from a typedef of X -In the following example, Bar matches isDerivedFrom(hasName("X")): - class Foo; - typedef Foo X; - class Bar : public Foo {}; // derived from a type that X is a typedef of + class Foo {}; + typedef Foo Alias; + class Bar : public Alias {}; + // derived from a type that Alias is a typedef of Foo + + +The matcher cxxRecordDecl(isDerivedFrom(hasName("X"))) +matches Y, Z and C. +The matcher cxxRecordDecl(isDerivedFrom(hasName("Foo"))) +matches Bar. In the following example, Bar matches isDerivedFrom(hasName("NSObject")) @interface NSObject @end @interface Bar : NSObject @end + Usable as: Matcher<CXXRecordDecl>, Matcher<ObjCInterfaceDecl> @@ -9383,24 +12452,45 @@

AST Traversal Matchers

Note that a class is not considered to be derived from itself. -Example matches Y, C (Base == hasName("X")) - class X; +Given + class X {}; class Y : public X {}; // directly derived class Z : public Y {}; // indirectly derived typedef X A; typedef A B; class C : public B {}; // derived from a typedef of X +The matcher +cxxRecordDecl(isDirectlyDerivedFrom(namedDecl(hasName("X")))) +matches Y and C (Base == hasName("X") + In the following example, Bar matches isDerivedFrom(hasName("X")): - class Foo; + class Foo {}; typedef Foo X; class Bar : public Foo {}; // derived from a type that X is a typedef of + +The matcher cxxRecordDecl(isDerivedFrom(hasName("X"))) +matches Bar Matcher<ObjCInterfaceDecl>isSameOrDerivedFromMatcher<NamedDecl> Base
Similar to isDerivedFrom(), but also matches classes that directly
 match Base.
+
+Given
+  class X {};
+  class Y : public X {};  // directly derived
+  class Z : public Y {};  // indirectly derived
+  typedef X A;
+  typedef A B;
+  class C : public B {};  // derived from a typedef of X
+
+The matcher
+cxxRecordDecl(isSameOrDerivedFrom(cxxRecordDecl(hasName("X"))),
+isDefinition())
+matches class X {}, class Y : public X {},
+class Z : public Y {} and class C : public B {}.
 
@@ -9409,19 +12499,23 @@

AST Traversal Matchers

given matcher; or 2) if the Obj-C message expression's callee's method declaration matches the given matcher. -Example matches y.x() (matcher = callExpr(callee( - cxxMethodDecl(hasName("x"))))) +Example 1 class Y { public: void x(); }; void z() { Y y; y.x(); } -Example 2. Matches [I foo] with -objcMessageExpr(callee(objcMethodDecl(hasName("foo")))) +The matcher callExpr(callee(cxxMethodDecl(hasName("x")))) +matches y.x() +Example 2 @interface I: NSObject +(void)foo; @end ... [I foo] + +The matcher +objcMessageExpr(callee(objcMethodDecl(hasName("foo")))) +matches [I foo] @@ -9430,17 +12524,19 @@

AST Traversal Matchers

expression, or an ObjC-message-send expression. Given - void x(int, int, int) { int y; x(1, y, 42); } -callExpr(hasAnyArgument(declRefExpr())) - matches x(1, y, 42) -with hasAnyArgument(...) + void x(int, int, int) { int y = 42; x(1, y, 42); } +The matcher +callExpr(hasAnyArgument(ignoringImplicit(declRefExpr()))) matches +x(1, y, 42) with hasAnyArgument(...) matching y For ObjectiveC, given @interface I - (void) f:(int) y; @end void foo(I *i) { [i f:12]; } + +The matcher objcMessageExpr(hasAnyArgument(integerLiteral(equals(12)))) - matches [i f:12] +matches [i f:12] @@ -9448,9 +12544,11 @@

AST Traversal Matchers

Matches the n'th argument of a call expression or a constructor
 call expression.
 
-Example matches y in x(y)
-    (matcher = callExpr(hasArgument(0, declRefExpr())))
+Given
   void x(int) { int y; x(y); }
+The matcher callExpr(hasArgument(0, declRefExpr().bind("arg")))
+matches x(y),
+with declRefExpr() matching y.
 
@@ -9458,23 +12556,26 @@

AST Traversal Matchers

Matches if the Objective-C message is sent to an instance,
 and the inner matcher matches on that instance.
 
-For example the method call in
+Given
   NSString *x = @"hello";
   [x containsString:@"h"];
-is matched by
+
+The matcher
 objcMessageExpr(hasReceiver(declRefExpr(to(varDecl(hasName("x"))))))
+matches [x containsString:@"h"];
 
Matcher<ObjCMessageExpr>hasReceiverTypeMatcher<QualType> InnerMatcher
Matches on the receiver of an ObjectiveC Message expression.
 
-Example
-matcher = objCMessageExpr(hasReceiverType(asString("UIWebView *")));
-matches the [webView ...] message invocation.
   NSString *webViewJavaScript = ...
   UIWebView *webView = ...
   [webView stringByEvaluatingJavaScriptFromString:webViewJavascript];
+
+The matcher objCMessageExpr(hasReceiverType(asString("UIWebView
+*"))) matches
+[webViewstringByEvaluatingJavaScriptFromString:webViewJavascript];
 
@@ -9486,23 +12587,26 @@

AST Traversal Matchers

Given class X { void f(int x, int y, int z) {} }; -cxxMethodDecl(hasAnyParameter(hasName("y"))) - matches f(int x, int y, int z) {} + +The matcher cxxMethodDecl(hasAnyParameter(hasName("y"))) + matches f with hasAnyParameter(...) matching int y For ObjectiveC, given @interface I - (void) f:(int) y; @end + the matcher objcMethodDecl(hasAnyParameter(hasName("y"))) -matches the declaration of method f with hasParameter + matches the declaration of method f with hasParameter matching y. For blocks, given b = ^(int y) { printf("%d", y) }; + the matcher blockDecl(hasAnyParameter(hasName("y"))) -matches the declaration of the block b with hasParameter + matches the declaration of the block b with hasParameter matching y. @@ -9513,15 +12617,18 @@

AST Traversal Matchers

Given class X { void f(int x) {} }; -cxxMethodDecl(hasParameter(0, hasType(varDecl()))) - matches f(int x) {} + +The matcher +cxxMethodDecl(hasParameter(0, hasType(asString("int")))) +matches f with hasParameter(...) - matching int x +matching int x. For ObjectiveC, given @interface I - (void) f:(int) y; @end -the matcher objcMethodDecl(hasParameter(0, hasName("y"))) + +The matcher objcMethodDecl(hasParameter(0, hasName("y"))) matches the declaration of method f with hasParameter matching y. @@ -9530,19 +12637,26 @@

AST Traversal Matchers

Matcher<ObjCPropertyDecl>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -9559,14 +12673,23 @@ 

AST Traversal Matchers

Matches if the cast's source expression
 or opaque value's source expression matches the given matcher.
 
-Example 1: matches "a string"
-(matcher = castExpr(hasSourceExpression(cxxConstructExpr())))
-class URL { URL(string); };
-URL url = "a string";
+Given
+ struct URL { URL(const char*); };
+ URL url = "a string";
+
+The matcher castExpr(hasSourceExpression(cxxConstructExpr()))
+matches "a string".
 
-Example 2: matches 'b' (matcher =
-opaqueValueExpr(hasSourceExpression(implicitCastExpr(declRefExpr())))
-int a = b ?: 1;
+Given
+void foo(bool b) {
+  int a = b ?: 1;
+}
+
+The matcher
+opaqueValueExpr(hasSourceExpression(
+              implicitCastExpr(has(
+                implicitCastExpr(has(declRefExpr()))))))
+matches b twice, for the conditiona and the true expression.
 
@@ -9581,9 +12704,11 @@

AST Traversal Matchers

foo(t); bar(t); } -unresolvedLookupExpr(hasAnyDeclaration( + +The matcher unresolvedLookupExpr(hasAnyDeclaration( functionTemplateDecl(hasName("foo")))) - matches foo in foo(t); but not bar in bar(t); +matches foo in foo(t); +but does not match bar in bar(t);
@@ -9594,8 +12719,10 @@

AST Traversal Matchers

int (*ptr_to_array)[4]; int (*ptr_to_func)(int); -varDecl(hasType(pointsTo(parenType(innerType(functionType()))))) matches -ptr_to_func but not ptr_to_array. +The matcher +varDecl(hasType(pointsTo(parenType(innerType(functionType()))))) + matches ptr_to_func but not + ptr_to_array. Usable as: Matcher<ParenType> @@ -9607,8 +12734,8 @@

AST Traversal Matchers

Given int* x; -pointerTypeLoc(hasPointeeLoc(loc(asString("int")))) - matches `int*`. +The matcher pointerTypeLoc(hasPointeeLoc(loc(asString("int")))) + matches int*. @@ -9618,10 +12745,14 @@

AST Traversal Matchers

Given int *a; - int const *b; - float const *f; -pointerType(pointee(isConstQualified(), isInteger())) - matches "int const *b" + const int *b; + int * const c = nullptr; + const float *f; + +The matcher pointerType(pointee(isConstQualified(), isInteger())) +matches const int *, +but does not match int * const +or const float *. Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>, Matcher<PointerType>, Matcher<ReferenceType> @@ -9631,19 +12762,22 @@

AST Traversal Matchers

Matcher<QualType>hasCanonicalTypeMatcher<QualType> InnerMatcher
Matches QualTypes whose canonical type matches InnerMatcher.
 
-Given:
+Given
   typedef int &int_ref;
   int a;
   int_ref b = a;
 
-varDecl(hasType(qualType(referenceType()))))) will not match the
-declaration of b but varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does.
+The matcher varDecl(hasType(qualType(referenceType())))
+does not match int_ref b = a,
+but the matcher
+varDecl(hasType(qualType(hasCanonicalType(referenceType()))))
+does match int_ref b = a.
 
Matcher<QualType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -9653,17 +12787,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -9681,30 +12823,56 @@

AST Traversal Matchers

Given void (*fp)(void); The matcher - varDecl(hasType(pointerType(pointee(ignoringParens(functionType()))))) -would match the declaration for fp. +varDecl(hasType(pointerType(pointee(ignoringParens(functionType()))))) +matches fp.
Matcher<QualType>pointsToMatcher<Decl> InnerMatcher -
Overloaded to match the pointee type's declaration.
+
Matches if the matched type is a pointer type and the pointee type
+  matches the specified matcher.
+Overloaded to match the pointee type's declaration.
+
+Given
+  class Y { public: void x(); };
+  void z() { Y *y; y->x(); }
+
+The matcher cxxMemberCallExpr(on(hasType(pointsTo(
+     cxxRecordDecl(hasName("Y"))))))
+matches y->x()
 
Matcher<QualType>pointsToMatcher<QualType> InnerMatcher
Matches if the matched type is a pointer type and the pointee type
-matches the specified matcher.
+  matches the specified matcher.
 
-Example matches y->x()
-  (matcher = cxxMemberCallExpr(on(hasType(pointsTo
-     cxxRecordDecl(hasName("Y")))))))
+Given
   class Y { public: void x(); };
   void z() { Y *y; y->x(); }
+
+The matcher cxxMemberCallExpr(on(hasType(pointsTo(
+     qualType()))))
+matches y->x()
 
Matcher<QualType>referencesMatcher<Decl> InnerMatcher -
Overloaded to match the referenced type's declaration.
+
Matches if the matched type is a reference type and the referenced
+type matches the specified matcher.
+Overloaded to match the referenced type's declaration.
+
+Given
+  class X {
+    void a(X b) {
+      X &x = b;
+      const X &y = b;
+    }
+  };
+
+The matcher
+varDecl(hasType(references(cxxRecordDecl(hasName("X"))))) matches
+X &x = b and const X &y = b.
 
@@ -9712,14 +12880,17 @@

AST Traversal Matchers

Matches if the matched type is a reference type and the referenced
 type matches the specified matcher.
 
-Example matches X &x and const X &y
-    (matcher = varDecl(hasType(references(cxxRecordDecl(hasName("X"))))))
+Given
   class X {
     void a(X b) {
       X &x = b;
       const X &y = b;
     }
   };
+
+The matcher
+varDecl(hasType(references(qualType()))) matches
+X &x = b and const X &y = b.
 
@@ -9728,16 +12899,18 @@

AST Traversal Matchers

`InnerMatcher`. Given - int* const x; - const int y; -qualifiedTypeLoc(hasUnqualifiedLoc(pointerTypeLoc())) - matches the `TypeLoc` of the variable declaration of `x`, but not `y`. -
+ int* const x = nullptr; + const int y = 0; + + +The matcher qualifiedTypeLoc(hasUnqualifiedLoc(pointerTypeLoc())) +matches the type int* of the variable declaration but +not
Matcher<RecordType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -9747,17 +12920,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -9776,8 +12957,10 @@

AST Traversal Matchers

Given int x = 3; int& xx = x; -referenceTypeLoc(hasReferentLoc(loc(asString("int")))) - matches `int&`. + + +The matcher referenceTypeLoc(hasReferentLoc(loc(asString("int")))) + matches int&.
@@ -9787,10 +12970,14 @@

AST Traversal Matchers

Given int *a; - int const *b; - float const *f; -pointerType(pointee(isConstQualified(), isInteger())) - matches "int const *b" + const int *b; + int * const c = nullptr; + const float *f; + +The matcher pointerType(pointee(isConstQualified(), isInteger())) +matches const int *, +but does not match int * const +or const float *. Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>, Matcher<PointerType>, Matcher<ReferenceType> @@ -9801,11 +12988,13 @@

AST Traversal Matchers

Matches the return value expression of a return statement
 
 Given
-  return a + b;
-hasReturnValue(binaryOperator())
-  matches 'return a + b'
-with binaryOperator()
-  matching 'a + b'
+  int foo(int a, int b) {
+    return a + b;
+  }
+The matcher
+returnStmt(hasReturnValue(binaryOperator().bind("op"))) matches
+return a + b, with binaryOperator() matching
+a + b.
 
@@ -9814,17 +13003,25 @@

AST Traversal Matchers

a given matcher. Also matches StmtExprs that have CompoundStmt as children. Given - { {}; 1+2; } -hasAnySubstatement(compoundStmt()) - matches '{ {}; 1+2; }' +void foo() { { {}; 1+2; } } +The matcher +compoundStmt(hasAnySubstatement(compoundStmt().bind("compound"))) +{ {}; 1+2; } and { { {}; 1+2; } } with compoundStmt() - matching '{}' +matching {} and { {}; 1+2; }. Matcher<Stmt>alignOfExprMatcher<UnaryExprOrTypeTraitExpr> InnerMatcher
Same as unaryExprOrTypeTraitExpr, but only matching
 alignof.
+
+Given
+  int align = alignof(int);
+
+
+The matcher alignOfExpr(expr())
+matches alignof(int).
 
@@ -9832,26 +13029,30 @@

AST Traversal Matchers

Matches declaration of the function, method, or block the statement
 belongs to.
 
-Given:
-F& operator=(const F& o) {
-  std::copy_if(o.begin(), o.end(), begin(), [](V v) { return v > 0; });
-  return *this;
-}
-returnStmt(forCallable(functionDecl(hasName("operator="))))
-  matches 'return *this'
-  but does not match 'return v > 0'
+Given
+struct F {
+  F& operator=(const F& other) {
+    []() { return 42 == 42; };
+    return *this;
+  }
+};
 
-Given:
--(void) foo {
+The matcher returnStmt(forFunction(hasName("operator=")))
+matches return *this
+but does not match return 42 == 42.
+
+Given
+void foo {
   int x = 1;
   dispatch_sync(queue, ^{ int y = 2; });
 }
-declStmt(forCallable(objcMethodDecl()))
-  matches 'int x = 1'
-  but does not match 'int y = 2'.
-whereas declStmt(forCallable(blockDecl()))
-  matches 'int y = 2'
-  but does not match 'int x = 1'.
+
+The matcher declStmt(forCallable(objcMethodDecl()))
+matches int x = 1
+but does not match int y = 2.
+The matcher declStmt(forCallable(blockDecl()))
+matches int y = 2
+but does not match int x = 1.
 
@@ -9860,23 +13061,34 @@

AST Traversal Matchers

Deprecated. Use forCallable() to correctly handle the situation when the declaration is not a function (but a block or an Objective-C method). -forFunction() not only fails to take non-functions into account but also -may match the wrong declaration in their presence. +The matcher forFunction() not only fails to take non-functions +into account but also may match the wrong declaration in their presence. -Given: -F& operator=(const F& o) { - std::copy_if(o.begin(), o.end(), begin(), [](V v) { return v > 0; }); - return *this; -} -returnStmt(forFunction(hasName("operator="))) - matches 'return *this' - but does not match 'return v > 0' +Given + struct F { + F& operator=(const F& other) { + []() { return 42 == 42; }; + return *this; + } + }; + + +The matcher returnStmt(forFunction(hasName("operator="))) +matches return *this +but does not match return 42 == 42. Matcher<Stmt>sizeOfExprMatcher<UnaryExprOrTypeTraitExpr> InnerMatcher
Same as unaryExprOrTypeTraitExpr, but only matching
 sizeof.
+
+Given
+  struct S { double x; double y; };
+  int size = sizeof(struct S);
+
+The matcher sizeOfExpr(expr())
+matches sizeof(struct S).
 
@@ -9890,7 +13102,9 @@

AST Traversal Matchers

int i; double j = F(i); -substTemplateTypeParmType(hasReplacementType(type())) matches int + +The matcher substTemplateTypeParmType(hasReplacementType(type())) +matches int. @@ -9899,11 +13113,18 @@

AST Traversal Matchers

statement. This matcher may produce multiple matches. Given - switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } } -switchStmt(forEachSwitchCase(caseStmt().bind("c"))).bind("s") - matches four times, with "c" binding each of "case 1:", "case 2:", -"case 3:" and "case 4:", and "s" respectively binding "switch (1)", -"switch (1)", "switch (2)" and "switch (2)". + void foo() { + switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } } + } +The matcher +switchStmt(forEachSwitchCase(caseStmt().bind("c"))) +matches four times, matching +switch (1) { case 1: case 2: default: switch (2) { case 3: +case 4: ; } } and +switch (2) { case 3: case 4: ; }, with +caseStmt() matching each of case 1:, +case 2:, case 3: +and case 4:. @@ -9911,15 +13132,23 @@

AST Traversal Matchers

Matches the condition expression of an if statement, for loop,
 switch statement or conditional operator.
 
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
   if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
 
Matcher<SwitchStmt>hasInitStatementMatcher<Stmt> InnerMatcher
Matches selection statements with initializer.
 
-Given:
+Given
+ struct vec { int* begin(); int* end(); };
+ int foobar();
+ vec& get_range();
  void foo() {
    if (int i = foobar(); i > 0) {}
    switch (int i = foobar(); i) {}
@@ -9930,18 +13159,23 @@ 

AST Traversal Matchers

switch (foobar()) {} for (auto& x : get_range()) {} } -ifStmt(hasInitStatement(anything())) - matches the if statement in foo but not in bar. -switchStmt(hasInitStatement(anything())) - matches the switch statement in foo but not in bar. -cxxForRangeStmt(hasInitStatement(anything())) - matches the range for statement in foo but not in bar. + +The matcher ifStmt(hasInitStatement(anything())) + matches the if statement if (int i = foobar(); i > 0) {} + in foo but not if (foobar() > 0) {} in bar. +The matcher switchStmt(hasInitStatement(anything())) + matches the switch statement switch (int i = foobar(); i) {} + in foo but not switch (foobar()) {} in bar. +The matcher cxxForRangeStmt(hasInitStatement(anything())) + matches the range for statement + for (auto& a = get_range(); auto& x : a) {} in foo + but not for (auto& x : get_range()) {} in bar.
Matcher<TagType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -9951,17 +13185,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -9976,19 +13218,26 @@

AST Traversal Matchers

Matcher<TemplateArgumentLoc>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -10008,10 +13257,13 @@ 

AST Traversal Matchers

struct B { int next; }; template<int(B::*next_ptr)> struct A {}; A<&B::next> a; + +The matcher templateSpecializationType(hasAnyTemplateArgument( - isExpr(hasDescendant(declRefExpr(to(fieldDecl(hasName("next")))))))) - matches the specialization A<&B::next> with fieldDecl(...) matching - B::next + isExpr(hasDescendant(declRefExpr(to(fieldDecl(hasName("next")).bind("next"))))))) +matches the specialization A<&struct B::next> +with fieldDecl(hasName("next")) matching +B::next.
@@ -10023,10 +13275,13 @@

AST Traversal Matchers

struct B { int next; }; template<int(B::*next_ptr)> struct A {}; A<&B::next> a; + +The matcher classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToDeclaration(fieldDecl(hasName("next"))))) - matches the specialization A<&B::next> with fieldDecl(...) matching - B::next + refersToDeclaration(fieldDecl(hasName("next")).bind("next")))) +matches the specialization struct A<&B::next> +with fieldDecl(hasName("next")) matching +B::next.
@@ -10036,9 +13291,12 @@

AST Traversal Matchers

Given template<int T> struct C {}; C<42> c; -classTemplateSpecializationDecl( + +The matcher classTemplateSpecializationDecl( hasAnyTemplateArgument(refersToIntegralType(asString("int")))) - matches the implicit instantiation of C in C<42>. +matches the implicitly declared specialization +struct C<42> from the instantiation for the type of the +variable c . @@ -10049,9 +13307,11 @@

AST Traversal Matchers

template<template <typename> class S> class X {}; template<typename T> class Y {}; X<Y> xi; + +The matcher classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToTemplate(templateName()))) - matches the specialization X<Y> + refersToTemplate(templateName()))) +matches the specialization class X<Y> @@ -10062,9 +13322,11 @@

AST Traversal Matchers

struct X {}; template<typename T> struct A {}; A<X> a; + +The matcher classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType( - recordType(hasDeclaration(recordDecl(hasName("X"))))))) -matches the specialization of struct A generated by A<X>. + recordType(hasDeclaration(recordDecl(hasName("X"))))))) +matches the specialization struct A<struct X>. @@ -10077,9 +13339,11 @@

AST Traversal Matchers

Given template<typename T> class A {}; A<int> a; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( - hasTypeLoc(loc(asString("int"))))))) - matches `A<int> a`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( +hasTypeLoc(loc(asString("int"))))))))) matches A<int> a. @@ -10092,9 +13356,12 @@

AST Traversal Matchers

template<typename T, typename U> class A {}; A<double, int> b; A<int, double> c; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, - hasTypeLoc(loc(asString("double"))))))) - matches `A<double, int> b`, but not `A<int, double> c`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, +hasTypeLoc(loc(asString("double"))))))))) +matches A<double, int> b, but not double> c}. @@ -10114,13 +13381,22 @@

AST Traversal Matchers

template <typename T, typename U> void f(T&& t, U&& u) {} - bool B = false; - f(R, B); -templateSpecializationType(forEachTemplateArgument(isExpr(expr()))) - matches twice, with expr() matching 'R * 2' and 'R * 4' -functionDecl(forEachTemplateArgument(refersToType(builtinType()))) - matches the specialization f<unsigned, bool> twice, for 'unsigned' - and 'bool' + void foo() { + bool B = false; + f(R, B); + } + +The matcher +templateSpecializationType(forEachTemplateArgument(isExpr(expr().bind("t_arg")))) +matches Matrix<int, R * 2, R * 4> twice, with +expr() matching R * 2 and +R * 4. +The matcher +functionDecl(forEachTemplateArgument(refersToType(qualType().bind("type")))) +matches the specialization of f twice, +with qualType() matching +unsigned and +bool. @@ -10134,21 +13410,25 @@

AST Traversal Matchers

template<> class A<double> {}; A<int> a; - template<typename T> f() {}; + template<typename T> void f() {}; void func() { f<int>(); }; -classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToType(asString("int")))) - matches the specialization A<int> -functionDecl(hasAnyTemplateArgument(refersToType(asString("int")))) - matches the specialization f<int> +The matcher classTemplateSpecializationDecl( + hasAnyTemplateArgument( + refersToType(asString("int")))) +matches class A<int>. + +The matcher +functionDecl(hasAnyTemplateArgument( + refersToType(asString("int")))) +matches the instantiation of f. Matcher<TemplateSpecializationType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -10158,17 +13438,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -10187,23 +13475,26 @@

AST Traversal Matchers

Given template<typename T, typename U> class A {}; - A<bool, int> b; - A<int, bool> c; + A<double, int> b; + A<int, double> c; template<typename T> void f() {} void func() { f<int>(); }; + +The matcher classTemplateSpecializationDecl(hasTemplateArgument( 1, refersToType(asString("int")))) - matches the specialization A<bool, int> +matches the specialization class A<double, int>. -functionDecl(hasTemplateArgument(0, refersToType(asString("int")))) - matches the specialization f<int> +The matcher functionDecl(hasTemplateArgument(0, + refersToType(asString("int")))) +matches the specialization of f.
Matcher<TemplateTypeParmType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -10213,17 +13504,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -10238,25 +13537,37 @@

AST Traversal Matchers

Matcher<TypeLoc>locMatcher<QualType> InnerMatcher
Matches TypeLocs for which the given inner
 QualType-matcher matches.
+
+  int a = 10;
+
+The matcher typeLoc(loc(qualType(isInteger())))
+matches the int of a .
 
Matcher<TypedefNameDecl>hasTypeLocMatcher<TypeLoc> Inner
Matches if the type location of a node matches the inner matcher.
 
-Examples:
+Given
   int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
+The matcher declaratorDecl(hasTypeLoc(loc(asString("int"))))
+matches int x.
+
+Given
+struct point { point(double, double); };
+point p = point(1.0, -1.0);
 
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
+The matcher
+cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("point"))))
+matches point(1.0, -1.0).
 
+Given
 struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
+Foo x = Foo(1, 2);
+
+The matcher cxxTemporaryObjectExpr(hasTypeLoc(
+                          loc(asString("Foo"))))
+matches Foo(1, 2).
 
 Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
   Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
@@ -10273,23 +13584,31 @@ 

AST Traversal Matchers

Matches if the expression's or declaration's type matches a type
 matcher.
 
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
-            and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
-            and U (matcher = typedefDecl(hasType(asString("int")))
-            and friend class X (matcher = friendDecl(hasType("X"))
-            and public virtual X (matcher = cxxBaseSpecifier(hasType(
-                                              asString("class X")))
+Exmaple
  class X {};
  void y(X &x) { x; X z; }
  typedef int U;
  class Y { friend class X; };
  class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
 
Matcher<TypedefType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -10299,17 +13618,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -10328,8 +13655,11 @@

AST Traversal Matchers

For example, in: class A {}; using B = A; -The matcher type(hasUnqualifiedDesugaredType(recordType())) matches -both B and A. + B b; + +The matcher +varDecl(hasType(hasUnqualifiedDesugaredType(recordType()))) +matches B b.
@@ -10338,17 +13668,23 @@

AST Traversal Matchers

Given int a, c; float b; int s = sizeof(a) + sizeof(b) + alignof(c); -unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int")) - matches sizeof(a) and alignof(c) + +The matcher +unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int"))) +matches sizeof(a) and alignof(c)
Matcher<UnaryOperator>hasUnaryOperandMatcher<Expr> InnerMatcher
Matches if the operand of a unary operator matches.
 
-Example matches true (matcher = hasUnaryOperand(
-                                  cxxBoolLiteral(equals(true))))
-  !true
+void foo() {
+  !true;
+}
+
+The matcher
+unaryOperator(hasUnaryOperand(cxxBoolLiteral(equals(true))))
+matches !true.
 
@@ -10362,17 +13698,20 @@

AST Traversal Matchers

int m; int f(X x) { x.m; return m; } }; + + +The matcher memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X"))))) - matches `x.m`, but not `m`; however, -memberExpr(hasObjectExpression(hasType(pointsTo( - cxxRecordDecl(hasName("X")))))) - matches `m` (aka. `this->m`), but not `x.m`. +matches x.m, but not m; however, +The matcher memberExpr(hasObjectExpression(hasType(pointsTo( +cxxRecordDecl(hasName("X")))))) +matches m (aka. this->m), but not x.m.
Matcher<UnresolvedUsingType>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
-matches the given matcher.
+  matches the given matcher.
 
 The associated declaration is:
 - for type nodes, the declaration of the underlying type
@@ -10382,17 +13721,25 @@ 

AST Traversal Matchers

- for CXXNewExpr, the declaration of the operator new - for ObjCIvarExpr, the declaration of the ivar -For type nodes, hasDeclaration will generally match the declaration of the -sugared type. Given +Given class X {}; typedef X Y; Y y; -in varDecl(hasType(hasDeclaration(decl()))) the decl will match the -typedefDecl. A common use case is to match the underlying, desugared type. + +For type nodes, hasDeclaration will generally match the declaration of the +sugared type, i.e., the matcher +varDecl(hasType(qualType(hasDeclaration(decl().bind("d"))))), +matches Y y, with +the matcher decl() matching +typedef X Y;. +A common use case is to match the underlying, desugared type. This can be achieved by using the hasUnqualifiedDesugaredType matcher: - varDecl(hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(decl()))))) -In this matcher, the decl will match the CXXRecordDecl of class X. +varDecl(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(decl().bind("d")))))) +matches Y y. +In this matcher, the matcher decl() will match the +CXXRecordDecl +class X {};. Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>, Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>, @@ -10412,8 +13759,12 @@

AST Traversal Matchers

namespace X { int a; void b(); } using X::a; using X::b; + +The matcher usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(functionDecl()))) - matches using X::b but not using X::a
+ matches using X::b + but not X::a} + Matcher<UsingType>hasUnderlyingTypeMatcher<Type> @@ -10422,8 +13773,11 @@

AST Traversal Matchers

Given decltype(1) a = 1; decltype(2.0) b = 2.0; -decltypeType(hasUnderlyingType(isInteger())) - matches the type of "a" + + +The matcher decltypeType(hasUnderlyingType(isInteger())) +matches the type decltype(1) of the variable +declaration of a . Usable as: Matcher<DecltypeType>, Matcher<UsingType> @@ -10433,18 +13787,20 @@

AST Traversal Matchers

Matches if a node refers to a declaration through a specific
 using shadow declaration.
 
-Examples:
+Given
   namespace a { int f(); }
   using a::f;
   int x = f();
-declRefExpr(throughUsingDecl(anything()))
-  matches f
+
+The matcher declRefExpr(throughUsingDecl(anything()))
+matches f
 
   namespace a { class X{}; }
   using a::X;
   X x;
-typeLoc(loc(usingType(throughUsingDecl(anything()))))
-  matches X
+
+The matcher typeLoc(loc(usingType(throughUsingDecl(anything()))))
+matches X
 
 Usable as: Matcher<DeclRefExpr>, Matcher<UsingType>
 
@@ -10460,21 +13816,31 @@

AST Traversal Matchers

X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the declaration of x. -Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) - and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) - and friend class X (matcher = friendDecl(hasType("X")) - and public virtual X (matcher = cxxBaseSpecifier(hasType( - cxxRecordDecl(hasName("X")))) class X {}; void y(X &x) { x; X z; } class Y { friend class X; }; class Z : public virtual X {}; -Example matches class Derived -(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) +The matcher expr(hasType(cxxRecordDecl(hasName("X")))) +matches x and z. +The matcher varDecl(hasType(cxxRecordDecl(hasName("X")))) +matches z. +The matcher friendDecl(hasType(asString("class X"))) +matches friend class X. +The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType( +asString("X"))).bind("b"))) matches +class Z : public virtual X {}, +with cxxBaseSpecifier(...) +matching public virtual X. + +Given class Base {}; class Derived : Base {}; +The matcher +cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))) +matches class Derived : Base {}. + Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>, Matcher<CXXBaseSpecifier> @@ -10484,17 +13850,25 @@

AST Traversal Matchers

Matches if the expression's or declaration's type matches a type
 matcher.
 
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
-            and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
-            and U (matcher = typedefDecl(hasType(asString("int")))
-            and friend class X (matcher = friendDecl(hasType("X"))
-            and public virtual X (matcher = cxxBaseSpecifier(hasType(
-                                              asString("class X")))
+Exmaple
  class X {};
  void y(X &x) { x; X z; }
  typedef int U;
  class Y { friend class X; };
  class Z : public virtual X {};
+
+The matcher expr(hasType(cxxRecordDecl(hasName("X"))))
+matches x and z.
+The matcher varDecl(hasType(cxxRecordDecl(hasName("X"))))
+matches z
+The matcher typedefDecl(hasType(asString("int")))
+matches typedef int U
+The matcher friendDecl(hasType(asString("class X")))
+matches friend class X
+The matcher cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(hasType(
+asString("X"))).bind("b"))) matches class Z : public virtual X {},
+with cxxBaseSpecifier(...)
+matching public virtual X.
 
@@ -10502,9 +13876,13 @@

AST Traversal Matchers

Matches a variable declaration that has an initializer expression
 that matches the given matcher.
 
-Example matches x (matcher = varDecl(hasInitializer(callExpr())))
-  bool y() { return true; }
-  bool x = y();
+Given
+  int y() { return 0; }
+  void foo() {
+    int x = y();
+  }
+The matcher varDecl(hasInitializer(callExpr()))
+matches x
 
@@ -10524,13 +13902,22 @@

AST Traversal Matchers

template <typename T, typename U> void f(T&& t, U&& u) {} - bool B = false; - f(R, B); -templateSpecializationType(forEachTemplateArgument(isExpr(expr()))) - matches twice, with expr() matching 'R * 2' and 'R * 4' -functionDecl(forEachTemplateArgument(refersToType(builtinType()))) - matches the specialization f<unsigned, bool> twice, for 'unsigned' - and 'bool' + void foo() { + bool B = false; + f(R, B); + } + +The matcher +templateSpecializationType(forEachTemplateArgument(isExpr(expr().bind("t_arg")))) +matches Matrix<int, R * 2, R * 4> twice, with +expr() matching R * 2 and +R * 4. +The matcher +functionDecl(forEachTemplateArgument(refersToType(qualType().bind("type")))) +matches the specialization of f twice, +with qualType() matching +unsigned and +bool. @@ -10543,9 +13930,11 @@

AST Traversal Matchers

Given template<typename T> class A {}; A<int> a; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( - hasTypeLoc(loc(asString("int"))))))) - matches `A<int> a`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( +hasTypeLoc(loc(asString("int"))))))))) matches A<int> a. @@ -10559,15 +13948,19 @@

AST Traversal Matchers

template<> class A<double> {}; A<int> a; - template<typename T> f() {}; + template<typename T> void f() {}; void func() { f<int>(); }; -classTemplateSpecializationDecl(hasAnyTemplateArgument( - refersToType(asString("int")))) - matches the specialization A<int> -functionDecl(hasAnyTemplateArgument(refersToType(asString("int")))) - matches the specialization f<int> +The matcher classTemplateSpecializationDecl( + hasAnyTemplateArgument( + refersToType(asString("int")))) +matches class A<int>. + +The matcher +functionDecl(hasAnyTemplateArgument( + refersToType(asString("int")))) +matches the instantiation of f. @@ -10580,9 +13973,12 @@

AST Traversal Matchers

template<typename T, typename U> class A {}; A<double, int> b; A<int, double> c; -varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, - hasTypeLoc(loc(asString("double"))))))) - matches `A<double, int> b`, but not `A<int, double> c`. + +The matcher +varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, +hasTypeLoc(loc(asString("double"))))))))) +matches A<double, int> b, but not double> c}. @@ -10593,17 +13989,20 @@

AST Traversal Matchers

Given template<typename T, typename U> class A {}; - A<bool, int> b; - A<int, bool> c; + A<double, int> b; + A<int, double> c; template<typename T> void f() {} void func() { f<int>(); }; + +The matcher classTemplateSpecializationDecl(hasTemplateArgument( 1, refersToType(asString("int")))) - matches the specialization A<bool, int> +matches the specialization class A<double, int>. -functionDecl(hasTemplateArgument(0, refersToType(asString("int")))) - matches the specialization f<int> +The matcher functionDecl(hasTemplateArgument(0, + refersToType(asString("int")))) +matches the specialization of f. @@ -10615,9 +14014,10 @@

AST Traversal Matchers

void f(int b) { int a[b]; } +The matcher variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to( varDecl(hasName("b"))))))) - matches "int a[b]" +matches int[b] @@ -10628,20 +14028,22 @@

AST Traversal Matchers

other declarations of the same function or coroutine. Given +void foo() { for (;;) {} -forStmt(hasBody(compoundStmt())) - matches 'for (;;) {}' +} +The matcher forStmt(hasBody(compoundStmt().bind("body"))) +matches for (;;) {} with compoundStmt() - matching '{}' + matching {} Given void f(); void f() {} -functionDecl(hasBody(compoundStmt())) - matches 'void f() {}' +The matcher functionDecl(hasBody(compoundStmt().bind("compound"))) +f with compoundStmt() - matching '{}' - but does not match 'void f();' +matching {} +but does not match void f(); @@ -10649,8 +14051,13 @@

AST Traversal Matchers

Matches the condition expression of an if statement, for loop,
 switch statement or conditional operator.
 
-Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
+Given
+void foo() {
   if (true) {}
+}
+
+The matcher ifStmt(hasCondition(cxxBoolLiteral(equals(true))))
+if (true) {}
 
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 14907e7db18de..a9cd68d392c75 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -81,6 +81,24 @@ C++ Specific Potentially Breaking Changes template void f(); +- During constant evaluation, comparisons between different evaluations of the + same string literal are now correctly treated as non-constant, and comparisons + between string literals that cannot possibly overlap in memory are now treated + as constant. This updates Clang to match the anticipated direction of open core + issue `CWG2765 `, but is subject to change once that + issue is resolved. + + .. code-block:: c++ + + constexpr const char *f() { return "hello"; } + constexpr const char *g() { return "world"; } + // Used to evaluate to false, now error: non-constant comparison. + constexpr bool a = f() == f(); + // Might evaluate to true or false, as before. + bool at_runtime() { return f() == f(); } + // Was error, now evaluates to false. + constexpr bool b = f() == g(); + ABI Changes in This Version --------------------------- @@ -550,6 +568,9 @@ AST Matchers - Fixed a crash when traverse lambda expr with invalid captures. (#GH106444) +- The examples in the AST matcher reference are now tested and additional + examples and descriptions were added. + clang-format ------------ diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 57d78f867bab6..4f03388bc87bd 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -2369,14 +2369,16 @@ are listed below. $ cd $P/bar && clang -c -funique-internal-linkage-names name_conflict.c $ cd $P && clang foo/name_conflict.o && bar/name_conflict.o -.. option:: -fbasic-block-sections=[labels, all, list=, none] +.. option:: -f[no]-basic-block-address-map: + Emits a ``SHT_LLVM_BB_ADDR_MAP`` section which includes address offsets for each + basic block in the program, relative to the parent function address. + + +.. option:: -fbasic-block-sections=[all, list=, none] Controls how Clang emits text sections for basic blocks. With values ``all`` and ``list=``, each basic block or a subset of basic blocks can be placed - in its own unique section. With the "labels" value, normal text sections are - emitted, but a ``.bb_addr_map`` section is emitted which includes address - offsets for each basic block in the program, relative to the parent function - address. + in its own unique section. With the ``list=`` option, a file containing the subset of basic blocks that need to placed in unique sections can be specified. The format of the diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index c124fefc78611..9847d449d76d0 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -1008,6 +1008,241 @@ optin.portability.UnixAPI """"""""""""""""""""""""" Finds implementation-defined behavior in UNIX/Posix functions. + +optin.taint +^^^^^^^^^^^ + +Checkers implementing +`taint analysis `_. + +.. _optin-taint-GenericTaint: + +optin.taint.GenericTaint (C, C++) +""""""""""""""""""""""""""""""""" + +Taint analysis identifies potential security vulnerabilities where the +attacker can inject malicious data to the program to execute an attack +(privilege escalation, command injection, SQL injection etc.). + +The malicious data is injected at the taint source (e.g. ``getenv()`` call) +which is then propagated through function calls and being used as arguments of +sensitive operations, also called as taint sinks (e.g. ``system()`` call). + +One can defend against this type of vulnerability by always checking and +sanitizing the potentially malicious, untrusted user input. + +The goal of the checker is to discover and show to the user these potential +taint source-sink pairs and the propagation call chain. + +The most notable examples of taint sources are: + + - data from network + - files or standard input + - environment variables + - data from databases + +Let us examine a practical example of a Command Injection attack. + +.. code-block:: c + + // Command Injection Vulnerability Example + int main(int argc, char** argv) { + char cmd[2048] = "/bin/cat "; + char filename[1024]; + printf("Filename:"); + scanf (" %1023[^\n]", filename); // The attacker can inject a shell escape here + strcat(cmd, filename); + system(cmd); // Warning: Untrusted data is passed to a system call + } + +The program prints the content of any user specified file. +Unfortunately the attacker can execute arbitrary commands +with shell escapes. For example with the following input the `ls` command is also +executed after the contents of `/etc/shadow` is printed. +`Input: /etc/shadow ; ls /` + +The analysis implemented in this checker points out this problem. + +One can protect against such attack by for example checking if the provided +input refers to a valid file and removing any invalid user input. + +.. code-block:: c + + // No vulnerability anymore, but we still get the warning + void sanitizeFileName(char* filename){ + if (access(filename,F_OK)){// Verifying user input + printf("File does not exist\n"); + filename[0]='\0'; + } + } + int main(int argc, char** argv) { + char cmd[2048] = "/bin/cat "; + char filename[1024]; + printf("Filename:"); + scanf (" %1023[^\n]", filename); // The attacker can inject a shell escape here + sanitizeFileName(filename);// filename is safe after this point + if (!filename[0]) + return -1; + strcat(cmd, filename); + system(cmd); // Superfluous Warning: Untrusted data is passed to a system call + } + +Unfortunately, the checker cannot discover automatically that the programmer +have performed data sanitation, so it still emits the warning. + +One can get rid of this superfluous warning by telling by specifying the +sanitation functions in the taint configuration file (see +:doc:`user-docs/TaintAnalysisConfiguration`). + +.. code-block:: YAML + + Filters: + - Name: sanitizeFileName + Args: [0] + +The clang invocation to pass the configuration file location: + +.. code-block:: bash + + clang --analyze -Xclang -analyzer-config -Xclang optin.taint.TaintPropagation:Config=`pwd`/taint_config.yml ... + +If you are validating your inputs instead of sanitizing them, or don't want to +mention each sanitizing function in our configuration, +you can use a more generic approach. + +Introduce a generic no-op `csa_mark_sanitized(..)` function to +tell the Clang Static Analyzer +that the variable is safe to be used on that analysis path. + +.. code-block:: c + + // Marking sanitized variables safe. + // No vulnerability anymore, no warning. + + // User csa_mark_sanitize function is for the analyzer only + #ifdef __clang_analyzer__ + void csa_mark_sanitized(const void *); + #endif + + int main(int argc, char** argv) { + char cmd[2048] = "/bin/cat "; + char filename[1024]; + printf("Filename:"); + scanf (" %1023[^\n]", filename); + if (access(filename,F_OK)){// Verifying user input + printf("File does not exist\n"); + return -1; + } + #ifdef __clang_analyzer__ + csa_mark_sanitized(filename); // Indicating to CSA that filename variable is safe to be used after this point + #endif + strcat(cmd, filename); + system(cmd); // No warning + } + +Similarly to the previous example, you need to +define a `Filter` function in a `YAML` configuration file +and add the `csa_mark_sanitized` function. + +.. code-block:: YAML + + Filters: + - Name: csa_mark_sanitized + Args: [0] + +Then calling `csa_mark_sanitized(X)` will tell the analyzer that `X` is safe to +be used after this point, because its contents are verified. It is the +responsibility of the programmer to ensure that this verification was indeed +correct. Please note that `csa_mark_sanitized` function is only declared and +used during Clang Static Analysis and skipped in (production) builds. + +Further examples of injection vulnerabilities this checker can find. + +.. code-block:: c + + void test() { + char x = getchar(); // 'x' marked as tainted + system(&x); // warn: untrusted data is passed to a system call + } + + // note: compiler internally checks if the second param to + // sprintf is a string literal or not. + // Use -Wno-format-security to suppress compiler warning. + void test() { + char s[10], buf[10]; + fscanf(stdin, "%s", s); // 's' marked as tainted + + sprintf(buf, s); // warn: untrusted data used as a format string + } + +There are built-in sources, propagations and sinks even if no external taint +configuration is provided. + +Default sources: + ``_IO_getc``, ``fdopen``, ``fopen``, ``freopen``, ``get_current_dir_name``, + ``getch``, ``getchar``, ``getchar_unlocked``, ``getwd``, ``getcwd``, + ``getgroups``, ``gethostname``, ``getlogin``, ``getlogin_r``, ``getnameinfo``, + ``gets``, ``gets_s``, ``getseuserbyname``, ``readlink``, ``readlinkat``, + ``scanf``, ``scanf_s``, ``socket``, ``wgetch`` + +Default propagations rules: + ``atoi``, ``atol``, ``atoll``, ``basename``, ``dirname``, ``fgetc``, + ``fgetln``, ``fgets``, ``fnmatch``, ``fread``, ``fscanf``, ``fscanf_s``, + ``index``, ``inflate``, ``isalnum``, ``isalpha``, ``isascii``, ``isblank``, + ``iscntrl``, ``isdigit``, ``isgraph``, ``islower``, ``isprint``, ``ispunct``, + ``isspace``, ``isupper``, ``isxdigit``, ``memchr``, ``memrchr``, ``sscanf``, + ``getc``, ``getc_unlocked``, ``getdelim``, ``getline``, ``getw``, ``memcmp``, + ``memcpy``, ``memmem``, ``memmove``, ``mbtowc``, ``pread``, ``qsort``, + ``qsort_r``, ``rawmemchr``, ``read``, ``recv``, ``recvfrom``, ``rindex``, + ``strcasestr``, ``strchr``, ``strchrnul``, ``strcasecmp``, ``strcmp``, + ``strcspn``, ``strncasecmp``, ``strncmp``, ``strndup``, + ``strndupa``, ``strpbrk``, ``strrchr``, ``strsep``, ``strspn``, + ``strstr``, ``strtol``, ``strtoll``, ``strtoul``, ``strtoull``, ``tolower``, + ``toupper``, ``ttyname``, ``ttyname_r``, ``wctomb``, ``wcwidth`` + +Default sinks: + ``printf``, ``setproctitle``, ``system``, ``popen``, ``execl``, ``execle``, + ``execlp``, ``execv``, ``execvp``, ``execvP``, ``execve``, ``dlopen`` + +Please note that there are no built-in filter functions. + +One can configure their own taint sources, sinks, and propagation rules by +providing a configuration file via checker option +``optin.taint.TaintPropagation:Config``. The configuration file is in +`YAML `_ format. The +taint-related options defined in the config file extend but do not override the +built-in sources, rules, sinks. The format of the external taint configuration +file is not stable, and could change without any notice even in a non-backward +compatible way. + +For a more detailed description of configuration options, please see the +:doc:`user-docs/TaintAnalysisConfiguration`. For an example see +:ref:`clangsa-taint-configuration-example`. + +**Configuration** + +* `Config` Specifies the name of the YAML configuration file. The user can + define their own taint sources and sinks. + +**Related Guidelines** + +* `CWE Data Neutralization Issues + `_ +* `SEI Cert STR02-C. Sanitize data passed to complex subsystems + `_ +* `SEI Cert ENV33-C. Do not call system() + `_ +* `ENV03-C. Sanitize the environment when invoking external programs + `_ + +**Limitations** + +* The taintedness property is not propagated through function calls which are + unknown (or too complex) to the analyzer, unless there is a specific + propagation rule built-in to the checker or given in the YAML configuration + file. This causes potential true positive findings to be lost. + + .. _optin-taint-TaintedAlloc: optin.taint.TaintedAlloc (C, C++) @@ -1026,7 +1261,7 @@ covers the SEI Cert coding standard rule `INT04-C You can silence this warning either by bound checking the ``size`` parameter, or by explicitly marking the ``size`` parameter as sanitized. See the -:ref:`alpha-security-taint-GenericTaint` checker for an example. +:ref:`optin-taint-GenericTaint` checker for an example. .. code-block:: c @@ -2976,7 +3211,7 @@ Warn about buffer overflows (newer checker). buf[0][-1] = 1; // warn } - // note: requires alpha.security.taint check turned on. + // note: requires optin.taint check turned on. void test() { char s[] = "abc"; int x = getchar(); @@ -3009,239 +3244,6 @@ alpha.security.cert SEI CERT checkers which tries to find errors based on their `C coding rules `_. -alpha.security.taint -^^^^^^^^^^^^^^^^^^^^ - -Checkers implementing -`taint analysis `_. - -.. _alpha-security-taint-GenericTaint: - -alpha.security.taint.GenericTaint (C, C++) -"""""""""""""""""""""""""""""""""""""""""" - -Taint analysis identifies potential security vulnerabilities where the -attacker can inject malicious data to the program to execute an attack -(privilege escalation, command injection, SQL injection etc.). - -The malicious data is injected at the taint source (e.g. ``getenv()`` call) -which is then propagated through function calls and being used as arguments of -sensitive operations, also called as taint sinks (e.g. ``system()`` call). - -One can defend against this type of vulnerability by always checking and -sanitizing the potentially malicious, untrusted user input. - -The goal of the checker is to discover and show to the user these potential -taint source-sink pairs and the propagation call chain. - -The most notable examples of taint sources are: - - - data from network - - files or standard input - - environment variables - - data from databases - -Let us examine a practical example of a Command Injection attack. - -.. code-block:: c - - // Command Injection Vulnerability Example - int main(int argc, char** argv) { - char cmd[2048] = "/bin/cat "; - char filename[1024]; - printf("Filename:"); - scanf (" %1023[^\n]", filename); // The attacker can inject a shell escape here - strcat(cmd, filename); - system(cmd); // Warning: Untrusted data is passed to a system call - } - -The program prints the content of any user specified file. -Unfortunately the attacker can execute arbitrary commands -with shell escapes. For example with the following input the `ls` command is also -executed after the contents of `/etc/shadow` is printed. -`Input: /etc/shadow ; ls /` - -The analysis implemented in this checker points out this problem. - -One can protect against such attack by for example checking if the provided -input refers to a valid file and removing any invalid user input. - -.. code-block:: c - - // No vulnerability anymore, but we still get the warning - void sanitizeFileName(char* filename){ - if (access(filename,F_OK)){// Verifying user input - printf("File does not exist\n"); - filename[0]='\0'; - } - } - int main(int argc, char** argv) { - char cmd[2048] = "/bin/cat "; - char filename[1024]; - printf("Filename:"); - scanf (" %1023[^\n]", filename); // The attacker can inject a shell escape here - sanitizeFileName(filename);// filename is safe after this point - if (!filename[0]) - return -1; - strcat(cmd, filename); - system(cmd); // Superfluous Warning: Untrusted data is passed to a system call - } - -Unfortunately, the checker cannot discover automatically that the programmer -have performed data sanitation, so it still emits the warning. - -One can get rid of this superfluous warning by telling by specifying the -sanitation functions in the taint configuration file (see -:doc:`user-docs/TaintAnalysisConfiguration`). - -.. code-block:: YAML - - Filters: - - Name: sanitizeFileName - Args: [0] - -The clang invocation to pass the configuration file location: - -.. code-block:: bash - - clang --analyze -Xclang -analyzer-config -Xclang alpha.security.taint.TaintPropagation:Config=`pwd`/taint_config.yml ... - -If you are validating your inputs instead of sanitizing them, or don't want to -mention each sanitizing function in our configuration, -you can use a more generic approach. - -Introduce a generic no-op `csa_mark_sanitized(..)` function to -tell the Clang Static Analyzer -that the variable is safe to be used on that analysis path. - -.. code-block:: c - - // Marking sanitized variables safe. - // No vulnerability anymore, no warning. - - // User csa_mark_sanitize function is for the analyzer only - #ifdef __clang_analyzer__ - void csa_mark_sanitized(const void *); - #endif - - int main(int argc, char** argv) { - char cmd[2048] = "/bin/cat "; - char filename[1024]; - printf("Filename:"); - scanf (" %1023[^\n]", filename); - if (access(filename,F_OK)){// Verifying user input - printf("File does not exist\n"); - return -1; - } - #ifdef __clang_analyzer__ - csa_mark_sanitized(filename); // Indicating to CSA that filename variable is safe to be used after this point - #endif - strcat(cmd, filename); - system(cmd); // No warning - } - -Similarly to the previous example, you need to -define a `Filter` function in a `YAML` configuration file -and add the `csa_mark_sanitized` function. - -.. code-block:: YAML - - Filters: - - Name: csa_mark_sanitized - Args: [0] - -Then calling `csa_mark_sanitized(X)` will tell the analyzer that `X` is safe to -be used after this point, because its contents are verified. It is the -responsibility of the programmer to ensure that this verification was indeed -correct. Please note that `csa_mark_sanitized` function is only declared and -used during Clang Static Analysis and skipped in (production) builds. - -Further examples of injection vulnerabilities this checker can find. - -.. code-block:: c - - void test() { - char x = getchar(); // 'x' marked as tainted - system(&x); // warn: untrusted data is passed to a system call - } - - // note: compiler internally checks if the second param to - // sprintf is a string literal or not. - // Use -Wno-format-security to suppress compiler warning. - void test() { - char s[10], buf[10]; - fscanf(stdin, "%s", s); // 's' marked as tainted - - sprintf(buf, s); // warn: untrusted data used as a format string - } - -There are built-in sources, propagations and sinks even if no external taint -configuration is provided. - -Default sources: - ``_IO_getc``, ``fdopen``, ``fopen``, ``freopen``, ``get_current_dir_name``, - ``getch``, ``getchar``, ``getchar_unlocked``, ``getwd``, ``getcwd``, - ``getgroups``, ``gethostname``, ``getlogin``, ``getlogin_r``, ``getnameinfo``, - ``gets``, ``gets_s``, ``getseuserbyname``, ``readlink``, ``readlinkat``, - ``scanf``, ``scanf_s``, ``socket``, ``wgetch`` - -Default propagations rules: - ``atoi``, ``atol``, ``atoll``, ``basename``, ``dirname``, ``fgetc``, - ``fgetln``, ``fgets``, ``fnmatch``, ``fread``, ``fscanf``, ``fscanf_s``, - ``index``, ``inflate``, ``isalnum``, ``isalpha``, ``isascii``, ``isblank``, - ``iscntrl``, ``isdigit``, ``isgraph``, ``islower``, ``isprint``, ``ispunct``, - ``isspace``, ``isupper``, ``isxdigit``, ``memchr``, ``memrchr``, ``sscanf``, - ``getc``, ``getc_unlocked``, ``getdelim``, ``getline``, ``getw``, ``memcmp``, - ``memcpy``, ``memmem``, ``memmove``, ``mbtowc``, ``pread``, ``qsort``, - ``qsort_r``, ``rawmemchr``, ``read``, ``recv``, ``recvfrom``, ``rindex``, - ``strcasestr``, ``strchr``, ``strchrnul``, ``strcasecmp``, ``strcmp``, - ``strcspn``, ``strncasecmp``, ``strncmp``, ``strndup``, - ``strndupa``, ``strpbrk``, ``strrchr``, ``strsep``, ``strspn``, - ``strstr``, ``strtol``, ``strtoll``, ``strtoul``, ``strtoull``, ``tolower``, - ``toupper``, ``ttyname``, ``ttyname_r``, ``wctomb``, ``wcwidth`` - -Default sinks: - ``printf``, ``setproctitle``, ``system``, ``popen``, ``execl``, ``execle``, - ``execlp``, ``execv``, ``execvp``, ``execvP``, ``execve``, ``dlopen`` - -Please note that there are no built-in filter functions. - -One can configure their own taint sources, sinks, and propagation rules by -providing a configuration file via checker option -``alpha.security.taint.TaintPropagation:Config``. The configuration file is in -`YAML `_ format. The -taint-related options defined in the config file extend but do not override the -built-in sources, rules, sinks. The format of the external taint configuration -file is not stable, and could change without any notice even in a non-backward -compatible way. - -For a more detailed description of configuration options, please see the -:doc:`user-docs/TaintAnalysisConfiguration`. For an example see -:ref:`clangsa-taint-configuration-example`. - -**Configuration** - -* `Config` Specifies the name of the YAML configuration file. The user can - define their own taint sources and sinks. - -**Related Guidelines** - -* `CWE Data Neutralization Issues - `_ -* `SEI Cert STR02-C. Sanitize data passed to complex subsystems - `_ -* `SEI Cert ENV33-C. Do not call system() - `_ -* `ENV03-C. Sanitize the environment when invoking external programs - `_ - -**Limitations** - -* The taintedness property is not propagated through function calls which are - unknown (or too complex) to the analyzer, unless there is a specific - propagation rule built-in to the checker or given in the YAML configuration - file. This causes potential true positive findings to be lost. - alpha.unix ^^^^^^^^^^ @@ -3440,6 +3442,27 @@ Check for non-determinism caused by sorting of pointers. alpha.WebKit ^^^^^^^^^^^^ +.. _alpha-webkit-NoUncheckedPtrMemberChecker: + +alpha.webkit.NoUncheckedPtrMemberChecker +"""""""""""""""""""""""""""""""""""""""" +Raw pointers and references to an object which supports CheckedPtr or CheckedRef can't be used as class members. Only CheckedPtr, CheckedRef, RefPtr, or Ref are allowed. + +.. code-block:: cpp + + struct CheckableObj { + void incrementPtrCount() {} + void decrementPtrCount() {} + }; + + struct Foo { + CheckableObj* ptr; // warn + CheckableObj& ptr; // warn + // ... + }; + +See `WebKit Guidelines for Safer C++ Programming `_ for details. + .. _alpha-webkit-UncountedCallArgsChecker: alpha.webkit.UncountedCallArgsChecker diff --git a/clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst b/clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst index 67e71d558f2ce..4849a553cb2ce 100644 --- a/clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst +++ b/clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.rst @@ -4,10 +4,10 @@ Taint Analysis Configuration The Clang Static Analyzer uses taint analysis to detect injection vulnerability related issues in code. The backbone of taint analysis in the Clang SA is the ``TaintPropagation`` modeling checker. -The reports are emitted via the :ref:`alpha-security-taint-GenericTaint` checker. +The reports are emitted via the :ref:`optin-taint-GenericTaint` checker. The ``TaintPropagation`` checker has a default taint-related configuration. The built-in default settings are defined in code, and they are always in effect. -The checker also provides a configuration interface for extending the default settings via the ``alpha.security.taint.TaintPropagation:Config`` checker config parameter +The checker also provides a configuration interface for extending the default settings via the ``optin.taint.TaintPropagation:Config`` checker config parameter by providing a configuration file to the in `YAML `_ format. This documentation describes the syntax of the configuration file and gives the informal semantics of the configuration options. diff --git a/clang/docs/doxygen.cfg.in b/clang/docs/doxygen.cfg.in index 251afb179b205..1d1deb0fcfb07 100644 --- a/clang/docs/doxygen.cfg.in +++ b/clang/docs/doxygen.cfg.in @@ -220,7 +220,14 @@ TAB_SIZE = 2 # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. -ALIASES = +ALIASES += compile_args{1}="Compiled with \1.\n" +ALIASES += matcher{1}="\1" +ALIASES += matcher{2$}="\2" +ALIASES += match{1}="\1" +ALIASES += match{2$}="\2" +ALIASES += nomatch{1}="\1" +ALIASES += header{1}="\code" +ALIASES += endheader="\endcode" # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" diff --git a/clang/docs/tools/dump_ast_matchers.py b/clang/docs/tools/dump_ast_matchers.py index 705ff0d4d4098..a3feac8728c65 100755 --- a/clang/docs/tools/dump_ast_matchers.py +++ b/clang/docs/tools/dump_ast_matchers.py @@ -100,15 +100,72 @@ def extract_result_types(comment): comment = m.group(1) +def find_next_closing_rbrace( + data: str, start_pos: int, braces_to_be_matched: int +) -> int: + """Finds the location of the closing rbrace '}' inside of data.""" + """'start_pos' should be one past the opening lbrace and braces_to_be_matched is initialized with 0""" + next_lbrace = data.find("{", start_pos) + next_rbrace = data.find("}", start_pos) + if next_lbrace != -1: + if next_lbrace < next_rbrace: + return find_next_closing_rbrace( + data, next_lbrace + 1, braces_to_be_matched + 1 + ) + if braces_to_be_matched == 0: + return next_rbrace + return find_next_closing_rbrace(data, next_rbrace + 1, braces_to_be_matched - 1) + + if braces_to_be_matched > 0: + return find_next_closing_rbrace(data, next_rbrace + 1, braces_to_be_matched - 1) + + return next_rbrace + + def strip_doxygen(comment): """Returns the given comment without \-escaped words.""" - # If there is only a doxygen keyword in the line, delete the whole line. - comment = re.sub(r"^\\[^\s]+\n", r"", comment, flags=re.M) - # If there is a doxygen \see command, change the \see prefix into "See also:". # FIXME: it would be better to turn this into a link to the target instead. comment = re.sub(r"\\see", r"See also:", comment) + commands: list[str] = [ + "\\compile_args{", + "\\matcher{", + "\\match{", + "\\nomatch{", + ] + + for command in commands: + delete_command = command == "\\compile_args{" + command_begin_loc = comment.find(command) + while command_begin_loc != -1: + command_end_loc = command_begin_loc + len(command) + end_brace_loc = find_next_closing_rbrace(comment, command_end_loc + 1, 0) + if end_brace_loc == -1: + print("found unmatched {") + command_begin_loc = comment.find(command, command_end_loc) + continue + + if delete_command: + comment = comment[0:command_begin_loc] + comment[end_brace_loc + 1 :] + command_begin_loc = comment.find(command, command_begin_loc) + continue + + tag_seperator_loc = comment.find("$", command_end_loc) + if tag_seperator_loc != -1 and tag_seperator_loc < end_brace_loc: + command_end_loc = tag_seperator_loc + 1 + + comment = ( + comment[0:command_begin_loc] + + comment[command_end_loc:end_brace_loc] + + comment[end_brace_loc + 1 :] + ) + + command_begin_loc = comment.find(command, command_begin_loc) + + # If there is only a doxygen keyword in the line, delete the whole line. + comment = re.sub(r"^\\[^\s]+\n", r"", comment, flags=re.M) + # Delete the doxygen command and the following whitespace. comment = re.sub(r"\\[^\s]+\s+", r"", comment) return comment @@ -191,8 +248,9 @@ def act_on_decl(declaration, comment, allowed_types): definition. """ if declaration.strip(): - - if re.match(r"^\s?(#|namespace|using|template using|})", declaration): + if re.match( + r"^\s?(#|namespace|using|template using|})", declaration + ): return # Node matchers are defined by writing: diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 1984310df0442..3db9871a4b07b 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -253,7 +253,7 @@ class ASTContext : public RefCountedBase { mutable llvm::FoldingSet BitIntTypes; mutable llvm::ContextualFoldingSet DependentBitIntTypes; - llvm::FoldingSet BTFTagAttributedTypes; + mutable llvm::FoldingSet BTFTagAttributedTypes; llvm::FoldingSet HLSLAttributedResourceTypes; mutable llvm::FoldingSet CountAttributedTypes; @@ -324,6 +324,14 @@ class ASTContext : public RefCountedBase { /// This is lazily created. This is intentionally not serialized. mutable llvm::StringMap StringLiteralCache; + /// The next string literal "version" to allocate during constant evaluation. + /// This is used to distinguish between repeated evaluations of the same + /// string literal. + /// + /// We don't need to serialize this because constants get re-evaluated in the + /// current file before they are compared locally. + unsigned NextStringLiteralVersion = 0; + /// MD5 hash of CUID. It is calculated when first used and cached by this /// data member. mutable std::string CUIDHash; @@ -1369,10 +1377,21 @@ class ASTContext : public RefCountedBase { /// calling T.withConst(). QualType getConstType(QualType T) const { return T.withConst(); } + /// Rebuild a type, preserving any existing type sugar. For function types, + /// you probably want to just use \c adjustFunctionResultType and friends + /// instead. + QualType adjustType(QualType OldType, + llvm::function_ref Adjust) const; + /// Change the ExtInfo on a function type. const FunctionType *adjustFunctionType(const FunctionType *Fn, FunctionType::ExtInfo EInfo); + /// Change the result type of a function type, preserving sugar such as + /// attributed types. + QualType adjustFunctionResultType(QualType FunctionType, + QualType NewResultType); + /// Adjust the given function result type. CanQualType getCanonicalFunctionResultType(QualType ResultType) const; @@ -1702,7 +1721,7 @@ class ASTContext : public RefCountedBase { QualType equivalentType) const; QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr, - QualType Wrapped); + QualType Wrapped) const; QualType getHLSLAttributedResourceType( QualType Wrapped, QualType Contained, @@ -3289,6 +3308,10 @@ class ASTContext : public RefCountedBase { /// PredefinedExpr to cache evaluated results. StringLiteral *getPredefinedStringLiteralFromCache(StringRef Key) const; + /// Return the next version number to be used for a string literal evaluated + /// as part of constant evaluation. + unsigned getNextStringLiteralVersion() { return NextStringLiteralVersion++; } + /// Return a declaration for the global GUID object representing the given /// GUID value. MSGuidDecl *getMSGuidDecl(MSGuidDeclParts Parts) const; diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 0600ecc4d14a1..7ff35d73df599 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -133,6 +133,10 @@ class TranslationUnitDecl : public Decl, static TranslationUnitDecl *castFromDeclContext(const DeclContext *DC) { return static_cast(const_cast(DC)); } + + /// Retrieves the canonical declaration of this translation unit. + TranslationUnitDecl *getCanonicalDecl() override { return getFirstDecl(); } + const TranslationUnitDecl *getCanonicalDecl() const { return getFirstDecl(); } }; /// Represents a `#pragma comment` line. Always a child of diff --git a/clang/include/clang/AST/DeclID.h b/clang/include/clang/AST/DeclID.h index f4607e42c4be3..49964b43c7d1d 100644 --- a/clang/include/clang/AST/DeclID.h +++ b/clang/include/clang/AST/DeclID.h @@ -189,6 +189,7 @@ class LocalDeclID : public DeclIDBase { // Every Decl ID is a local decl ID to the module being writing in ASTWriter. friend class ASTWriter; friend class GlobalDeclID; + friend struct llvm::DenseMapInfo; public: LocalDeclID() : Base() {} @@ -267,6 +268,27 @@ template <> struct DenseMapInfo { } }; +template <> struct DenseMapInfo { + using LocalDeclID = clang::LocalDeclID; + using DeclID = LocalDeclID::DeclID; + + static LocalDeclID getEmptyKey() { + return LocalDeclID(DenseMapInfo::getEmptyKey()); + } + + static LocalDeclID getTombstoneKey() { + return LocalDeclID(DenseMapInfo::getTombstoneKey()); + } + + static unsigned getHashValue(const LocalDeclID &Key) { + return DenseMapInfo::getHashValue(Key.getRawValue()); + } + + static bool isEqual(const LocalDeclID &L, const LocalDeclID &R) { + return L == R; + } +}; + } // namespace llvm #endif diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index f1c72efc23878..2dc96184a0460 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -39,6 +39,158 @@ // See ASTMatchFinder.h for how to use the generated matchers to run over // an AST. // +// The doxygen comments on matchers are used to: +// - create the doxygen documentation +// - get information in the editor via signature help and goto definition +// - generate the AST matcher reference html file +// - test the documentation using a special syntax +// +// Test Annotations: +// +// The automatic testing uses doxygen commands (aliases) to extract the +// relevant information about an example of using a matcher from the +// documentation. +// +// \header{a.h} +// \endheader <- zero or more header +// +// \code +// int a = 42; +// \endcode +// \compile_args{-std=c++,c23-or-later} <- optional, the std flag supports +// std ranges and +// whole languages +// +// \matcher{expr()} <- one or more matchers in succession +// \matcher{integerLiteral()} <- one or more matchers in succession +// both matcher will have to match the +// following matches +// \match{42} <- one or more matches in succession +// +// \matcher{varDecl()} <- new matcher resets the context, the above +// \match will not count for this new +// matcher(-group) +// \match{int a = 42} <- only applies to the previous matcher (not to the +// previous case) +// +// +// The above block can be repeated inside a doxygen command for multiple code +// examples for a single matcher. The test generation script will only look for +// these annotations and ignore anything else like `\c` or the sentences where +// these annotations are embedded into: `The matcher \matcher{expr()} matches +// the number \match{42}.`. +// +// Language Grammar: +// +// [] denotes an optional, and <> denotes user-input +// +// compile_args j:= \compile_args{[;]} +// matcher_tag_key ::= type +// match_tag_key ::= type || std || count || sub +// matcher_tags ::= [matcher_tag_key=;]matcher_tag_key= +// match_tags ::= [match_tag_key=;]match_tag_key= +// matcher ::= \matcher{[matcher_tags$]} +// matchers ::= [matcher] matcher +// match ::= \match{[match_tags$]} +// matches ::= [match] match +// case ::= matchers matches +// cases ::= [case] case +// header-block ::= \header{} \endheader +// code-block ::= \code \endcode +// testcase ::= code-block [compile_args] cases +// +// Language Standard Versions: +// +// The 'std' tag and '\compile_args' support specifying a specific language +// version, a whole language and all of its versions, and thresholds (implies +// ranges). Multiple arguments are passed with a ',' separator. For a language +// and version to execute a tested matcher, it has to match the specified +// '\compile_args' for the code, and the 'std' tag for the matcher. Predicates +// for the 'std' compiler flag are used with disjunction between languages +// (e.g. 'c || c++') and conjunction for all predicates specific to each +// language (e.g. 'c++11-or-later && c++23-or-earlier'). +// +// Examples: +// - `c` all available versions of C +// - `c++11` only C++11 +// - `c++11-or-later` C++11 or later +// - `c++11-or-earlier` C++11 or earlier +// - `c++11-or-later,c++23-or-earlier,c` all of C and C++ between 11 and +// 23 (inclusive) +// - `c++11-23,c` same as above +// +// Tags +// +// `type`: +// **Match types** are used to select where the string that is used to check if +// a node matches comes from. Available: `code`, `name`, `typestr`, +// `typeofstr`. The default is `code`. +// +// - `code`: Forwards to `tooling::fixit::getText(...)` and should be the +// preferred way to show what matches. +// - `name`: Casts the match to a `NamedDecl` and returns the result of +// `getNameAsString`. Useful when the matched AST node is not easy to spell +// out (`code` type), e.g., namespaces or classes with many members. +// - `typestr`: Returns the result of `QualType::getAsString` for the type +// derived from `Type` (otherwise, if it is derived from `Decl`, recurses with +// `Node->getTypeForDecl()`) +// +// **Matcher types** are used to mark matchers as sub-matcher with 'sub' or as +// deactivated using 'none'. Testing sub-matcher is not implemented. +// +// `count`: +// Specifying a 'count=n' on a match will result in a test that requires that +// the specified match will be matched n times. Default is 1. +// +// `std`: +// A match allows specifying if it matches only in specific language versions. +// This may be needed when the AST differs between language versions. +// +// `sub`: +// The `sub` tag on a `\match` will indicate that the match is for a node of a +// bound sub-matcher. E.g., `\matcher{expr(expr().bind("inner"))}` has a +// sub-matcher that binds to `inner`, which is the value for the `sub` tag of +// the expected match for the sub-matcher `\match{sub=inner$...}`. Currently, +// sub-matchers are not tested in any way. +// +// +// What if ...? +// +// ... I want to add a matcher? +// +// Add a doxygen comment to the matcher with a code example, corresponding +// matchers and matches, that shows what the matcher is supposed to do. Specify +// the compile arguments/supported languages if required, and run `ninja +// check-clang-unit` to test the documentation. +// +// ... the example I wrote is wrong? +// +// The test-failure output of the generated test file will provide information +// about +// - where the generated test file is located +// - which line in `ASTMatcher.h` the example is from +// - which matches were: found, not-(yet)-found, expected +// - in case of an unexpected match: what the node looks like using the +// different `type`s +// - the language version and if the test ran with a windows `-target` flag +// (also in failure summary) +// +// ... I don't adhere to the required order of the syntax? +// +// The script will diagnose any found issues, such as `matcher is missing an +// example` with a `file:line:` prefix, which should provide enough information +// about the issue. +// +// ... the script diagnoses a false-positive issue with a doxygen comment? +// +// It hopefully shouldn't, but if you, e.g., added some non-matcher code and +// documented it with doxygen, then the script will consider that as a matcher +// documentation. As a result, the script will print that it detected a +// mismatch between the actual and the expected number of failures. If the +// diagnostic truly is a false-positive, change the +// `expected_failure_statistics` at the top of the +// `generate_ast_matcher_doc_tests.py` file. +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H @@ -160,13 +312,13 @@ using AttrMatcher = internal::Matcher; /// additional constraint. This will often be used with an explicit conversion /// to an \c internal::Matcher<> type such as \c TypeMatcher. /// -/// Example: \c DeclarationMatcher(anything()) matches all declarations, e.g., +/// Given /// \code -/// "int* p" and "void f()" in /// int* p; /// void f(); /// \endcode -/// +/// The matcher \matcher{decl(anything())} +/// matches \match{int* p} and \match{void f()}. /// Usable as: Any Matcher inline internal::TrueMatcher anything() { return internal::TrueMatcher(); } @@ -175,12 +327,13 @@ inline internal::TrueMatcher anything() { return internal::TrueMatcher(); } /// Given /// \code /// int X; -/// namespace NS { -/// int Y; -/// } // namespace NS +/// namespace NS { int Y; } /// \endcode -/// decl(hasDeclContext(translationUnitDecl())) -/// matches "int X", but not "int Y". +/// \compile_args{-std=c++} +/// The matcher \matcher{namedDecl(hasDeclContext(translationUnitDecl()))} +/// matches \match{int X} and \match{namespace NS { int Y; }}, +/// but does not match \nomatch{int Y} because its decl-context is the +/// namespace \c NS . extern const internal::VariadicDynCastAllOfMatcher translationUnitDecl; @@ -191,8 +344,10 @@ extern const internal::VariadicDynCastAllOfMatcher /// typedef int X; /// using Y = int; /// \endcode -/// typedefDecl() -/// matches "typedef int X", but not "using Y = int" +/// \compile_args{-std=c++} +/// The matcher \matcher{typedefDecl()} +/// matches \match{typedef int X}, +/// but does not match \nomatch{using Y = int}. extern const internal::VariadicDynCastAllOfMatcher typedefDecl; @@ -203,8 +358,9 @@ extern const internal::VariadicDynCastAllOfMatcher /// typedef int X; /// using Y = int; /// \endcode -/// typedefNameDecl() -/// matches "typedef int X" and "using Y = int" +/// \compile_args{-std=c++11-or-later} +/// The matcher \matcher{typedefNameDecl()} +/// matches \match{typedef int X} and \match{using Y = int}. extern const internal::VariadicDynCastAllOfMatcher typedefNameDecl; @@ -215,34 +371,45 @@ extern const internal::VariadicDynCastAllOfMatcher /// typedef int X; /// using Y = int; /// \endcode -/// typeAliasDecl() -/// matches "using Y = int", but not "typedef int X" +/// \compile_args{-std=c++11-or-later} +/// The matcher \matcher{typeAliasDecl()} +/// matches \match{using Y = int}, +/// but does not match \nomatch{typedef int X}. extern const internal::VariadicDynCastAllOfMatcher typeAliasDecl; /// Matches type alias template declarations. /// -/// typeAliasTemplateDecl() matches +/// Given /// \code -/// template -/// using Y = X; +/// template struct X {}; +/// template using Y = X; /// \endcode +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher \matcher{typeAliasTemplateDecl()} +/// matches \match{template using Y = X}. extern const internal::VariadicDynCastAllOfMatcher typeAliasTemplateDecl; /// Matches AST nodes that were expanded within the main-file. /// -/// Example matches X but not Y -/// (matcher = cxxRecordDecl(isExpansionInMainFile()) -/// \code -/// #include -/// class X {}; -/// \endcode -/// Y.h: +/// Given the header \c Y.h +/// \header{Y.h} +/// #pragma once +/// typedef int my_header_int; +/// \endheader +/// and the source file /// \code -/// class Y {}; +/// #include "Y.h" +/// typedef int my_main_file_int; +/// my_main_file_int a = 0; +/// my_header_int b = 1; /// \endcode /// +/// The matcher \matcher{typedefDecl(isExpansionInMainFile())} +/// matches \match{typedef int my_main_file_int}, +/// but does not match \nomatch{typedef int my_header_int}. +/// /// Usable as: Matcher, Matcher, Matcher AST_POLYMORPHIC_MATCHER(isExpansionInMainFile, AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc)) { @@ -253,16 +420,21 @@ AST_POLYMORPHIC_MATCHER(isExpansionInMainFile, /// Matches AST nodes that were expanded within system-header-files. /// -/// Example matches Y but not X -/// (matcher = cxxRecordDecl(isExpansionInSystemHeader()) +/// Given the header \c SystemHeader.h +/// \header{system_include/SystemHeader.h} +/// #pragma once +/// int header(); +/// \endheader +/// and the source code /// \code /// #include -/// class X {}; -/// \endcode -/// SystemHeader.h: -/// \code -/// class Y {}; +/// static int main_file(); /// \endcode +/// \compile_args{-isystemsystem_include/} +/// +/// The matcher \matcher{type=none$functionDecl(isExpansionInSystemHeader())} +/// matches \match{int header()}, +/// but does not match \nomatch{static int main_file()}. /// /// Usable as: Matcher, Matcher, Matcher AST_POLYMORPHIC_MATCHER(isExpansionInSystemHeader, @@ -278,17 +450,32 @@ AST_POLYMORPHIC_MATCHER(isExpansionInSystemHeader, /// Matches AST nodes that were expanded within files whose name is /// partially matching a given regex. /// -/// Example matches Y but not X -/// (matcher = cxxRecordDecl(isExpansionInFileMatching("AST.*")) -/// \code -/// #include "ASTMatcher.h" -/// class X {}; -/// \endcode -/// ASTMatcher.h: -/// \code -/// class Y {}; +/// Given the headers \c Y.h +/// \header{Y.h} +/// #pragma once +/// typedef int my_y_int; +/// \endheader +/// and \c X.h +/// \header{X.h} +/// #pragma once +/// typedef int my_x_int; +/// \endheader +/// and the source code +/// \code +/// #include "X.h" +/// #include "Y.h" +/// typedef int my_main_file_int; +/// my_main_file_int a = 0; +/// my_x_int b = 1; +/// my_y_int c = 2; /// \endcode /// +/// The matcher +/// \matcher{type=none$typedefDecl(isExpansionInFileMatching("Y.h"))} +/// matches \match{typedef int my_y_int}, +/// but does not match \nomatch{typedef int my_main_file_int} or +/// \nomatch{typedef int my_x_int}. +/// /// Usable as: Matcher, Matcher, Matcher AST_POLYMORPHIC_MATCHER_REGEX(isExpansionInFileMatching, AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, @@ -313,6 +500,17 @@ AST_POLYMORPHIC_MATCHER_REGEX(isExpansionInFileMatching, /// Does not match if only part of the statement is expanded from that macro or /// if different parts of the statement are expanded from different /// appearances of the macro. +/// +/// Given +/// \code +/// #define A 0 +/// #define B A +/// int c = B; +/// \endcode +/// +/// The matcher \matcher{integerLiteral(isExpandedFromMacro("A"))} +/// matches the literal expanded at the initializer \match{B} of the variable +/// \c c . AST_POLYMORPHIC_MATCHER_P(isExpandedFromMacro, AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc), std::string, MacroName) { @@ -330,35 +528,50 @@ AST_POLYMORPHIC_MATCHER_P(isExpandedFromMacro, /// Matches declarations. /// -/// Examples matches \c X, \c C, and the friend declaration inside \c C; +/// Given /// \code /// void X(); /// class C { -/// friend X; +/// friend void X(); /// }; /// \endcode +/// \compile_args{-std=c++} +/// The matcher \matcher{decl()} +/// matches \match{void X()} once, \match{type=name;count=2$C} +/// twice, once for the definition and once for the implicit class declaration, +/// and \match{count=2$friend void X()} twice, once for the declaration of the +/// friend, and once for the redeclaration of the function itself. extern const internal::VariadicAllOfMatcher decl; /// Matches decomposition-declarations. /// -/// Examples matches the declaration node with \c foo and \c bar, but not -/// \c number. -/// (matcher = declStmt(has(decompositionDecl()))) -/// +/// Given /// \code +/// struct pair { int x; int y; }; +/// pair make(int, int); /// int number = 42; -/// auto [foo, bar] = std::make_pair{42, 42}; +/// auto [foo, bar] = make(42, 42); /// \endcode +/// \compile_args{-std=c++17-or-later} +/// The matcher \matcher{decompositionDecl()} +/// matches \match{auto [foo, bar] = make(42, 42)}, +/// but does not match \nomatch{type=name$number}. extern const internal::VariadicDynCastAllOfMatcher decompositionDecl; /// Matches binding declarations -/// Example matches \c foo and \c bar -/// (matcher = bindingDecl() /// +/// Given /// \code -/// auto [foo, bar] = std::make_pair{42, 42}; +/// struct pair { int x; int y; }; +/// pair make(int, int); +/// void f() { +/// auto [foo, bar] = make(42, 42); +/// } /// \endcode +/// \compile_args{-std=c++17-or-later} +/// The matcher \matcher{bindingDecl()} +/// matches \match{type=name$foo} and \match{type=name$bar}. extern const internal::VariadicDynCastAllOfMatcher bindingDecl; @@ -368,33 +581,41 @@ extern const internal::VariadicDynCastAllOfMatcher /// \code /// extern "C" {} /// \endcode -/// linkageSpecDecl() -/// matches "extern "C" {}" +/// \compile_args{-std=c++} +/// The matcher \matcher{linkageSpecDecl()} +/// matches \match{extern "C" {}}. extern const internal::VariadicDynCastAllOfMatcher linkageSpecDecl; /// Matches a declaration of anything that could have a name. /// /// Example matches \c X, \c S, the anonymous union type, \c i, and \c U; +/// Given /// \code /// typedef int X; -/// struct S { -/// union { -/// int i; -/// } U; -/// }; -/// \endcode +/// struct S { union { int i; } U; }; +/// \endcode +/// The matcher \matcher{namedDecl()} +/// matches \match{typedef int X}, +/// \match{std=c$struct S { union { int i; } U; }}, \match{int i}, +/// the unnamed union\match{type=name$} and the variable +/// \match{union { int i; } U}, +/// with \match{type=name;count=2;std=c++$S} matching twice in C++. +/// Once for the implicit class declaration and once for the declaration itself. extern const internal::VariadicDynCastAllOfMatcher namedDecl; /// Matches a declaration of label. /// /// Given /// \code -/// goto FOO; -/// FOO: bar(); +/// void bar(); +/// void foo() { +/// goto FOO; +/// FOO: bar(); +/// } /// \endcode -/// labelDecl() -/// matches 'FOO:' +/// The matcher \matcher{type=none$labelDecl()} +/// matches \match{FOO: bar()}. extern const internal::VariadicDynCastAllOfMatcher labelDecl; /// Matches a declaration of a namespace. @@ -404,8 +625,9 @@ extern const internal::VariadicDynCastAllOfMatcher labelDecl; /// namespace {} /// namespace test {} /// \endcode -/// namespaceDecl() -/// matches "namespace {}" and "namespace test {}" +/// \compile_args{-std=c++} +/// The matcher \matcher{namespaceDecl()} +/// matches \match{namespace {}} and \match{namespace test {}}. extern const internal::VariadicDynCastAllOfMatcher namespaceDecl; @@ -416,38 +638,53 @@ extern const internal::VariadicDynCastAllOfMatcher /// namespace test {} /// namespace alias = ::test; /// \endcode -/// namespaceAliasDecl() -/// matches "namespace alias" but not "namespace test" +/// \compile_args{-std=c++} +/// The matcher \matcher{namespaceAliasDecl()} +/// matches \match{namespace alias = ::test}, +/// but does not match \nomatch{namespace test {}}. extern const internal::VariadicDynCastAllOfMatcher namespaceAliasDecl; /// Matches class, struct, and union declarations. /// -/// Example matches \c X, \c Z, \c U, and \c S +/// Given /// \code /// class X; /// template class Z {}; /// struct S {}; /// union U {}; /// \endcode +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher \matcher{recordDecl()} +/// matches \match{class X} once, and the rest of the declared records twice, +/// once for their written definition and once for their implicit declaration: +/// \match{type=name;count=2$Z}, \match{type=name;count=2$S} and +/// \match{type=name;count=2$U}. extern const internal::VariadicDynCastAllOfMatcher recordDecl; /// Matches C++ class declarations. /// -/// Example matches \c X, \c Z +/// Given /// \code /// class X; /// template class Z {}; /// \endcode +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher \matcher{cxxRecordDecl()} +/// matches \match{class X} once, and \match{type=name;count=2$Z} twice, +/// once for the written definition and once for the implicit declaration. extern const internal::VariadicDynCastAllOfMatcher cxxRecordDecl; /// Matches C++ class template declarations. /// -/// Example matches \c Z +/// Given /// \code /// template class Z {}; /// \endcode +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher \matcher{classTemplateDecl()} +/// matches \match{template class Z {}}. extern const internal::VariadicDynCastAllOfMatcher classTemplateDecl; @@ -459,8 +696,10 @@ extern const internal::VariadicDynCastAllOfMatcher /// template<> class A {}; /// A a; /// \endcode -/// classTemplateSpecializationDecl() -/// matches the specializations \c A and \c A +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher \matcher{classTemplateSpecializationDecl()} +/// matches \match{type=typestr$class A} +/// and \match{type=typestr$class A}. extern const internal::VariadicDynCastAllOfMatcher< Decl, ClassTemplateSpecializationDecl> classTemplateSpecializationDecl; @@ -472,14 +711,15 @@ extern const internal::VariadicDynCastAllOfMatcher< /// template /// class A {}; /// -/// template -/// class A {}; +/// template class A {}; /// /// template<> /// class A {}; /// \endcode -/// classTemplatePartialSpecializationDecl() -/// matches the specialization \c A but not \c A +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher \matcher{classTemplatePartialSpecializationDecl()} +/// matches \match{template class A {}}, +/// but does not match \nomatch{A}. extern const internal::VariadicDynCastAllOfMatcher< Decl, ClassTemplatePartialSpecializationDecl> classTemplatePartialSpecializationDecl; @@ -491,8 +731,9 @@ extern const internal::VariadicDynCastAllOfMatcher< /// \code /// class X { int y; }; /// \endcode -/// declaratorDecl() -/// matches \c int y. +/// \compile_args{-std=c++} +/// The matcher \matcher{declaratorDecl()} +/// matches \match{int y}. extern const internal::VariadicDynCastAllOfMatcher declaratorDecl; @@ -502,8 +743,8 @@ extern const internal::VariadicDynCastAllOfMatcher /// \code /// void f(int x); /// \endcode -/// parmVarDecl() -/// matches \c int x. +/// The matcher \matcher{parmVarDecl()} +/// matches \match{int x}. extern const internal::VariadicDynCastAllOfMatcher parmVarDecl; @@ -516,29 +757,36 @@ extern const internal::VariadicDynCastAllOfMatcher /// int a; /// }; /// \endcode -/// accessSpecDecl() -/// matches 'public:' +/// \compile_args{-std=c++} +/// The matcher \matcher{accessSpecDecl()} +/// matches \match{public:}. extern const internal::VariadicDynCastAllOfMatcher accessSpecDecl; /// Matches class bases. /// -/// Examples matches \c public virtual B. +/// Given /// \code /// class B {}; -/// class C : public virtual B {}; +/// class C : public B {}; /// \endcode +/// \compile_args{-std=c++} +/// The matcher \matcher{cxxRecordDecl(hasDirectBase(cxxBaseSpecifier()))} +/// matches \match{class C : public B {}}. extern const internal::VariadicAllOfMatcher cxxBaseSpecifier; /// Matches constructor initializers. /// -/// Examples matches \c i(42). +/// Given /// \code /// class C { /// C() : i(42) {} /// int i; /// }; /// \endcode +/// \compile_args{-std=c++} +/// The matcher \matcher{cxxCtorInitializer()} +/// matches \match{i(42)}. extern const internal::VariadicAllOfMatcher cxxCtorInitializer; @@ -549,8 +797,10 @@ extern const internal::VariadicAllOfMatcher /// template struct C {}; /// C c; /// \endcode -/// templateArgument() -/// matches 'int' in C. +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher +/// \matcher{templateSpecializationType(hasAnyTemplateArgument(templateArgument()))} +/// matches \match{type=typestr$C}. extern const internal::VariadicAllOfMatcher templateArgument; /// Matches template arguments (with location info). @@ -560,8 +810,9 @@ extern const internal::VariadicAllOfMatcher templateArgument; /// template struct C {}; /// C c; /// \endcode -/// templateArgumentLoc() -/// matches 'int' in C. +/// \compile_args{-fno-delayed-template-parsing;-std=c++} +/// The matcher \matcher{templateArgumentLoc()} +/// matches \match{int} in C. extern const internal::VariadicAllOfMatcher templateArgumentLoc; @@ -569,11 +820,15 @@ extern const internal::VariadicAllOfMatcher /// /// Given /// \code -/// template class X { }; -/// X xi; +/// template