
These are identified by misc-include-cleaner. I've filtered out those that break builds. Also, I'm staying away from llvm-config.h, config.h, and Compiler.h, which likely cause platform- or compiler-specific build failures.
78 lines
2.9 KiB
C++
78 lines
2.9 KiB
C++
//===----- 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>("cxxForRangeStmt");
|
|
|
|
if ((ForRangePointers) && !(ForRangePointers->getBeginLoc().isMacroID())) {
|
|
const auto *RangeInit = Result.Nodes.getNodeAs<Stmt>("rangeinit");
|
|
if (const auto *ClassTemplate =
|
|
Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(
|
|
"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<Stmt>("sortsemantic");
|
|
|
|
if ((SortPointers) && !(SortPointers->getBeginLoc().isMacroID())) {
|
|
SourceRange R = SortPointers->getSourceRange();
|
|
diag(R.getBegin(), "sorting pointers is nondeterministic") << R;
|
|
}
|
|
}
|
|
|
|
} // namespace clang::tidy::bugprone
|