================
@@ -0,0 +1,354 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "UseInitStatementCheck.h"
+#include "../utils/ASTUtils.h"
+#include "../utils/LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/QualTypeNames.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include <algorithm> // for std::adjacent_find
+#include <cctype>
+#include <string>
+#include <utility>
+
+using namespace clang::ast_matchers;
+using namespace clang::tidy::utils::lexer;
+
+using clang::ast_matchers::internal::Matcher;
+using clang::ast_matchers::internal::VariadicDynCastAllOfMatcher;
+
+namespace clang::tidy::modernize {
+
+namespace {
+
+// Matches CompoundStmt that contains a PrevStmt immediately followed by
+// NextStmt
+// FIXME: use hasAdjSubstatements, see
+// https://github.com/llvm/llvm-project/pull/169965
+AST_MATCHER_P2(CompoundStmt, hasAdjacentStmts, Matcher<Stmt>, DeclMatcher,
+ Matcher<Stmt>, StmtMatcher) {
+ const auto Statements = Node.body();
+
+ return std::adjacent_find(
+ Statements.begin(), Statements.end(),
+ [&](const Stmt *PrevStmt, const Stmt *NextStmt) {
+ clang::ast_matchers::internal::BoundNodesTreeBuilder
PrevBuilder;
+ if (!DeclMatcher.matches(*PrevStmt, Finder, &PrevBuilder))
+ return false;
+
+ clang::ast_matchers::internal::BoundNodesTreeBuilder
NextBuilder;
+ NextBuilder.addMatch(PrevBuilder);
+ if (!StmtMatcher.matches(*NextStmt, Finder, &NextBuilder))
+ return false;
+
+ Builder->addMatch(NextBuilder);
+ return true;
+ }) != Statements.end();
+}
+
+AST_MATCHER(Decl, isTemplate) { return Node.isTemplated(); }
+
+AST_MATCHER(VarDecl, isUsed) {
+ if (Node.getType().isConstQualified())
+ return true; // FIXME: implement proper "used" check for consts
+ return Node.isUsed();
+}
+
+// got from implementation of memberHasSameNameAsBoundNode mather
+AST_MATCHER_P(VarDecl, hasSameNameAsBoundNode, std::string, BindingID) {
+ auto VarName = Node.getNameAsString();
+
+ return Builder->removeBindings(
+ [this,
+ VarName](const clang::ast_matchers::internal::BoundNodesMap &Nodes) {
+ const DynTypedNode &BN = Nodes.getNode(this->BindingID);
+ if (const auto *ND = BN.get<NamedDecl>()) {
+ if (!isa<BindingDecl, VarDecl>(ND))
+ return true;
+ return ND->getName() != VarName;
+ }
+ return true;
+ });
+}
+
+} // namespace
+
+UseInitStatementCheck::UseInitStatementCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IgnoreConditionVariableStatements(
+ Options.get("IgnoreConditionVariableStatements", false)) {}
+
+void UseInitStatementCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IgnoreConditionVariableStatements",
+ IgnoreConditionVariableStatements);
+}
+
+static Matcher<Stmt> callByRef(const Matcher<Decl> &VarOrBindingNodeMatcher) {
+ const auto ArgMatcher = declRefExpr(to(VarOrBindingNodeMatcher));
+ const auto ParamMatcher = parmVarDecl(hasType(referenceType()));
+
+ return anyOf(
+ callExpr(forEachArgumentWithParam(ArgMatcher, ParamMatcher)),
+ cxxConstructExpr(forEachArgumentWithParam(ArgMatcher, ParamMatcher)));
+}
+
+static Matcher<VarDecl> hasInitializerWithLifetimeExtension() {
+ return hasInitializer(expr(hasDescendant(expr(materializeTemporaryExpr()))));
+}
+
+static Matcher<DeclStmt> includingLifetimeExtension() {
+ return has(varDecl(hasInitializerWithLifetimeExtension()));
+}
+
+static Matcher<DeclStmt> excludingLifetimeExtension() {
+ return unless(includingLifetimeExtension());
+}
+
+// Complete matcher to detect stealing cases, preventing
+// the checker from generating code that could result in dangling references,
+// such as: `int* p; if (int v;cond) { p=&v; } use(p);`
+static Matcher<Stmt> hasStealingMatcher() {
+ const auto IsStealingViaPointer =
+ hasParent(unaryOperator(hasOperatorName("&")));
+ const auto HasLTE = hasInitializerWithLifetimeExtension();
+ const auto HasLTEForBind =
+ hasParent(declStmt(has(varDecl(equalsBoundNode("singleVar"), HasLTE))));
+ const auto IsNonreferenceType = unless(hasType(referenceType()));
+ const auto BoundVar =
+ varDecl(equalsBoundNode("singleVar"), anyOf(IsNonreferenceType, HasLTE));
+ const auto BoundBind = bindingDecl(
+ equalsBoundNode("bindingDecl"),
+ hasParent(decompositionDecl(anyOf(IsNonreferenceType, HasLTEForBind))));
+ const auto VarOrBindingNode = anyOf(BoundVar, BoundBind);
+ const auto StealingAsThis =
+ anyOf(hasParent(memberExpr()),
+ hasParent(implicitCastExpr(hasCastKind(CK_NoOp),
+ hasParent(memberExpr()))));
+ const auto HasStealingByPointer =
+ hasDescendant(declRefExpr(to(VarOrBindingNode), IsStealingViaPointer));
+ const auto HasStealingByReference =
+ hasDescendant(callByRef(VarOrBindingNode));
+ const auto HasStealingAsThis =
+ hasDescendant(declRefExpr(to(VarOrBindingNode), StealingAsThis));
+ return anyOf(HasStealingByPointer, HasStealingByReference,
HasStealingAsThis);
+}
+
+static Matcher<Stmt> hasConflictMatcher() {
+ return hasDescendant(varDecl(anyOf(hasSameNameAsBoundNode("singleVar"),
+ hasSameNameAsBoundNode("bindingDecl")))
+ .bind("conflict"));
+}
+
+static Matcher<Stmt>
+compoundStmtMatcher(const Matcher<Stmt> &StmtMatcher, StringRef StmtName,
+ const Matcher<Stmt> &PrevStmtMatcher,
+ const Matcher<Stmt> &RefToBoundMatcher) {
+ const auto NoOtherVarRefs =
+ unless(has(stmt(unless(equalsBoundNode(StmtName.str())),
+ hasDescendant(RefToBoundMatcher))));
+ return compoundStmt(unless(isExpansionInSystemHeader()),
+ unless(hasAncestor(functionDecl(isTemplate()))),
----------------
denzor200 wrote:
Oke, I will add tests for C++20 generic lambdas:
```
auto lambda = []<typename T> (std::vector<T>& t) { /* ... */ };
```
and for C++14 auto lambdas:
```
auto lambda = [] (auto& t) { /* ... */ };
```
https://github.com/llvm/llvm-project/pull/171086
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits