diff --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp @@ -10,8 +10,10 @@ #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Analysis/Analyses/ExprMutationAnalyzer.h" +#include "../utils/Aliasing.h" using namespace clang::ast_matchers; +using clang::tidy::utils::hasPtrOrReferenceInFunc; namespace clang { namespace tidy { @@ -24,54 +26,6 @@ callExpr(Internal, callee(functionDecl(isNoReturn()))))); } -/// Return whether `S` is a reference to the declaration of `Var`. -static bool isAccessForVar(const Stmt *S, const VarDecl *Var) { - if (const auto *DRE = dyn_cast(S)) - return DRE->getDecl() == Var; - - return false; -} - -/// Return whether `Var` has a pointer or reference in `S`. -static bool isPtrOrReferenceForVar(const Stmt *S, const VarDecl *Var) { - if (const auto *DS = dyn_cast(S)) { - for (const Decl *D : DS->getDeclGroup()) { - if (const auto *LeftVar = dyn_cast(D)) { - if (LeftVar->hasInit() && LeftVar->getType()->isReferenceType()) { - return isAccessForVar(LeftVar->getInit(), Var); - } - } - } - } else if (const auto *UnOp = dyn_cast(S)) { - if (UnOp->getOpcode() == UO_AddrOf) - return isAccessForVar(UnOp->getSubExpr(), Var); - } - - return false; -} - -/// Return whether `Var` has a pointer or reference in `S`. -static bool hasPtrOrReferenceInStmt(const Stmt *S, const VarDecl *Var) { - if (isPtrOrReferenceForVar(S, Var)) - return true; - - for (const Stmt *Child : S->children()) { - if (!Child) - continue; - - if (hasPtrOrReferenceInStmt(Child, Var)) - return true; - } - - return false; -} - -/// Return whether `Var` has a pointer or reference in `Func`. -static bool hasPtrOrReferenceInFunc(const FunctionDecl *Func, - const VarDecl *Var) { - return hasPtrOrReferenceInStmt(Func->getBody(), Var); -} - /// Return whether `Var` was changed in `LoopStmt`. static bool isChanged(const Stmt *LoopStmt, const VarDecl *Var, ASTContext *Context) { diff --git a/clang-tools-extra/clang-tidy/utils/Aliasing.h b/clang-tools-extra/clang-tidy/utils/Aliasing.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/utils/Aliasing.h @@ -0,0 +1,36 @@ +//===------------- Aliasing.h - 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_ALIASING_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_ALIASING_H + +#include "clang/AST/Decl.h" + +namespace clang { +namespace tidy { +namespace utils { + +/// Returns whether \p Var has a pointer or reference in \p Func. +/// +/// Example: +/// void f() { +/// int n; +/// ... +/// int *p = &n; +/// } +/// +/// For `f()` and `n` the function returns ``true`` because `p` is a +/// pointer to `n` created in `f()`. + +bool hasPtrOrReferenceInFunc(const FunctionDecl *Func, const VarDecl *Var); + +} // namespace utils +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_ALIASING_H diff --git a/clang-tools-extra/clang-tidy/utils/Aliasing.cpp b/clang-tools-extra/clang-tidy/utils/Aliasing.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/utils/Aliasing.cpp @@ -0,0 +1,65 @@ +//===------------- Aliasing.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 "Aliasing.h" + +#include "clang/AST/Expr.h" + +namespace clang { +namespace tidy { +namespace utils { + +/// Return whether \p S is a reference to the declaration of \p Var. +static bool isAccessForVar(const Stmt *S, const VarDecl *Var) { + if (const auto *DRE = dyn_cast(S)) + return DRE->getDecl() == Var; + + return false; +} + +/// Return whether \p Var has a pointer or reference in \p S. +static bool isPtrOrReferenceForVar(const Stmt *S, const VarDecl *Var) { + if (const auto *DS = dyn_cast(S)) { + for (const Decl *D : DS->getDeclGroup()) { + if (const auto *LeftVar = dyn_cast(D)) { + if (LeftVar->hasInit() && LeftVar->getType()->isReferenceType()) { + return isAccessForVar(LeftVar->getInit(), Var); + } + } + } + } else if (const auto *UnOp = dyn_cast(S)) { + if (UnOp->getOpcode() == UO_AddrOf) + return isAccessForVar(UnOp->getSubExpr(), Var); + } + + return false; +} + +/// Return whether \p Var has a pointer or reference in \p S. +static bool hasPtrOrReferenceInStmt(const Stmt *S, const VarDecl *Var) { + if (isPtrOrReferenceForVar(S, Var)) + return true; + + for (const Stmt *Child : S->children()) { + if (!Child) + continue; + + if (hasPtrOrReferenceInStmt(Child, Var)) + return true; + } + + return false; +} + +bool hasPtrOrReferenceInFunc(const FunctionDecl *Func, const VarDecl *Var) { + return hasPtrOrReferenceInStmt(Func->getBody(), Var); +} + +} // namespace utils +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt @@ -4,6 +4,7 @@ ) add_clang_library(clangTidyUtils + Aliasing.cpp ASTUtils.cpp DeclRefExprUtils.cpp ExceptionAnalyzer.cpp