Skip to content

Commit 851ca24

Browse files
committed
Merge from 'master' to 'sycl-web' (#1)
CONFLICT (content): Merge conflict in clang/lib/Driver/ToolChains/Clang.cpp
2 parents d88e790 + 1282889 commit 851ca24

File tree

1,877 files changed

+66872
-31694
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,877 files changed

+66872
-31694
lines changed

clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ void ArgumentCommentCheck::checkCallArgs(ASTContext *Ctx,
324324
<< FixItHint::CreateInsertion(Args[I]->getBeginLoc(), ArgComment);
325325
}
326326
}
327-
} // namespace bugprone
327+
}
328328

329329
void ArgumentCommentCheck::check(const MatchFinder::MatchResult &Result) {
330330
const auto *E = Result.Nodes.getNodeAs<Expr>("expr");
@@ -337,7 +337,7 @@ void ArgumentCommentCheck::check(const MatchFinder::MatchResult &Result) {
337337
llvm::makeArrayRef(Call->getArgs(), Call->getNumArgs()));
338338
} else {
339339
const auto *Construct = cast<CXXConstructExpr>(E);
340-
if (Construct->getNumArgs() == 1 &&
340+
if (Construct->getNumArgs() > 0 &&
341341
Construct->getArg(0)->getSourceRange() == Construct->getSourceRange()) {
342342
// Ignore implicit construction.
343343
return;

clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "ForwardingReferenceOverloadCheck.h"
2424
#include "InaccurateEraseCheck.h"
2525
#include "IncorrectRoundingsCheck.h"
26+
#include "InfiniteLoopCheck.h"
2627
#include "IntegerDivisionCheck.h"
2728
#include "LambdaFunctionNameCheck.h"
2829
#include "MacroParenthesesCheck.h"
@@ -88,6 +89,8 @@ class BugproneModule : public ClangTidyModule {
8889
"bugprone-inaccurate-erase");
8990
CheckFactories.registerCheck<IncorrectRoundingsCheck>(
9091
"bugprone-incorrect-roundings");
92+
CheckFactories.registerCheck<InfiniteLoopCheck>(
93+
"bugprone-infinite-loop");
9194
CheckFactories.registerCheck<IntegerDivisionCheck>(
9295
"bugprone-integer-division");
9396
CheckFactories.registerCheck<LambdaFunctionNameCheck>(

clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ add_clang_library(clangTidyBugproneModule
1515
ForwardingReferenceOverloadCheck.cpp
1616
InaccurateEraseCheck.cpp
1717
IncorrectRoundingsCheck.cpp
18+
InfiniteLoopCheck.cpp
1819
IntegerDivisionCheck.cpp
1920
LambdaFunctionNameCheck.cpp
2021
MacroParenthesesCheck.cpp
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
//===--- InfiniteLoopCheck.cpp - clang-tidy -------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "InfiniteLoopCheck.h"
10+
#include "clang/AST/ASTContext.h"
11+
#include "clang/ASTMatchers/ASTMatchFinder.h"
12+
#include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
13+
14+
using namespace clang::ast_matchers;
15+
16+
namespace clang {
17+
namespace tidy {
18+
namespace bugprone {
19+
20+
static internal::Matcher<Stmt>
21+
loopEndingStmt(internal::Matcher<Stmt> Internal) {
22+
return stmt(anyOf(breakStmt(Internal), returnStmt(Internal),
23+
gotoStmt(Internal), cxxThrowExpr(Internal),
24+
callExpr(Internal, callee(functionDecl(isNoReturn())))));
25+
}
26+
27+
/// \brief Return whether `S` is a reference to the declaration of `Var`.
28+
static bool isAccessForVar(const Stmt *S, const VarDecl *Var) {
29+
if (const auto *DRE = dyn_cast<DeclRefExpr>(S))
30+
return DRE->getDecl() == Var;
31+
32+
return false;
33+
}
34+
35+
/// \brief Return whether `Var` has a pointer of reference in `S`.
36+
static bool isPtrOrReferenceForVar(const Stmt *S, const VarDecl *Var) {
37+
if (const auto *DS = dyn_cast<DeclStmt>(S)) {
38+
for (const Decl *D : DS->getDeclGroup()) {
39+
if (const auto *LeftVar = dyn_cast<VarDecl>(D)) {
40+
if (LeftVar->hasInit() && LeftVar->getType()->isReferenceType()) {
41+
return isAccessForVar(LeftVar->getInit(), Var);
42+
}
43+
}
44+
}
45+
} else if (const auto *UnOp = dyn_cast<UnaryOperator>(S)) {
46+
if (UnOp->getOpcode() == UO_AddrOf)
47+
return isAccessForVar(UnOp->getSubExpr(), Var);
48+
}
49+
50+
return false;
51+
}
52+
53+
/// \brief Return whether `Var` has a pointer of reference in `S`.
54+
static bool hasPtrOrReferenceInStmt(const Stmt *S, const VarDecl *Var) {
55+
if (isPtrOrReferenceForVar(S, Var))
56+
return true;
57+
58+
for (const Stmt *Child : S->children()) {
59+
if (!Child)
60+
continue;
61+
62+
if (hasPtrOrReferenceInStmt(Child, Var))
63+
return true;
64+
}
65+
66+
return false;
67+
}
68+
69+
/// \brief Return whether `Var` has a pointer of reference in `Func`.
70+
static bool hasPtrOrReferenceInFunc(const FunctionDecl *Func,
71+
const VarDecl *Var) {
72+
return hasPtrOrReferenceInStmt(Func->getBody(), Var);
73+
}
74+
75+
/// \brief Return whether `Var` was changed in `LoopStmt`.
76+
static bool isChanged(const Stmt *LoopStmt, const VarDecl *Var,
77+
ASTContext *Context) {
78+
if (const auto *ForLoop = dyn_cast<ForStmt>(LoopStmt))
79+
return (ForLoop->getInc() &&
80+
ExprMutationAnalyzer(*ForLoop->getInc(), *Context)
81+
.isMutated(Var)) ||
82+
(ForLoop->getBody() &&
83+
ExprMutationAnalyzer(*ForLoop->getBody(), *Context)
84+
.isMutated(Var)) ||
85+
(ForLoop->getCond() &&
86+
ExprMutationAnalyzer(*ForLoop->getCond(), *Context).isMutated(Var));
87+
88+
return ExprMutationAnalyzer(*LoopStmt, *Context).isMutated(Var);
89+
}
90+
91+
/// \brief Return whether `Cond` is a variable that is possibly changed in
92+
/// `LoopStmt`.
93+
static bool isVarThatIsPossiblyChanged(const FunctionDecl *Func,
94+
const Stmt *LoopStmt, const Stmt *Cond,
95+
ASTContext *Context) {
96+
if (const auto *DRE = dyn_cast<DeclRefExpr>(Cond)) {
97+
if (const auto *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
98+
if (!Var->isLocalVarDeclOrParm())
99+
return true;
100+
101+
if (Var->getType().isVolatileQualified())
102+
return true;
103+
104+
if (!Var->getType().getTypePtr()->isIntegerType())
105+
return true;
106+
107+
return hasPtrOrReferenceInFunc(Func, Var) ||
108+
isChanged(LoopStmt, Var, Context);
109+
// FIXME: Track references.
110+
}
111+
} else if (isa<MemberExpr>(Cond) || isa<CallExpr>(Cond)) {
112+
// FIXME: Handle MemberExpr.
113+
return true;
114+
}
115+
116+
return false;
117+
}
118+
119+
/// \brief Return whether at least one variable of `Cond` changed in `LoopStmt`.
120+
static bool isAtLeastOneCondVarChanged(const FunctionDecl *Func,
121+
const Stmt *LoopStmt, const Stmt *Cond,
122+
ASTContext *Context) {
123+
if (isVarThatIsPossiblyChanged(Func, LoopStmt, Cond, Context))
124+
return true;
125+
126+
for (const Stmt *Child : Cond->children()) {
127+
if (!Child)
128+
continue;
129+
130+
if (isAtLeastOneCondVarChanged(Func, LoopStmt, Child, Context))
131+
return true;
132+
}
133+
return false;
134+
}
135+
136+
/// \brief Return the variable names in `Cond`.
137+
static std::string getCondVarNames(const Stmt *Cond) {
138+
if (const auto *DRE = dyn_cast<DeclRefExpr>(Cond)) {
139+
if (const auto *Var = dyn_cast<VarDecl>(DRE->getDecl()))
140+
return Var->getName();
141+
}
142+
143+
std::string Result;
144+
for (const Stmt *Child : Cond->children()) {
145+
if (!Child)
146+
continue;
147+
148+
std::string NewNames = getCondVarNames(Child);
149+
if (!Result.empty() && !NewNames.empty())
150+
Result += ", ";
151+
Result += NewNames;
152+
}
153+
return Result;
154+
}
155+
156+
void InfiniteLoopCheck::registerMatchers(MatchFinder *Finder) {
157+
const auto LoopCondition = allOf(
158+
hasCondition(
159+
expr(forFunction(functionDecl().bind("func"))).bind("condition")),
160+
unless(hasBody(hasDescendant(
161+
loopEndingStmt(forFunction(equalsBoundNode("func")))))));
162+
163+
Finder->addMatcher(stmt(anyOf(whileStmt(LoopCondition), doStmt(LoopCondition),
164+
forStmt(LoopCondition)))
165+
.bind("loop-stmt"),
166+
this);
167+
}
168+
169+
void InfiniteLoopCheck::check(const MatchFinder::MatchResult &Result) {
170+
const auto *Cond = Result.Nodes.getNodeAs<Expr>("condition");
171+
const auto *LoopStmt = Result.Nodes.getNodeAs<Stmt>("loop-stmt");
172+
const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
173+
174+
if (isAtLeastOneCondVarChanged(Func, LoopStmt, Cond, Result.Context))
175+
return;
176+
177+
std::string CondVarNames = getCondVarNames(Cond);
178+
if (CondVarNames.empty())
179+
return;
180+
181+
diag(LoopStmt->getBeginLoc(),
182+
"this loop is infinite; none of its condition variables (%0)"
183+
" are updated in the loop body")
184+
<< CondVarNames;
185+
}
186+
187+
} // namespace bugprone
188+
} // namespace tidy
189+
} // namespace clang
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//===--- InfiniteLoopCheck.h - clang-tidy -----------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INFINITELOOPCHECK_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INFINITELOOPCHECK_H
11+
12+
#include "../ClangTidyCheck.h"
13+
14+
namespace clang {
15+
namespace tidy {
16+
namespace bugprone {
17+
18+
/// Finds obvious infinite loops (loops where the condition variable is
19+
/// not changed at all).
20+
///
21+
/// For the user-facing documentation see:
22+
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-infinite-loop.html
23+
class InfiniteLoopCheck : public ClangTidyCheck {
24+
public:
25+
InfiniteLoopCheck(StringRef Name, ClangTidyContext *Context)
26+
: ClangTidyCheck(Name, Context) {}
27+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
28+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
29+
};
30+
31+
} // namespace bugprone
32+
} // namespace tidy
33+
} // namespace clang
34+
35+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INFINITELOOPCHECK_H

clang-tools-extra/clang-tidy/bugprone/PosixReturnCheck.cpp

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,31 @@ static StringRef getFunctionSpelling(const MatchFinder::MatchResult &Result,
2828
}
2929

3030
void PosixReturnCheck::registerMatchers(MatchFinder *Finder) {
31-
Finder->addMatcher(binaryOperator(hasOperatorName("<"),
32-
hasLHS(callExpr(callee(functionDecl(
33-
matchesName("^::posix_"),
34-
unless(hasName("::posix_openpt")))))),
35-
hasRHS(integerLiteral(equals(0))))
36-
.bind("ltzop"),
37-
this);
38-
Finder->addMatcher(binaryOperator(hasOperatorName(">="),
39-
hasLHS(callExpr(callee(functionDecl(
40-
matchesName("^::posix_"),
41-
unless(hasName("::posix_openpt")))))),
42-
hasRHS(integerLiteral(equals(0))))
43-
.bind("atop"),
44-
this);
31+
Finder->addMatcher(
32+
binaryOperator(
33+
hasOperatorName("<"),
34+
hasLHS(callExpr(callee(functionDecl(
35+
anyOf(matchesName("^::posix_"), matchesName("^::pthread_")),
36+
unless(hasName("::posix_openpt")))))),
37+
hasRHS(integerLiteral(equals(0))))
38+
.bind("ltzop"),
39+
this);
40+
Finder->addMatcher(
41+
binaryOperator(
42+
hasOperatorName(">="),
43+
hasLHS(callExpr(callee(functionDecl(
44+
anyOf(matchesName("^::posix_"), matchesName("^::pthread_")),
45+
unless(hasName("::posix_openpt")))))),
46+
hasRHS(integerLiteral(equals(0))))
47+
.bind("atop"),
48+
this);
4549
Finder->addMatcher(
4650
binaryOperator(
4751
anyOf(hasOperatorName("=="), hasOperatorName("!="),
4852
hasOperatorName("<="), hasOperatorName("<")),
4953
hasLHS(callExpr(callee(functionDecl(
50-
matchesName("^::posix_"), unless(hasName("::posix_openpt")))))),
54+
anyOf(matchesName("^::posix_"), matchesName("^::pthread_")),
55+
unless(hasName("::posix_openpt")))))),
5156
hasRHS(unaryOperator(hasOperatorName("-"),
5257
hasUnaryOperand(integerLiteral()))))
5358
.bind("binop"),

clang-tools-extra/clang-tidy/bugprone/PosixReturnCheck.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===--- PosixReturnCheck.h - clang-tidy-------------------------*- C++ -*-===//
1+
//===--- PosixReturnCheck.h - clang-tidy ------------------------*- C++ -*-===//
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.

clang-tools-extra/clang-tidy/objc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ add_clang_library(clangTidyObjCModule
44
AvoidNSErrorInitCheck.cpp
55
AvoidSpinlockCheck.cpp
66
ForbiddenSubclassingCheck.cpp
7+
MissingHashCheck.cpp
78
ObjCTidyModule.cpp
89
PropertyDeclarationCheck.cpp
910
SuperSelfCheck.cpp
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//===--- MissingHashCheck.cpp - clang-tidy --------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "MissingHashCheck.h"
10+
#include "clang/AST/ASTContext.h"
11+
#include "clang/ASTMatchers/ASTMatchFinder.h"
12+
13+
using namespace clang::ast_matchers;
14+
15+
namespace clang {
16+
namespace tidy {
17+
namespace objc {
18+
19+
namespace {
20+
21+
AST_MATCHER_P(ObjCImplementationDecl, hasInterface,
22+
ast_matchers::internal::Matcher<ObjCInterfaceDecl>, Base) {
23+
const ObjCInterfaceDecl *InterfaceDecl = Node.getClassInterface();
24+
return Base.matches(*InterfaceDecl, Finder, Builder);
25+
}
26+
27+
AST_MATCHER_P(ObjCContainerDecl, hasInstanceMethod,
28+
ast_matchers::internal::Matcher<ObjCMethodDecl>, Base) {
29+
// Check each instance method against the provided matcher.
30+
for (const auto *I : Node.instance_methods()) {
31+
if (Base.matches(*I, Finder, Builder))
32+
return true;
33+
}
34+
return false;
35+
}
36+
37+
} // namespace
38+
39+
void MissingHashCheck::registerMatchers(MatchFinder *Finder) {
40+
// This check should only be applied to Objective-C sources.
41+
if (!getLangOpts().ObjC)
42+
return;
43+
44+
Finder->addMatcher(
45+
objcMethodDecl(
46+
hasName("isEqual:"), isInstanceMethod(),
47+
hasDeclContext(objcImplementationDecl(
48+
hasInterface(isDirectlyDerivedFrom("NSObject")),
49+
unless(hasInstanceMethod(hasName("hash"))))
50+
.bind("impl"))),
51+
this);
52+
}
53+
54+
void MissingHashCheck::check(const MatchFinder::MatchResult &Result) {
55+
const auto *ID = Result.Nodes.getNodeAs<ObjCImplementationDecl>("impl");
56+
diag(ID->getLocation(), "%0 implements -isEqual: without implementing -hash")
57+
<< ID;
58+
}
59+
60+
} // namespace objc
61+
} // namespace tidy
62+
} // namespace clang

0 commit comments

Comments
 (0)