//===----- NondeterministicPointerIterationOrderCheck.cpp - clang-tidy ----===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "NondeterministicPointerIterationOrderCheck.h" #include "clang/Lex/Lexer.h" using namespace clang::ast_matchers; namespace clang::tidy::bugprone { void NondeterministicPointerIterationOrderCheck::registerMatchers( MatchFinder *Finder) { auto LoopVariable = varDecl(hasType( qualType(hasCanonicalType(anyOf(referenceType(), pointerType()))))); auto RangeInit = declRefExpr(to(varDecl( hasType(recordDecl(hasAnyName("std::unordered_set", "std::unordered_map", "std::unordered_multiset", "std::unordered_multimap")) .bind("recorddecl"))))); Finder->addMatcher(cxxForRangeStmt(hasLoopVariable(LoopVariable), hasRangeInit(RangeInit.bind("rangeinit"))) .bind("cxxForRangeStmt"), this); auto SortFuncM = callee(functionDecl(hasAnyName( "std::is_sorted", "std::nth_element", "std::sort", "std::partial_sort", "std::partition", "std::stable_partition", "std::stable_sort"))); auto IteratesPointerEltsM = hasArgument( 0, cxxMemberCallExpr(on(hasType(cxxRecordDecl(has(fieldDecl(hasType(qualType( hasCanonicalType(pointsTo(hasCanonicalType(pointerType())))))))))))); Finder->addMatcher( callExpr(allOf(SortFuncM, IteratesPointerEltsM)).bind("sortsemantic"), this); } void NondeterministicPointerIterationOrderCheck::check( const MatchFinder::MatchResult &Result) { const auto *ForRangePointers = Result.Nodes.getNodeAs("cxxForRangeStmt"); if ((ForRangePointers) && !(ForRangePointers->getBeginLoc().isMacroID())) { const auto *RangeInit = Result.Nodes.getNodeAs("rangeinit"); if (const auto *ClassTemplate = Result.Nodes.getNodeAs( "recorddecl")) { const TemplateArgumentList &TemplateArgs = ClassTemplate->getTemplateArgs(); const bool IsAlgoArgPointer = TemplateArgs[0].getAsType()->isPointerType(); if (IsAlgoArgPointer) { SourceRange R = RangeInit->getSourceRange(); diag(R.getBegin(), "iteration of pointers is nondeterministic") << R; } } return; } const auto *SortPointers = Result.Nodes.getNodeAs("sortsemantic"); if ((SortPointers) && !(SortPointers->getBeginLoc().isMacroID())) { SourceRange R = SortPointers->getSourceRange(); diag(R.getBegin(), "sorting pointers is nondeterministic") << R; } } } // namespace clang::tidy::bugprone