================ @@ -0,0 +1,320 @@ +//===----------------------------------------------------------------------===// +// +// 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 "InefficientContainerAssignmentCheck.h" +#include "../utils/OptionsUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ParentMapContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include <optional> +#include <string> + +using namespace clang::ast_matchers; + +namespace clang::tidy::performance { + +namespace { + +/// How the assignment can be rewritten without the temporary. The order +/// matches the %select in the diagnostic. +enum class Rewrite { + Assign, ///< lhs.assign(args...) + AssignRange, ///< lhs.assign_range(range) + ClearResize, ///< lhs.clear(); lhs.resize(count) + InitList, ///< lhs = {...} + Direct, ///< lhs = source +}; + +} // namespace + +/// Collects the variables and members named by \p E so that arguments +/// referring back to the destination can be detected. +static void +collectReferencedDecls(const Expr &E, ASTContext &Ctx, + llvm::SmallPtrSetImpl<const ValueDecl *> &Decls) { + for (const BoundNodes &N : match(findAll(declRefExpr().bind("ref")), E, Ctx)) + Decls.insert(N.getNodeAs<DeclRefExpr>("ref")->getDecl()); + for (const BoundNodes &N : + match(findAll(memberExpr().bind("member")), E, Ctx)) + Decls.insert(N.getNodeAs<MemberExpr>("member")->getMemberDecl()); +} + +static bool +refersToAnyOf(const Expr &E, ASTContext &Ctx, + const llvm::SmallPtrSetImpl<const ValueDecl *> &Decls) { + llvm::SmallPtrSet<const ValueDecl *, 8> Referenced; + collectReferencedDecls(E, Ctx, Referenced); + return llvm::any_of( + Referenced, [&Decls](const ValueDecl *D) { return Decls.contains(D); }); +} + +/// Returns true if one of the first \p NumArgs parameters of \p Ctor has the +/// type of a template argument of the container other than its element type. +/// That is what the allocator parameter of the standard containers looks +/// like, and an explicitly passed allocator has no counterpart in 'assign'. +static bool passesAllocator(const CXXConstructorDecl &Ctor, unsigned NumArgs, + const ASTContext &Ctx) { + const auto *Spec = + dyn_cast<ClassTemplateSpecializationDecl>(Ctor.getParent()); + if (!Spec) + return false; + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + for (unsigned I = 0, E = std::min(NumArgs, Ctor.getNumParams()); I < E; ++I) { + const QualType ParamType = + Ctor.getParamDecl(I)->getType().getNonReferenceType(); + if (!ParamType->isRecordType()) + continue; + for (unsigned J = 1; J < TemplateArgs.size(); ++J) { + const TemplateArgument &Arg = TemplateArgs[J]; + if (Arg.getKind() == TemplateArgument::Type && + ASTContext::hasSameUnqualifiedType(Arg.getAsType(), ParamType)) + return true; + } + } + return false; +} + +static bool isFromRangeTag(QualType T) { + const CXXRecordDecl *RD = T.getNonReferenceType()->getAsCXXRecordDecl(); + return RD && RD->isInStdNamespace() && RD->getName() == "from_range_t"; +} + +/// A postfix expression can take a member access directly; anything else has +/// to be parenthesized first. +static bool needsParens(const Expr &E) { ---------------- unterumarmung wrote:
Could we use `tooling::buildAccess()` here? It handles the parentheses and member-access spelling, including turning `*H.Ptr` into `H.Ptr->`, so we could drop this helper and the manual `Dest` construction. https://github.com/llvm/llvm-project/pull/222159 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
