[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)
https://github.com/fberger approved this pull request. LGTM https://github.com/llvm/llvm-project/pull/73921 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)
@@ -290,69 +296,72 @@ void UnnecessaryCopyInitialization::check( // instantiations where the types differ and rely on implicit conversion would // no longer compile if we switched to a reference. if (differentReplacedTemplateParams( - NewVar->getType(), constructorArgumentType(OldVar, Result.Nodes), + Context.Var.getType(), constructorArgumentType(OldVar, Result.Nodes), *Result.Context)) return; if (OldVar == nullptr) { -handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix, ObjectArg, - *Result.Context); +// `auto NewVar = functionCall();` +handleCopyFromMethodReturn(Context, ObjectArg); } else { -handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix, - *Result.Context); +// `auto NewVar = OldVar;` +handleCopyFromLocalVar(Context, *OldVar); } } -void UnnecessaryCopyInitialization::makeDiagnostic( -DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt, -const DeclStmt &Stmt, ASTContext &Context, bool IssueFix) { - const bool IsVarUnused = isVariableUnused(Var, BlockStmt, Context); - Diagnostic << &Var << IsVarUnused; - if (!IssueFix) -return; - if (IsVarUnused) -recordRemoval(Stmt, Context, Diagnostic); - else -recordFixes(Var, Context, Diagnostic); -} - void UnnecessaryCopyInitialization::handleCopyFromMethodReturn( -const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt, -bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) { - bool IsConstQualified = Var.getType().isConstQualified(); - if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context)) +const CheckContext &Ctx, const VarDecl *ObjectArg) { + bool IsConstQualified = Ctx.Var.getType().isConstQualified(); + if (!IsConstQualified && !Ctx.IsVarOnlyUsedAsConst) return; if (ObjectArg != nullptr && - !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context, + !isInitializingVariableImmutable(*ObjectArg, Ctx.BlockStmt, Ctx.ASTCtx, ExcludedContainerTypes)) return; - - auto Diagnostic = - diag(Var.getLocation(), - "the %select{|const qualified }0variable %1 is copy-constructed " - "from a const reference%select{" - "%select{ but is only used as const reference|}0" - "| but is never used}2; consider " - "%select{making it a const reference|removing the statement}2") - << IsConstQualified; - makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context, - IssueFix); + diagnoseCopyFromMethodReturn(Ctx, ObjectArg); } void UnnecessaryCopyInitialization::handleCopyFromLocalVar( -const VarDecl &Var, const VarDecl &OldVar, const Stmt &BlockStmt, -const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) { - if (!isOnlyUsedAsConst(Var, BlockStmt, Context) || - !isInitializingVariableImmutable(OldVar, BlockStmt, Context, +const CheckContext &Ctx, const VarDecl &OldVar) { + if (!Ctx.IsVarOnlyUsedAsConst || + !isInitializingVariableImmutable(OldVar, Ctx.BlockStmt, Ctx.ASTCtx, ExcludedContainerTypes)) return; - auto Diagnostic = diag(Var.getLocation(), - "local copy %1 of the variable %0 is never modified" - "%select{| and never used}2; consider " - "%select{avoiding the copy|removing the statement}2") -<< &OldVar; - makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context, - IssueFix); + diagnoseCopyFromLocalVar(Ctx, OldVar); +} + +void UnnecessaryCopyInitialization::diagnoseCopyFromMethodReturn( +const CheckContext &Ctx, const VarDecl *ObjectArg) { fberger wrote: It doesn't look like ObjectArg is used. Can we remove it? https://github.com/llvm/llvm-project/pull/73921 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)
@@ -290,69 +296,72 @@ void UnnecessaryCopyInitialization::check( // instantiations where the types differ and rely on implicit conversion would // no longer compile if we switched to a reference. if (differentReplacedTemplateParams( - NewVar->getType(), constructorArgumentType(OldVar, Result.Nodes), + Context.Var.getType(), constructorArgumentType(OldVar, Result.Nodes), *Result.Context)) return; if (OldVar == nullptr) { -handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix, ObjectArg, - *Result.Context); +// `auto NewVar = functionCall();` +handleCopyFromMethodReturn(Context, ObjectArg); } else { -handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix, - *Result.Context); +// `auto NewVar = OldVar;` +handleCopyFromLocalVar(Context, *OldVar); } } -void UnnecessaryCopyInitialization::makeDiagnostic( -DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt, -const DeclStmt &Stmt, ASTContext &Context, bool IssueFix) { - const bool IsVarUnused = isVariableUnused(Var, BlockStmt, Context); - Diagnostic << &Var << IsVarUnused; - if (!IssueFix) -return; - if (IsVarUnused) -recordRemoval(Stmt, Context, Diagnostic); - else -recordFixes(Var, Context, Diagnostic); -} - void UnnecessaryCopyInitialization::handleCopyFromMethodReturn( -const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt, -bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) { - bool IsConstQualified = Var.getType().isConstQualified(); - if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context)) +const CheckContext &Ctx, const VarDecl *ObjectArg) { + bool IsConstQualified = Ctx.Var.getType().isConstQualified(); + if (!IsConstQualified && !Ctx.IsVarOnlyUsedAsConst) return; if (ObjectArg != nullptr && - !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context, + !isInitializingVariableImmutable(*ObjectArg, Ctx.BlockStmt, Ctx.ASTCtx, ExcludedContainerTypes)) return; - - auto Diagnostic = - diag(Var.getLocation(), - "the %select{|const qualified }0variable %1 is copy-constructed " - "from a const reference%select{" - "%select{ but is only used as const reference|}0" - "| but is never used}2; consider " - "%select{making it a const reference|removing the statement}2") - << IsConstQualified; - makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context, - IssueFix); + diagnoseCopyFromMethodReturn(Ctx, ObjectArg); } void UnnecessaryCopyInitialization::handleCopyFromLocalVar( -const VarDecl &Var, const VarDecl &OldVar, const Stmt &BlockStmt, -const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) { - if (!isOnlyUsedAsConst(Var, BlockStmt, Context) || - !isInitializingVariableImmutable(OldVar, BlockStmt, Context, +const CheckContext &Ctx, const VarDecl &OldVar) { + if (!Ctx.IsVarOnlyUsedAsConst || + !isInitializingVariableImmutable(OldVar, Ctx.BlockStmt, Ctx.ASTCtx, ExcludedContainerTypes)) return; - auto Diagnostic = diag(Var.getLocation(), - "local copy %1 of the variable %0 is never modified" - "%select{| and never used}2; consider " - "%select{avoiding the copy|removing the statement}2") -<< &OldVar; - makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context, - IssueFix); + diagnoseCopyFromLocalVar(Ctx, OldVar); +} + +void UnnecessaryCopyInitialization::diagnoseCopyFromMethodReturn( +const CheckContext &Ctx, const VarDecl *ObjectArg) { fberger wrote: Oh, I see sub classes might need access to it. Makes sense. https://github.com/llvm/llvm-project/pull/73921 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)
https://github.com/fberger edited https://github.com/llvm/llvm-project/pull/73921 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang-tidy] Handle C++ structured bindings in `performance-for-range-copy` (PR #77105)
https://github.com/fberger edited https://github.com/llvm/llvm-project/pull/77105 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang] [clang-tidy] Handle C++ structured bindings in `performance-for-range-copy` (PR #77105)
@@ -234,6 +239,22 @@ void positiveOnlyAccessedFieldAsConst() { } } +void positiveOnlyAccessedFieldAsConstBinding() { + for (auto [X, Y] : View>()) { +// CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but +// CHECK-FIXES: for (const auto& [X, Y] : View>()) { +use(X); +use(Y); + } +} + +void negativeOnlyAccessedFieldAsConstBinding() { fberger wrote: Same here: Can we just have "mutated" in the function name? https://github.com/llvm/llvm-project/pull/77105 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang-tidy] Handle C++ structured bindings in `performance-for-range-copy` (PR #77105)
https://github.com/fberger approved this pull request. https://github.com/llvm/llvm-project/pull/77105 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang-tidy] Handle C++ structured bindings in `performance-for-range-copy` (PR #77105)
@@ -234,6 +239,22 @@ void positiveOnlyAccessedFieldAsConst() { } } +void positiveOnlyAccessedFieldAsConstBinding() { fberger wrote: Why `AccessedField` here, it seems to be `JustUsedAsConst` as in other test names? https://github.com/llvm/llvm-project/pull/77105 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] 00edae9 - [clang-tidy] performance-unnecessary-copy-initialization: Disable check when variable and initializer have different replaced template param types.
Author: Felix Berger Date: 2021-07-22T15:17:24-04:00 New Revision: 00edae9203c9a4f50da058d4bd25dc2e6a4930c1 URL: https://github.com/llvm/llvm-project/commit/00edae9203c9a4f50da058d4bd25dc2e6a4930c1 DIFF: https://github.com/llvm/llvm-project/commit/00edae9203c9a4f50da058d4bd25dc2e6a4930c1.diff LOG: [clang-tidy] performance-unnecessary-copy-initialization: Disable check when variable and initializer have different replaced template param types. This can happen when a template with two parameter types is instantiated with a single type. The fix would only be valid for this instantiation but fail for others that rely on an implicit type conversion. The test cases illustrate when the check should trigger and when not. Differential Revision: https://reviews.llvm.org/D106011 Added: Modified: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp Removed: diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp index f6b8e44785b5f..9631e06a8f95b 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -27,6 +27,8 @@ using utils::decl_ref_expr::isOnlyUsedAsConst; static constexpr StringRef ObjectArgId = "objectArg"; static constexpr StringRef InitFunctionCallId = "initFunctionCall"; +static constexpr StringRef MethodDeclId = "methodDecl"; +static constexpr StringRef FunctionDeclId = "functionDecl"; static constexpr StringRef OldVarDeclId = "oldVarDecl"; void recordFixes(const VarDecl &Var, ASTContext &Context, @@ -81,7 +83,8 @@ AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningMethodCall) { // returned either points to a global static variable or to a member of the // called object. return cxxMemberCallExpr( - callee(cxxMethodDecl(returns(matchers::isReferenceToConst(, + callee(cxxMethodDecl(returns(matchers::isReferenceToConst())) + .bind(MethodDeclId)), on(declRefExpr(to(varDecl().bind(ObjectArgId); } @@ -89,7 +92,8 @@ AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) { // Only allow initialization of a const reference from a free function if it // has no arguments. Otherwise it could return an alias to one of its // arguments and the arguments need to be checked for const use as well. - return callExpr(callee(functionDecl(returns(matchers::isReferenceToConst(, + return callExpr(callee(functionDecl(returns(matchers::isReferenceToConst())) + .bind(FunctionDeclId)), argumentCountIs(0), unless(callee(cxxMethodDecl( .bind(InitFunctionCallId); } @@ -155,6 +159,45 @@ bool isVariableUnused(const VarDecl &Var, const Stmt &BlockStmt, return allDeclRefExprs(Var, BlockStmt, Context).empty(); } +const SubstTemplateTypeParmType *getSubstitutedType(const QualType &Type, +ASTContext &Context) { + auto Matches = match( + qualType(anyOf(substTemplateTypeParmType().bind("subst"), + hasDescendant(substTemplateTypeParmType().bind("subst", + Type, Context); + return selectFirst("subst", Matches); +} + +bool diff erentReplacedTemplateParams(const QualType &VarType, + const QualType &InitializerType, + ASTContext &Context) { + if (const SubstTemplateTypeParmType *VarTmplType = + getSubstitutedType(VarType, Context)) { +if (const SubstTemplateTypeParmType *InitializerTmplType = +getSubstitutedType(InitializerType, Context)) { + return VarTmplType->getReplacedParameter() + ->desugar() + .getCanonicalType() != + InitializerTmplType->getReplacedParameter() + ->desugar() + .getCanonicalType(); +} + } + return false; +} + +QualType constructorArgumentType(const VarDecl *OldVar, + const BoundNodes &Nodes) { + if (OldVar) { +return OldVar->getType(); + } + if (const auto *FuncDecl = Nodes.getNodeAs(FunctionDeclId)) { +return FuncDecl->getReturnType(); + } + const auto *MethodDecl = Nodes.getNodeAs(MethodDeclId); + return MethodDecl->getReturnType(); +} + } // namespace UnnecessaryCopyInitialization::UnnecessaryCopyInitialization( @@ -222,6 +265,16 @@ void UnnecessaryCopyInitialization::check( if (!CtorCall->getArg(I)->isDefaultArgument()) return; + // Don't apply the check if the variable and its initializer have diff erent + // replaced template parameter types. In this case the check trigg
[clang-tools-extra] cb4c12b - [clang-tidy] performance-unnecessary-copy-initialization: Create option to exclude container types from triggering the check.
Author: Felix Berger Date: 2021-07-22T16:20:20-04:00 New Revision: cb4c12b6117a6f2989d5745854a94c75cb6a09ba URL: https://github.com/llvm/llvm-project/commit/cb4c12b6117a6f2989d5745854a94c75cb6a09ba DIFF: https://github.com/llvm/llvm-project/commit/cb4c12b6117a6f2989d5745854a94c75cb6a09ba.diff LOG: [clang-tidy] performance-unnecessary-copy-initialization: Create option to exclude container types from triggering the check. Add string list option of type names analagous to `AllowedTypes` which lets users specify a list of ExcludedContainerTypes. Types matching this list will not trigger the check when an expensive variable is copy initialized from a const accessor method they provide, i.e.: ``` ExcludedContainerTypes = 'ExcludedType' void foo() { ExcludedType Container; const ExpensiveToCopy NecessaryCopy = Container.get(); } ``` Even though an expensive to copy variable is copy initialized the check does not trigger because the container type is excluded. This is useful for container types that don't own their data, such as view types where modification of the returned references in other places cannot be reliably tracked, or const incorrect types. Differential Revision: https://reviews.llvm.org/D106173 Reviewed-by: ymandel Added: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp Modified: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst Removed: diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp index 9631e06a8f95b..6f9495fd1e66c 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -75,7 +75,8 @@ void recordRemoval(const DeclStmt &Stmt, ASTContext &Context, } } -AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningMethodCall) { +AST_MATCHER_FUNCTION_P(StatementMatcher, isConstRefReturningMethodCall, + std::vector, ExcludedContainerTypes) { // Match method call expressions where the `this` argument is only used as // const, this will be checked in `check()` part. This returned const // reference is highly likely to outlive the local const reference of the @@ -85,7 +86,11 @@ AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningMethodCall) { return cxxMemberCallExpr( callee(cxxMethodDecl(returns(matchers::isReferenceToConst())) .bind(MethodDeclId)), - on(declRefExpr(to(varDecl().bind(ObjectArgId); + on(declRefExpr(to( + varDecl( + unless(hasType(qualType(hasCanonicalType(hasDeclaration(namedDecl( + matchers::matchesAnyListedName(ExcludedContainerTypes + .bind(ObjectArgId); } AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) { @@ -98,11 +103,13 @@ AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) { .bind(InitFunctionCallId); } -AST_MATCHER_FUNCTION(StatementMatcher, initializerReturnsReferenceToConst) { +AST_MATCHER_FUNCTION_P(StatementMatcher, initializerReturnsReferenceToConst, + std::vector, ExcludedContainerTypes) { auto OldVarDeclRef = declRefExpr(to(varDecl(hasLocalStorage()).bind(OldVarDeclId))); return expr( - anyOf(isConstRefReturningFunctionCall(), isConstRefReturningMethodCall(), + anyOf(isConstRefReturningFunctionCall(), +isConstRefReturningMethodCall(ExcludedContainerTypes), ignoringImpCasts(OldVarDeclRef), ignoringImpCasts(unaryOperator(hasOperatorName("&"), hasUnaryOperand(OldVarDeclRef); @@ -120,9 +127,9 @@ AST_MATCHER_FUNCTION(StatementMatcher, initializerReturnsReferenceToConst) { // the same set of criteria we apply when identifying the unnecessary copied // variable in this check to begin with. In this case we check whether the // object arg or variable that is referenced is immutable as well. -static bool isInitializingVariableImmutable(const VarDecl &InitializingVar, -const Stmt &BlockStmt, -ASTContext &Context) { +static bool isInitializingVariableImmutable( +const VarDecl &InitializingVar, const Stmt &BlockStmt, ASTContext &Context, +const std::vector &ExcludedContainerTypes) { if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context)) return false; @@ -138,18 +145,21 @@ static bool isInitializingVariableImmutable(const VarDecl &I
[clang-tools-extra] [clang-tidy] `isOnlyUsedAsConst`: Handle static method calls. (PR #84005)
https://github.com/fberger approved this pull request. https://github.com/llvm/llvm-project/pull/84005 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add support for determining constness of more expressions. (PR #82617)
https://github.com/fberger approved this pull request. https://github.com/llvm/llvm-project/pull/82617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] 671ad58 - [clang-tidy] performance-unnecessary-copy-initialization: Prevent false positives when dependent variable is modified.
Author: Felix Berger Date: 2020-12-10T16:58:17-05:00 New Revision: 671ad580610ad91139358b7786e02ff70433a90e URL: https://github.com/llvm/llvm-project/commit/671ad580610ad91139358b7786e02ff70433a90e DIFF: https://github.com/llvm/llvm-project/commit/671ad580610ad91139358b7786e02ff70433a90e.diff LOG: [clang-tidy] performance-unnecessary-copy-initialization: Prevent false positives when dependent variable is modified. Extend the check to not only look at the variable the unnecessarily copied variable is initialized from, but also ensure that any variable the old variable references is not modified. Extend DeclRefExprUtils to also count references and pointers to const assigned from the DeclRef we check for const usages. Reviewed-by: aaron.ballman Differential Revision: https://reviews.llvm.org/D91893 Added: Modified: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp clang-tools-extra/clang-tidy/utils/Matchers.h clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp Removed: diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp index 24847d80657c..f6b9365435fb 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -19,6 +19,14 @@ namespace tidy { namespace performance { namespace { +using namespace ::clang::ast_matchers; +using llvm::StringRef; +using utils::decl_ref_expr::isOnlyUsedAsConst; + +static constexpr StringRef ObjectArgId = "objectArg"; +static constexpr StringRef InitFunctionCallId = "initFunctionCall"; +static constexpr StringRef OldVarDeclId = "oldVarDecl"; + void recordFixes(const VarDecl &Var, ASTContext &Context, DiagnosticBuilder &Diagnostic) { Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context); @@ -29,10 +37,88 @@ void recordFixes(const VarDecl &Var, ASTContext &Context, } } -} // namespace +AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningMethodCall) { + // Match method call expressions where the `this` argument is only used as + // const, this will be checked in `check()` part. This returned const + // reference is highly likely to outlive the local const reference of the + // variable being declared. The assumption is that the const reference being + // returned either points to a global static variable or to a member of the + // called object. + return cxxMemberCallExpr( + callee(cxxMethodDecl(returns(matchers::isReferenceToConst(, + on(declRefExpr(to(varDecl().bind(ObjectArgId); +} -using namespace ::clang::ast_matchers; -using utils::decl_ref_expr::isOnlyUsedAsConst; +AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) { + // Only allow initialization of a const reference from a free function if it + // has no arguments. Otherwise it could return an alias to one of its + // arguments and the arguments need to be checked for const use as well. + return callExpr(callee(functionDecl(returns(matchers::isReferenceToConst(, + argumentCountIs(0), unless(callee(cxxMethodDecl( + .bind(InitFunctionCallId); +} + +AST_MATCHER_FUNCTION(StatementMatcher, isInitializedFromReferenceToConst) { + auto OldVarDeclRef = + declRefExpr(to(varDecl(hasLocalStorage()).bind(OldVarDeclId))); + return declStmt(has(varDecl(hasInitializer( + anyOf(isConstRefReturningFunctionCall(), isConstRefReturningMethodCall(), +ignoringImpCasts(OldVarDeclRef), +ignoringImpCasts(unaryOperator( +hasOperatorName("&"), hasUnaryOperand(OldVarDeclRef; +} + +// This checks that the variable itself is only used as const, and also makes +// sure that it does not reference another variable that could be modified in +// the BlockStmt. It does this by checking the following: +// 1. If the variable is neither a reference nor a pointer then the +// isOnlyUsedAsConst() check is sufficient. +// 2. If the (reference or pointer) variable is not initialized in a DeclStmt in +// the BlockStmt. In this case its pointee is likely not modified (unless it +// is passed as an alias into the method as well). +// 3. If the reference is initialized from a reference to const. This is +// the same set of criteria we apply when identifying the unnecessary copied +// variable in this check to begin with. In this case we check whether the +// object arg or variable that is referenced is immutable as well. +static bool isInitializingVariableImmutable(const VarDecl &InitializingVar, +const Stmt &BlockStmt, +ASTContex
[clang-tools-extra] ace9653 - [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.
Author: Felix Berger Date: 2020-11-16T17:08:18-05:00 New Revision: ace9653c11c6308401dcda2e8b26bf97e6e66e30 URL: https://github.com/llvm/llvm-project/commit/ace9653c11c6308401dcda2e8b26bf97e6e66e30 DIFF: https://github.com/llvm/llvm-project/commit/ace9653c11c6308401dcda2e8b26bf97e6e66e30.diff LOG: [clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type. This fixes false positive cases where a non-const reference is passed to a std::function but interpreted as a const reference. Fix the definition of the fake std::function added in the test to match std::function and make the bug reproducible. Reviewed-by: aaron.ballman Differential Revision: https://reviews.llvm.org/D90042 Added: Modified: clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp Removed: diff --git a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp index c4bc1835057b..d0933f0860c8 100644 --- a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp +++ b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp @@ -59,9 +59,13 @@ constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, extractNodesByIdTo(Matches, "declRef", DeclRefs); auto ConstReferenceOrValue = qualType(anyOf(referenceType(pointee(qualType(isConstQualified(, - unless(anyOf(referenceType(), pointerType(); + unless(anyOf(referenceType(), pointerType(), + substTemplateTypeParmType(); + auto ConstReferenceOrValueOrReplaced = qualType(anyOf( + ConstReferenceOrValue, + substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue; auto UsedAsConstRefOrValueArg = forEachArgumentWithParam( - DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue))); + DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced))); Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context); extractNodesByIdTo(Matches, "declRef", DeclRefs); Matches = diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp index 9055529c7a3f..120902d0eade 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp @@ -411,12 +411,12 @@ inline namespace __1 { template class function; -template -class function { +template +class function { public: function(); - function(const function &other); - R operator()(Args &&...args) const; + function(const function &Other); + R operator()(ArgTypes... Args) const; }; } // namespace __1 @@ -460,3 +460,19 @@ void positiveFakeStdFunction(std::function F) { } } // namespace fake + +void positiveInvokedOnStdFunction( +std::function Update, +const ExpensiveToCopyType Orig) { + auto Copy = Orig.reference(); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is copy-constructed from a const reference + // CHECK-FIXES: const auto& Copy = Orig.reference(); + Update(Copy); +} + +void negativeInvokedOnStdFunction( +std::function Update, +const ExpensiveToCopyType Orig) { + auto Copy = Orig.reference(); + Update(Copy); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] 1c1f794 - Always allow std::function to be copied.
Author: Felix Berger Date: 2020-10-21T17:20:35-04:00 New Revision: 1c1f794c2b645ba33a98f0359bc9d30bbef89920 URL: https://github.com/llvm/llvm-project/commit/1c1f794c2b645ba33a98f0359bc9d30bbef89920 DIFF: https://github.com/llvm/llvm-project/commit/1c1f794c2b645ba33a98f0359bc9d30bbef89920.diff LOG: Always allow std::function to be copied. Since its call operator is const but can modify the state of its underlying functor we cannot tell whether the copy is necessary or not. This avoids false positives. Reviewed-by: aaron.ballman, gribozavr2 Differential Revision: https://reviews.llvm.org/D89332 Added: Modified: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp Removed: diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp index 03b4450d8ca8..24847d80657c 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -63,8 +63,10 @@ void UnnecessaryCopyInitialization::registerMatchers(MatchFinder *Finder) { declStmt( has(varDecl(hasLocalStorage(), hasType(qualType( - hasCanonicalType( - matchers::isExpensiveToCopy()), + hasCanonicalType(allOf( + matchers::isExpensiveToCopy(), + unless(hasDeclaration(namedDecl( + hasName("::std::function")), unless(hasDeclaration(namedDecl( matchers::matchesAnyListedName( AllowedTypes)), diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp index 7a70bc18a28c..9055529c7a3f 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp @@ -405,3 +405,58 @@ void negativeInitialzedFromFreeFunctionWithNonDefaultArg() { ExpensiveToCopyType Orig; const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig); } + +namespace std { +inline namespace __1 { + +template +class function; +template +class function { +public: + function(); + function(const function &other); + R operator()(Args &&...args) const; +}; + +} // namespace __1 +} // namespace std + +void negativeStdFunction() { + std::function Orig; + std::function Copy = Orig; + int i = Orig(); +} + +using Functor = std::function; + +void negativeAliasedStdFunction() { + Functor Orig; + Functor Copy = Orig; + int i = Orig(); +} + +typedef std::function TypedefFunc; + +void negativeTypedefedStdFunction() { + TypedefFunc Orig; + TypedefFunc Copy = Orig; + int i = Orig(); +} + +namespace fake { +namespace std { +template +struct function { + // Custom copy constructor makes it expensive to copy; + function(const function &); +}; +} // namespace std + +void positiveFakeStdFunction(std::function F) { + auto Copy = F; + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'Copy' of the variable 'F' is never modified; + // CHECK-FIXES: const auto& Copy = F; +} + +} // namespace fake ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] 5dbe3bf - [clang-tidy] performance-unnecessary-copy-initialization: Remove the complete statement when the copied variable is unused.
Author: Felix Berger Date: 2021-06-09T15:52:48-04:00 New Revision: 5dbe3bf4b8dbb7e67d41c7c1360f15d512dd72a0 URL: https://github.com/llvm/llvm-project/commit/5dbe3bf4b8dbb7e67d41c7c1360f15d512dd72a0 DIFF: https://github.com/llvm/llvm-project/commit/5dbe3bf4b8dbb7e67d41c7c1360f15d512dd72a0.diff LOG: [clang-tidy] performance-unnecessary-copy-initialization: Remove the complete statement when the copied variable is unused. It is not useful to keep the statement around and can lead to compiler warnings when -Wall (-Wunused-variable specifically) turned on. Differential Revision: https://reviews.llvm.org/D102175 Reviewed-by: ymandel Added: Modified: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-allowed-types.cpp clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp Removed: diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp index 0cc9a44263021..57a2310e779fb 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -7,9 +7,9 @@ //===--===// #include "UnnecessaryCopyInitialization.h" - #include "../utils/DeclRefExprUtils.h" #include "../utils/FixItHintUtils.h" +#include "../utils/LexerUtils.h" #include "../utils/Matchers.h" #include "../utils/OptionsUtils.h" #include "clang/Basic/Diagnostic.h" @@ -21,6 +21,7 @@ namespace { using namespace ::clang::ast_matchers; using llvm::StringRef; +using utils::decl_ref_expr::allDeclRefExprs; using utils::decl_ref_expr::isOnlyUsedAsConst; static constexpr StringRef ObjectArgId = "objectArg"; @@ -37,6 +38,19 @@ void recordFixes(const VarDecl &Var, ASTContext &Context, } } +void recordRemoval(const DeclStmt &Stmt, ASTContext &Context, + DiagnosticBuilder &Diagnostic) { + // Attempt to remove the whole line until the next non-comment token. + auto Tok = utils::lexer::findNextTokenSkippingComments( + Stmt.getEndLoc(), Context.getSourceManager(), Context.getLangOpts()); + if (Tok) { +Diagnostic << FixItHint::CreateRemoval(SourceRange( +Stmt.getBeginLoc(), Tok->getLocation().getLocWithOffset(-1))); + } else { +Diagnostic << FixItHint::CreateRemoval(Stmt.getSourceRange()); + } +} + AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningMethodCall) { // Match method call expressions where the `this` argument is only used as // const, this will be checked in `check()` part. This returned const @@ -118,6 +132,11 @@ static bool isInitializingVariableImmutable(const VarDecl &InitializingVar, return false; } +bool isVariableUnused(const VarDecl &Var, const Stmt &BlockStmt, + ASTContext &Context) { + return allDeclRefExprs(Var, BlockStmt, Context).empty(); +} + } // namespace UnnecessaryCopyInitialization::UnnecessaryCopyInitialization( @@ -169,14 +188,13 @@ void UnnecessaryCopyInitialization::check( const auto *ObjectArg = Result.Nodes.getNodeAs(ObjectArgId); const auto *BlockStmt = Result.Nodes.getNodeAs("blockStmt"); const auto *CtorCall = Result.Nodes.getNodeAs("ctorCall"); + const auto *Stmt = Result.Nodes.getNodeAs("declStmt"); TraversalKindScope RAII(*Result.Context, TK_AsIs); // Do not propose fixes if the DeclStmt has multiple VarDecls or in macros // since we cannot place them correctly. - bool IssueFix = - Result.Nodes.getNodeAs("declStmt")->isSingleDecl() && - !NewVar->getLocation().isMacroID(); + bool IssueFix = Stmt->isSingleDecl() && !NewVar->getLocation().isMacroID(); // A constructor that looks like T(const T& t, bool arg = false) counts as a // copy only when it is called with default arguments for the arguments after @@ -186,47 +204,68 @@ void UnnecessaryCopyInitialization::check( return; if (OldVar == nullptr) { -handleCopyFromMethodReturn(*NewVar, *BlockStmt, IssueFix, ObjectArg, +handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix, ObjectArg, *Result.Context); } else { -handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, IssueFix, +handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix, *Result.Context); } } void UnnecessaryCopyInitialization::handleCopyFromMethodReturn( -const VarDecl &Var, const Stmt &BlockStmt, bool IssueFix, -const VarDecl *ObjectArg, ASTContext &Context) { +const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt, +
[clang-tools-extra] efa4dbc - [clang-tidy] performance-unnecessary-copy-initialization: Look at the canonical type when checking for aliases.
Author: Felix Berger Date: 2021-06-09T16:36:53-04:00 New Revision: efa4dbc32ca9b7f3319edbcc6ac502ea962c8f0a URL: https://github.com/llvm/llvm-project/commit/efa4dbc32ca9b7f3319edbcc6ac502ea962c8f0a DIFF: https://github.com/llvm/llvm-project/commit/efa4dbc32ca9b7f3319edbcc6ac502ea962c8f0a.diff LOG: [clang-tidy] performance-unnecessary-copy-initialization: Look at the canonical type when checking for aliases. This fixes a false positive case where for instance a pointer is obtained and declared using `auto`. Differential Revision: https://reviews.llvm.org/D103018 Reviewed-by: ymandel Added: Modified: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp Removed: diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp index 57a2310e779fb..27ce36e49a073 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -100,7 +100,7 @@ static bool isInitializingVariableImmutable(const VarDecl &InitializingVar, if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context)) return false; - QualType T = InitializingVar.getType(); + QualType T = InitializingVar.getType().getCanonicalType(); // The variable is a value type and we know it is only used as const. Safe // to reference it and avoid the copy. if (!isa(T)) diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp index 3a4c3ec869e1c..e894f84f11d8c 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp @@ -4,6 +4,7 @@ struct ExpensiveToCopyType { ExpensiveToCopyType(); virtual ~ExpensiveToCopyType(); const ExpensiveToCopyType &reference() const; + const ExpensiveToCopyType *pointer() const; void nonConstMethod(); bool constMethod() const; }; @@ -548,6 +549,25 @@ void negativeCopiedFromGetterOfReferenceToModifiedVar() { Orig.nonConstMethod(); } +void negativeAliasNonCanonicalPointerType() { + ExpensiveToCopyType Orig; + // The use of auto here hides that the type is a pointer type. The check needs + // to look at the canonical type to detect the aliasing through this pointer. + const auto Pointer = Orig.pointer(); + const auto NecessaryCopy = Pointer->reference(); + Orig.nonConstMethod(); +} + +void negativeAliasTypedefedType() { + typedef const ExpensiveToCopyType &ReferenceType; + ExpensiveToCopyType Orig; + // The typedef hides the fact that this is a reference type. The check needs + // to look at the canonical type to detect the aliasing. + ReferenceType Ref = Orig.reference(); + const auto NecessaryCopy = Ref.reference(); + Orig.nonConstMethod(); +} + void positiveCopiedFromGetterOfReferenceToConstVar() { ExpensiveToCopyType Orig; const auto &Ref = Orig.reference(); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] bdd5da9 - [clang-tidy] performance-unnecessary-copy-initialization: Directly examine the initializing var's initializer.
Author: Felix Berger Date: 2021-06-18T15:25:17-04:00 New Revision: bdd5da9dec61072f693726d9ed2a94c78e431ba2 URL: https://github.com/llvm/llvm-project/commit/bdd5da9dec61072f693726d9ed2a94c78e431ba2 DIFF: https://github.com/llvm/llvm-project/commit/bdd5da9dec61072f693726d9ed2a94c78e431ba2.diff LOG: [clang-tidy] performance-unnecessary-copy-initialization: Directly examine the initializing var's initializer. This fixes false positive cases where a reference is initialized outside of a block statement and then its initializing variable is modified. Another case is when the looped over container is modified. Differential Revision: https://reviews.llvm.org/D103021 Reviewed-by: ymandel Added: Modified: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp Removed: diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp index 27ce36e49a073..f75a3a901ecd5 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -12,6 +12,7 @@ #include "../utils/LexerUtils.h" #include "../utils/Matchers.h" #include "../utils/OptionsUtils.h" +#include "clang/AST/Decl.h" #include "clang/Basic/Diagnostic.h" namespace clang { @@ -72,14 +73,14 @@ AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) { .bind(InitFunctionCallId); } -AST_MATCHER_FUNCTION(StatementMatcher, isInitializedFromReferenceToConst) { +AST_MATCHER_FUNCTION(StatementMatcher, initializerReturnsReferenceToConst) { auto OldVarDeclRef = declRefExpr(to(varDecl(hasLocalStorage()).bind(OldVarDeclId))); - return declStmt(has(varDecl(hasInitializer( + return expr( anyOf(isConstRefReturningFunctionCall(), isConstRefReturningMethodCall(), ignoringImpCasts(OldVarDeclRef), -ignoringImpCasts(unaryOperator( -hasOperatorName("&"), hasUnaryOperand(OldVarDeclRef; +ignoringImpCasts(unaryOperator(hasOperatorName("&"), + hasUnaryOperand(OldVarDeclRef); } // This checks that the variable itself is only used as const, and also makes @@ -106,18 +107,14 @@ static bool isInitializingVariableImmutable(const VarDecl &InitializingVar, if (!isa(T)) return true; - auto Matches = - match(findAll(declStmt(has(varDecl(equalsNode(&InitializingVar -.bind("declStmt")), -BlockStmt, Context); - // The reference or pointer is not initialized in the BlockStmt. We assume - // its pointee is not modified then. - if (Matches.empty()) + // The reference or pointer is not declared and hence not initialized anywhere + // in the function. We assume its pointee is not modified then. + if (!InitializingVar.isLocalVarDecl() || !InitializingVar.hasInit()) { return true; + } - const auto *Initialization = selectFirst("declStmt", Matches); - Matches = - match(isInitializedFromReferenceToConst(), *Initialization, Context); + auto Matches = match(initializerReturnsReferenceToConst(), + *InitializingVar.getInit(), Context); // The reference is initialized from a free function without arguments // returning a const reference. This is a global immutable object. if (selectFirst(InitFunctionCallId, Matches) != nullptr) diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h index 8193672218932..c11be2d8885d6 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_UNNECESSARY_COPY_INITIALIZATION_H #include "../ClangTidyCheck.h" +#include "clang/AST/Decl.h" namespace clang { namespace tidy { diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp index e894f84f11d8c..c2b3d8f9c7395 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp @@ -1,10 +1,20 @@ // RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t +template +struct Iterator { + void operator++(); + const T &operator*() const; + bool operator!=(const Iterator &) const
[clang-tools-extra] 187e050 - [clang-tidy] performance-unnecessary-copy-initialization: Disable structured bindings.
Author: Felix Berger Date: 2021-07-12T09:55:27-04:00 New Revision: 187e050b33bbee1ef210c83f5595c283ba671909 URL: https://github.com/llvm/llvm-project/commit/187e050b33bbee1ef210c83f5595c283ba671909 DIFF: https://github.com/llvm/llvm-project/commit/187e050b33bbee1ef210c83f5595c283ba671909.diff LOG: [clang-tidy] performance-unnecessary-copy-initialization: Disable structured bindings. Structured bindings can currently trigger the check and lead to a wrong fix. Because the DecompositionDecl itself is not used and the check does not iterate through its the decl's bindings to verify whether the bindings' holding vars are used this leads to the whole statement to be deleted. To support structured bindings properly 3 cases would need to be considered. 1. All holding vars are not used -> The statement can be deleted. 2. All holding vars are used as const or not used -> auto can be converted to const auto&. 3. Neither case is true -> leave unchanged. In the check we'll have to separate the logic that determines this from the code that produces the diagnostic and fixes and first determine which of the cases we're dealing with before creating fixes. Since this is a bigger refactoring we'll disable structured bindings for now to prevent incorrect fixes. Differential Revision: https://reviews.llvm.org/D105727 Reviewed-by: ymandel Added: Modified: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp Removed: diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp index f75a3a901ecd5..f69a2079e4ba1 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -147,6 +147,7 @@ void UnnecessaryCopyInitialization::registerMatchers(MatchFinder *Finder) { return compoundStmt( forEachDescendant( declStmt( + unless(has(decompositionDecl())), has(varDecl(hasLocalStorage(), hasType(qualType( hasCanonicalType(allOf( diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp index c2b3d8f9c7395..b66a88e5cf81f 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t +// RUN: %check_clang_tidy -std=c++17 %s performance-unnecessary-copy-initialization %t template struct Iterator { @@ -637,3 +637,18 @@ void negativeReferenceIsInitializedOutsideOfBlock() { } }; } + +void negativeStructuredBinding() { + // Structured bindings are not yet supported but can trigger false positives + // since the DecompositionDecl itself is unused and the check doesn't traverse + // VarDecls of the BindingDecls. + struct Pair { +ExpensiveToCopyType first; +ExpensiveToCopyType second; + }; + + Pair P; + const auto [C, D] = P; + C.constMethod(); + D.constMethod(); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] 0ec8120 - [clang-tidy] performance-unnecessary-copy-initialization: Do not remove comments on new lines.
Author: Felix Berger Date: 2021-07-12T16:23:04-04:00 New Revision: 0ec812023b43992810499b04222348fdbdb41ef2 URL: https://github.com/llvm/llvm-project/commit/0ec812023b43992810499b04222348fdbdb41ef2 DIFF: https://github.com/llvm/llvm-project/commit/0ec812023b43992810499b04222348fdbdb41ef2.diff LOG: [clang-tidy] performance-unnecessary-copy-initialization: Do not remove comments on new lines. When deleting the copy assignment statement because copied variable is not used only remove trailing comments on the same line. Differential Revision: https://reviews.llvm.org/D105734 Reviewed-by: ymandel Added: Modified: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp Removed: diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp index f69a2079e4ba1..f6b8e44785b5f 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -39,14 +39,35 @@ void recordFixes(const VarDecl &Var, ASTContext &Context, } } +llvm::Optional firstLocAfterNewLine(SourceLocation Loc, +SourceManager &SM) { + bool Invalid; + const char *TextAfter = SM.getCharacterData(Loc, &Invalid); + if (Invalid) { +return llvm::None; + } + size_t Offset = std::strcspn(TextAfter, "\n"); + return Loc.getLocWithOffset(TextAfter[Offset] == '\0' ? Offset : Offset + 1); +} + void recordRemoval(const DeclStmt &Stmt, ASTContext &Context, DiagnosticBuilder &Diagnostic) { - // Attempt to remove the whole line until the next non-comment token. - auto Tok = utils::lexer::findNextTokenSkippingComments( - Stmt.getEndLoc(), Context.getSourceManager(), Context.getLangOpts()); - if (Tok) { -Diagnostic << FixItHint::CreateRemoval(SourceRange( -Stmt.getBeginLoc(), Tok->getLocation().getLocWithOffset(-1))); + auto &SM = Context.getSourceManager(); + // Attempt to remove trailing comments as well. + auto Tok = utils::lexer::findNextTokenSkippingComments(Stmt.getEndLoc(), SM, + Context.getLangOpts()); + llvm::Optional PastNewLine = + firstLocAfterNewLine(Stmt.getEndLoc(), SM); + if (Tok && PastNewLine) { +auto BeforeFirstTokenAfterComment = Tok->getLocation().getLocWithOffset(-1); +// Remove until the end of the line or the end of a trailing comment which +// ever comes first. +auto End = +SM.isBeforeInTranslationUnit(*PastNewLine, BeforeFirstTokenAfterComment) +? *PastNewLine +: BeforeFirstTokenAfterComment; +Diagnostic << FixItHint::CreateRemoval( +SourceRange(Stmt.getBeginLoc(), End)); } else { Diagnostic << FixItHint::CreateRemoval(Stmt.getSourceRange()); } diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp index b66a88e5cf81f..3ce151035d5be 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp @@ -596,8 +596,15 @@ void positiveUnusedReferenceIsRemoved() { // CHECK-FIXES: int i = 0; // Foo bar. auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment. // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'TrailingCommentRemoved' is copy-constructed from a const reference but is never used; - // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment. + // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); + // CHECK-FIXES-NOT: // Trailing comment. // clang-format on + + auto UnusedAndUnnecessary = ExpensiveTypeReference(); + // Comments on a new line should not be deleted. + // CHECK-MESSAGES: [[@LINE-2]]:8: warning: the variable 'UnusedAndUnnecessary' is copy-constructed + // CHECK-FIXES-NOT: auto UnusedAndUnnecessary = ExpensiveTypeReference(); + // CHECK-FIXES: // Comments on a new line should not be deleted. } void negativeloopedOverObjectIsModified() { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] a189b3b - [clang-tidy] performance-for-range-copy: Don't trigger on implicit type conversions.
Author: Felix Berger Date: 2021-03-02T20:02:48-05:00 New Revision: a189b3b9e8bb398d9fe8770956f8ad1d58c2a214 URL: https://github.com/llvm/llvm-project/commit/a189b3b9e8bb398d9fe8770956f8ad1d58c2a214 DIFF: https://github.com/llvm/llvm-project/commit/a189b3b9e8bb398d9fe8770956f8ad1d58c2a214.diff LOG: [clang-tidy] performance-for-range-copy: Don't trigger on implicit type conversions. This disables the check for false positive cases where implicit type conversion through either an implicit single argument constructor or a member conversion operator is triggered when constructing the loop variable. Fix the test cases that meant to cover these cases. Differential Revision: https://reviews.llvm.org/D97577 Reviewed-by: hokein Added: Modified: clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp Removed: diff --git a/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp b/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp index 4b7a34f6c40f..8046301e3ce7 100644 --- a/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp @@ -45,10 +45,14 @@ void ForRangeCopyCheck::registerMatchers(MatchFinder *Finder) { hasOverloadedOperatorName("*"), callee( cxxMethodDecl(returns(unless(hasCanonicalType(referenceType())); + auto NotConstructedByCopy = cxxConstructExpr( + hasDeclaration(cxxConstructorDecl(unless(isCopyConstructor(); + auto ConstructedByConversion = cxxMemberCallExpr(callee(cxxConversionDecl())); auto LoopVar = varDecl(HasReferenceOrPointerTypeOrIsAllowed, - unless(hasInitializer(expr(hasDescendant(expr(anyOf( - materializeTemporaryExpr(), IteratorReturnsValueType))); + unless(hasInitializer(expr(hasDescendant(expr( + anyOf(materializeTemporaryExpr(), IteratorReturnsValueType, +NotConstructedByCopy, ConstructedByConversion))); Finder->addMatcher( traverse(TK_AsIs, cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar"))) diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp index e22650e10198..07b5116dfb14 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp @@ -60,13 +60,13 @@ void negativeConstReference() { void negativeUserDefinedConversion() { Convertible C[0]; - for (const S &S1 : C) { + for (const S S1 : C) { } } void negativeImplicitConstructorConversion() { ConstructorConvertible C[0]; - for (const S &S1 : C) { + for (const S S1 : C) { } } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] fefe20b - [clang-tidy] performance-unnecessary-copy-initialization: Correctly match the type name of the thisPointertype.
Author: Felix Berger Date: 2021-11-20T15:13:41-05:00 New Revision: fefe20b99313d6b0738806d1504652c3b7edb9e0 URL: https://github.com/llvm/llvm-project/commit/fefe20b99313d6b0738806d1504652c3b7edb9e0 DIFF: https://github.com/llvm/llvm-project/commit/fefe20b99313d6b0738806d1504652c3b7edb9e0.diff LOG: [clang-tidy] performance-unnecessary-copy-initialization: Correctly match the type name of the thisPointertype. The matching did not work correctly for pointer and reference types. Differential Revision: https://reviews.llvm.org/D114212 Reviewed-by: courbet Added: Modified: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp Removed: diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp index 2cdd7827ee42..514ce6f6e3b8 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -87,11 +87,9 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, isConstRefReturningMethodCall, callee(cxxMethodDecl( returns(hasCanonicalType(matchers::isReferenceToConst( .bind(MethodDeclId)), - on(declRefExpr(to( - varDecl( - unless(hasType(qualType(hasCanonicalType(hasDeclaration(namedDecl( - matchers::matchesAnyListedName(ExcludedContainerTypes - .bind(ObjectArgId); + on(declRefExpr(to(varDecl().bind(ObjectArgId, + thisPointerType(namedDecl( + unless(matchers::matchesAnyListedName(ExcludedContainerTypes); } AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) { diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp index 6d1d28ad1498..88b850fe2ff8 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp @@ -58,3 +58,13 @@ void excludedConstIncorrectType() { const auto E = C.secretlyMutates(); E.constMethod(); } + +void excludedConstIncorrectTypeAsPointer(ConstInCorrectType *C) { + const auto E = C->secretlyMutates(); + E.constMethod(); +} + +void excludedConstIncorrectTypeAsReference(const ConstInCorrectType &C) { + const auto E = C.secretlyMutates(); + E.constMethod(); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] r289912 - [clang-tidy] Do not move parameter if only DeclRefExpr occurs inside of a loop
Author: flx Date: Thu Dec 15 20:47:56 2016 New Revision: 289912 URL: http://llvm.org/viewvc/llvm-project?rev=289912&view=rev Log: [clang-tidy] Do not move parameter if only DeclRefExpr occurs inside of a loop Summary: This fixes a bug where the performance-unnecessary-value-param check suggests a fix to move the parameter inside of a loop which could be invoked multiple times. Reviewers: sbenza, aaron.ballman, alexfh Subscribers: JDevlieghere, cfe-commits Differential Revision: https://reviews.llvm.org/D27187 Modified: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Modified: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp?rev=289912&r1=289911&r2=289912&view=diff == --- clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp (original) +++ clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp Thu Dec 15 20:47:56 2016 @@ -47,6 +47,17 @@ bool isReferencedOutsideOfCallExpr(const return !Matches.empty(); } +bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Stmt &Stmt, + ASTContext &Context) { + auto Matches = + match(findAll(declRefExpr( +equalsNode(&DeclRef), +unless(hasAncestor(stmt(anyOf(forStmt(), cxxForRangeStmt(), + whileStmt(), doStmt())), +Stmt, Context); + return Matches.empty(); +} + } // namespace UnnecessaryValueParamCheck::UnnecessaryValueParamCheck( @@ -105,6 +116,8 @@ void UnnecessaryValueParamCheck::check(c if (!IsConstQualified) { auto CanonicalType = Param->getType().getCanonicalType(); if (AllDeclRefExprs.size() == 1 && +!hasLoopStmtAncestor(**AllDeclRefExprs.begin(), *Function->getBody(), + *Result.Context) && ((utils::type_traits::hasNonTrivialMoveConstructor(CanonicalType) && utils::decl_ref_expr::isCopyConstructorArgument( **AllDeclRefExprs.begin(), *Function->getBody(), Modified: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp?rev=289912&r1=289911&r2=289912&view=diff == --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp (original) +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Thu Dec 15 20:47:56 2016 @@ -225,6 +225,15 @@ void PositiveMoveOnCopyAssignment(Expens // CHECK-FIXES: F = std::move(E); } +// The argument could be moved but is not since copy statement is inside a loop. +void PositiveNoMoveInsideLoop(ExpensiveMovableType E) { + // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the parameter 'E' is copied + // CHECK-FIXES: void PositiveNoMoveInsideLoop(const ExpensiveMovableType& E) { + for (;;) { +auto F = E; + } +} + void PositiveConstRefNotMoveConstructible(ExpensiveToCopyType T) { // CHECK-MESSAGES: [[@LINE-1]]:63: warning: the parameter 'T' is copied // CHECK-FIXES: void PositiveConstRefNotMoveConstructible(const ExpensiveToCopyType& T) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] r292491 - [clang-tidy] Do not trigger move fix for non-copy assignment operators in performance-unnecessary-value-param check
Author: flx Date: Thu Jan 19 09:51:10 2017 New Revision: 292491 URL: http://llvm.org/viewvc/llvm-project?rev=292491&view=rev Log: [clang-tidy] Do not trigger move fix for non-copy assignment operators in performance-unnecessary-value-param check Reviewers: alexfh, sbenza, malcolm.parsons Subscribers: JDevlieghere, cfe-commits Differential Revision: https://reviews.llvm.org/D28899 Modified: clang-tools-extra/trunk/clang-tidy/utils/DeclRefExprUtils.cpp clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Modified: clang-tools-extra/trunk/clang-tidy/utils/DeclRefExprUtils.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/utils/DeclRefExprUtils.cpp?rev=292491&r1=292490&r2=292491&view=diff == --- clang-tools-extra/trunk/clang-tidy/utils/DeclRefExprUtils.cpp (original) +++ clang-tools-extra/trunk/clang-tidy/utils/DeclRefExprUtils.cpp Thu Jan 19 09:51:10 2017 @@ -159,7 +159,8 @@ bool isCopyAssignmentArgument(const Decl parmVarDecl(hasType(matchers::isReferenceToConst(; auto Matches = match( decl(hasDescendant( - cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName("=")) + cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName("="), + callee(cxxMethodDecl(isCopyAssignmentOperator( .bind("operatorCallExpr"))), Decl, Context); return !Matches.empty(); Modified: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp?rev=292491&r1=292490&r2=292491&view=diff == --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp (original) +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Thu Jan 19 09:51:10 2017 @@ -247,6 +247,17 @@ void PositiveMoveOnCopyAssignment(Expens // CHECK-FIXES: F = std::move(E); } +struct NotCopyAssigned { + NotCopyAssigned &operator=(const ExpensiveMovableType &); +}; + +void PositiveNoMoveForNonCopyAssigmentOperator(ExpensiveMovableType E) { + // CHECK-MESSAGES: [[@LINE-1]]:69: warning: the parameter 'E' is copied + // CHECK-FIXES: void PositiveNoMoveForNonCopyAssigmentOperator(const ExpensiveMovableType& E) { + NotCopyAssigned N; + N = E; +} + // The argument could be moved but is not since copy statement is inside a loop. void PositiveNoMoveInsideLoop(ExpensiveMovableType E) { // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the parameter 'E' is copied ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] r309067 - [clang-tidy] Do not issue fixit for explicit template specializations
Author: flx Date: Tue Jul 25 17:45:41 2017 New Revision: 309067 URL: http://llvm.org/viewvc/llvm-project?rev=309067&view=rev Log: [clang-tidy] Do not issue fixit for explicit template specializations Summary: Do not issue fixit in UnnecessaryValueParamCheck if the function is an explicit template specialization as this could cause build breakages. Reviewers: alexfh Subscribers: JDevlieghere, xazax.hun, cfe-commits Differential Revision: https://reviews.llvm.org/D35718 Modified: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Modified: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp?rev=309067&r1=309066&r2=309067&view=diff == --- clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp (original) +++ clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp Tue Jul 25 17:45:41 2017 @@ -58,6 +58,18 @@ bool hasLoopStmtAncestor(const DeclRefEx return Matches.empty(); } +bool isExplicitTemplateSpecialization(const FunctionDecl &Function) { + if (const auto *SpecializationInfo = Function.getTemplateSpecializationInfo()) +if (SpecializationInfo->getTemplateSpecializationKind() == +TSK_ExplicitSpecialization) + return true; + if (const auto *Method = llvm::dyn_cast(&Function)) +if (Method->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization && +Method->getMemberSpecializationInfo()->isExplicitSpecialization()) + return true; + return false; +} + } // namespace UnnecessaryValueParamCheck::UnnecessaryValueParamCheck( @@ -133,9 +145,11 @@ void UnnecessaryValueParamCheck::check(c // 2. the function is virtual as it might break overrides // 3. the function is referenced outside of a call expression within the //compilation unit as the signature change could introduce build errors. + // 4. the function is an explicit template specialization. const auto *Method = llvm::dyn_cast(Function); if (Param->getLocStart().isMacroID() || (Method && Method->isVirtual()) || - isReferencedOutsideOfCallExpr(*Function, *Result.Context)) + isReferencedOutsideOfCallExpr(*Function, *Result.Context) || + isExplicitTemplateSpecialization(*Function)) return; for (const auto *FunctionDecl = Function; FunctionDecl != nullptr; FunctionDecl = FunctionDecl->getPreviousDecl()) { Modified: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp?rev=309067&r1=309066&r2=309067&view=diff == --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp (original) +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Tue Jul 25 17:45:41 2017 @@ -348,3 +348,14 @@ void fun() { ExpensiveToCopyType E; NegativeUsingConstructor S(E); } + +template +void templateFunction(T) { +} + +template<> +void templateFunction(ExpensiveToCopyType E) { + // CHECK-MESSAGES: [[@LINE-1]]:64: warning: the parameter 'E' is copied + // CHECK-FIXES: void templateFunction(ExpensiveToCopyType E) { + E.constReference(); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] r288502 - [clang-tidy] Do not trigger unnecessary-value-param check on methods marked as final
Author: flx Date: Fri Dec 2 08:44:16 2016 New Revision: 288502 URL: http://llvm.org/viewvc/llvm-project?rev=288502&view=rev Log: [clang-tidy] Do not trigger unnecessary-value-param check on methods marked as final Summary: Virtual method overrides of dependent types cannot be recognized unless they are marked as override or final. Exclude methods marked as final from check and add test. Reviewers: sbenza, hokein, alexfh Subscribers: malcolm.parsons, JDevlieghere, cfe-commits Differential Revision: https://reviews.llvm.org/D27248 Modified: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Modified: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp?rev=288502&r1=288501&r2=288502&view=diff == --- clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp (original) +++ clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp Fri Dec 2 08:44:16 2016 @@ -61,7 +61,8 @@ void UnnecessaryValueParamCheck::registe unless(referenceType(), decl().bind("param")); Finder->addMatcher( - functionDecl(isDefinition(), unless(cxxMethodDecl(isOverride())), + functionDecl(isDefinition(), + unless(cxxMethodDecl(anyOf(isOverride(), isFinal(, unless(isInstantiated()), has(typeLoc(forEach(ExpensiveValueParamDecl))), decl().bind("functionDecl")), Modified: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp?rev=288502&r1=288501&r2=288502&view=diff == --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp (original) +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Fri Dec 2 08:44:16 2016 @@ -271,3 +271,21 @@ void PositiveMessageAndFixAsFunctionIsCa void ReferenceFunctionByCallingIt() { PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType()); } + +// Virtual method overrides of dependent types cannot be recognized unless they +// are marked as override or final. Test that check is not triggered on methods +// marked with override or final. +template +struct NegativeDependentTypeInterface { + virtual void Method(ExpensiveToCopyType E) = 0; +}; + +template +struct NegativeOverrideImpl : public NegativeDependentTypeInterface { + void Method(ExpensiveToCopyType E) override {} +}; + +template +struct NegativeFinalImpl : public NegativeDependentTypeInterface { + void Method(ExpensiveToCopyType E) final {} +}; ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26195: Ignore incomplete types when determining whether they are expensive to copy
flx created this revision. flx added a reviewer: alexfh. flx added a subscriber: cfe-commits. flx set the repository for this revision to rL LLVM. IsExpensiveToCopy can return false positives for incomplete types, so ignore them. All existing ClangTidy tests that depend on this function still pass as the types are complete. Repository: rL LLVM https://reviews.llvm.org/D26195 Files: clang-tidy/utils/TypeTraits.cpp Index: clang-tidy/utils/TypeTraits.cpp === --- clang-tidy/utils/TypeTraits.cpp +++ clang-tidy/utils/TypeTraits.cpp @@ -41,7 +41,7 @@ llvm::Optional isExpensiveToCopy(QualType Type, const ASTContext &Context) { - if (Type->isDependentType()) + if (Type->isDependentType() || Type->isIncompleteType()) return llvm::None; return !Type.isTriviallyCopyableType(Context) && !classHasTrivialCopyAndDestroy(Type) && Index: clang-tidy/utils/TypeTraits.cpp === --- clang-tidy/utils/TypeTraits.cpp +++ clang-tidy/utils/TypeTraits.cpp @@ -41,7 +41,7 @@ llvm::Optional isExpensiveToCopy(QualType Type, const ASTContext &Context) { - if (Type->isDependentType()) + if (Type->isDependentType() || Type->isIncompleteType()) return llvm::None; return !Type.isTriviallyCopyableType(Context) && !classHasTrivialCopyAndDestroy(Type) && ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26195: Ignore incomplete types when determining whether they are expensive to copy
flx added a comment. In https://reviews.llvm.org/D26195#584712, @aaron.ballman wrote: > Please add a test case with an incomplete type that would exercise this code > path, otherwise, LGTM. Hi Aaron, do you have any advise on how to add an incomplete type? When debugging this I had a compilation unit that failed to compile causing it, but I'm not sure this is a good way to add a test case. Repository: rL LLVM https://reviews.llvm.org/D26195 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26203: [ClangTidy - performance-unnecessary-value-param]: Do not issue fix for functions that are referenced outside of callExpr
flx created this revision. flx added reviewers: alexfh, sbenza. flx added a subscriber: cfe-commits. flx set the repository for this revision to rL LLVM. Suppress fixes for functions that are referenced within the compilation unit outside of a call expression as the signature change could break the code referencing the function. We still issue a warning in this case so that users can decide to manually change the function signature. Repository: rL LLVM https://reviews.llvm.org/D26203 Files: clang-tidy/performance/UnnecessaryValueParamCheck.cpp test/clang-tidy/performance-unnecessary-value-param.cpp Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -237,3 +237,21 @@ ExpensiveToCopyType B; B = A; } + +void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:75: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { +} + +void ReferenceFunctionOutsideOfCallExpr() { + void (*ptr)(ExpensiveToCopyType) = &PositiveOnlyMessageAsReferencedInCompilationUnit; +} + +void PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveMessageAndFixAsFunctionIsCalled(const ExpensiveToCopyType& A) { +} + +void ReferenceFunctionByCallingIt() { + PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType()); +} Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp === --- clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -39,6 +39,14 @@ return true; } +bool isReferencedOutsideOfCallExpr(const FunctionDecl &Function, + ASTContext &Context) { + auto Matches = match(declRefExpr(to(functionDecl(equalsNode(&Function))), + unless(hasAncestor(callExpr(, + Context); + return !Matches.empty(); +} + } // namespace UnnecessaryValueParamCheck::UnnecessaryValueParamCheck( @@ -118,10 +126,14 @@ "invocation but only used as a const reference; " "consider making it a const reference") << paramNameOrIndex(Param->getName(), Index); - // Do not propose fixes in macros since we cannot place them correctly, or if - // function is virtual as it might break overrides. + // Do not propose fixes when: + // 1. in macros since we cannot place them correctly + // 2. the function is virtual as it might break overrides + // 3. the function is referenced outside of a call expression within the + //compilation unit as the signature change could introduce build errors. const auto *Method = llvm::dyn_cast(Function); - if (Param->getLocStart().isMacroID() || (Method && Method->isVirtual())) + if (Param->getLocStart().isMacroID() || (Method && Method->isVirtual()) || + isReferencedOutsideOfCallExpr(*Function, *Result.Context)) return; for (const auto *FunctionDecl = Function; FunctionDecl != nullptr; FunctionDecl = FunctionDecl->getPreviousDecl()) { Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -237,3 +237,21 @@ ExpensiveToCopyType B; B = A; } + +void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:75: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { +} + +void ReferenceFunctionOutsideOfCallExpr() { + void (*ptr)(ExpensiveToCopyType) = &PositiveOnlyMessageAsReferencedInCompilationUnit; +} + +void PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveMessageAndFixAsFunctionIsCalled(const ExpensiveToCopyType& A) { +} + +void ReferenceFunctionByCallingIt() { + PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType()); +} Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp === --- clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -39,6 +39,14 @@ return true; } +bool isReferencedOutsideOfCallExpr(const FunctionDecl &Function, + ASTContext &Context) { + auto Matches = match(declRefExpr(to(functionDec
[PATCH] D26195: Ignore incomplete types when determining whether they are expensive to copy
flx added a comment. In https://reviews.llvm.org/D26195#584730, @aaron.ballman wrote: > In https://reviews.llvm.org/D26195#584724, @flx wrote: > > > In https://reviews.llvm.org/D26195#584712, @aaron.ballman wrote: > > > > > Please add a test case with an incomplete type that would exercise this > > > code path, otherwise, LGTM. > > > > > > Hi Aaron, > > > > do you have any advise on how to add an incomplete type? When debugging > > this I had a compilation unit that failed to compile causing it, but I'm > > not sure this is a good way to add a test case. > > > A type like `class C;` is an incomplete type, as is `void`, so perhaps you > can find a check that would let such a construct call through to > `isExpensiveToCopy()`. Great, this works and I was able to see the check produce a false positive without the proposed change here, but the test code introduces a compile error now due to the incomplete type used in the function definition. Is there a way to suppress that? Repository: rL LLVM https://reviews.llvm.org/D26195 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26207: [ClangTidy - performance-unnecessary-value-param] Only add "const" when current parameter is not already const qualified
flx created this revision. flx added reviewers: alexfh, sbenza, aaron.ballman. flx added a subscriber: cfe-commits. flx set the repository for this revision to rL LLVM. Repository: rL LLVM https://reviews.llvm.org/D26207 Files: clang-tidy/performance/UnnecessaryValueParamCheck.cpp test/clang-tidy/performance-unnecessary-value-param.cpp Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -237,3 +237,12 @@ ExpensiveToCopyType B; B = A; } + +// Case where parameter in declaration is already const-qualified but not in +// implementation. Make sure a second 'const' is not added to the declaration. +void PositiveConstDeclaration(const ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A); +void PositiveConstDeclaration(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) { +} Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp === --- clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -128,7 +128,8 @@ const auto &CurrentParam = *FunctionDecl->getParamDecl(Index); Diag << utils::fixit::changeVarDeclToReference(CurrentParam, *Result.Context); -if (!IsConstQualified) +if (!IsConstQualified && +!CurrentParam.getType().getCanonicalType().isConstQualified()) Diag << utils::fixit::changeVarDeclToConst(CurrentParam); } } Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -237,3 +237,12 @@ ExpensiveToCopyType B; B = A; } + +// Case where parameter in declaration is already const-qualified but not in +// implementation. Make sure a second 'const' is not added to the declaration. +void PositiveConstDeclaration(const ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A); +void PositiveConstDeclaration(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) { +} Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp === --- clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -128,7 +128,8 @@ const auto &CurrentParam = *FunctionDecl->getParamDecl(Index); Diag << utils::fixit::changeVarDeclToReference(CurrentParam, *Result.Context); -if (!IsConstQualified) +if (!IsConstQualified && +!CurrentParam.getType().getCanonicalType().isConstQualified()) Diag << utils::fixit::changeVarDeclToConst(CurrentParam); } } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26207: [ClangTidy - performance-unnecessary-value-param] Only add "const" when current parameter is not already const qualified
flx updated this revision to Diff 76630. Repository: rL LLVM https://reviews.llvm.org/D26207 Files: clang-tidy/performance/UnnecessaryValueParamCheck.cpp test/clang-tidy/performance-unnecessary-value-param.cpp Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -237,3 +237,19 @@ ExpensiveToCopyType B; B = A; } + +// Case where parameter in declaration is already const-qualified but not in +// implementation. Make sure a second 'const' is not added to the declaration. +void PositiveConstDeclaration(const ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A); +void PositiveConstDeclaration(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) { +} + +void PositiveNonConstDeclaration(ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A); +void PositiveNonConstDeclaration(const ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A' + // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) { +} Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp === --- clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -128,7 +128,7 @@ const auto &CurrentParam = *FunctionDecl->getParamDecl(Index); Diag << utils::fixit::changeVarDeclToReference(CurrentParam, *Result.Context); -if (!IsConstQualified) +if (!CurrentParam.getType().getCanonicalType().isConstQualified()) Diag << utils::fixit::changeVarDeclToConst(CurrentParam); } } Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -237,3 +237,19 @@ ExpensiveToCopyType B; B = A; } + +// Case where parameter in declaration is already const-qualified but not in +// implementation. Make sure a second 'const' is not added to the declaration. +void PositiveConstDeclaration(const ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A); +void PositiveConstDeclaration(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) { +} + +void PositiveNonConstDeclaration(ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A); +void PositiveNonConstDeclaration(const ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A' + // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) { +} Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp === --- clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -128,7 +128,7 @@ const auto &CurrentParam = *FunctionDecl->getParamDecl(Index); Diag << utils::fixit::changeVarDeclToReference(CurrentParam, *Result.Context); -if (!IsConstQualified) +if (!CurrentParam.getType().getCanonicalType().isConstQualified()) Diag << utils::fixit::changeVarDeclToConst(CurrentParam); } } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26207: [ClangTidy - performance-unnecessary-value-param] Only add "const" when current parameter is not already const qualified
flx added inline comments. Comment at: test/clang-tidy/performance-unnecessary-value-param.cpp:242 +// Case where parameter in declaration is already const-qualified but not in +// implementation. Make sure a second 'const' is not added to the declaration. +void PositiveConstDeclaration(const ExpensiveToCopyType A); aaron.ballman wrote: > This comment doesn't really match the test cases. The original code has two > *different* declarations (only one of which is a definition), not one > declaration and one redeclaration with the definition. > > I think what is really happening is that it is adding the `&` qualifier to > the first declaration, and adding the `const` and `&` qualifiers to the > second declaration, and the result is that you get harmonization. But it > brings up a question to me; what happens with: > ``` > void f1(ExpensiveToCopyType A) { > } > > void f1(const ExpensiveToCopyType A) { > > } > ``` > Does the fix-it try to create two definitions of the same function? Good catch. I added the reverse case as well and modified the check slightly to make that case work as well. Comment at: test/clang-tidy/performance-unnecessary-value-param.cpp:244 +void PositiveConstDeclaration(const ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A); +void PositiveConstDeclaration(ExpensiveToCopyType A) { aaron.ballman wrote: > Is the `CHECK-MESSAGES` missing? The message is only generated on the definition below, the declaration will only have a fix. Repository: rL LLVM https://reviews.llvm.org/D26207 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26195: Ignore incomplete types when determining whether they are expensive to copy
flx added a comment. In https://reviews.llvm.org/D26195#585091, @aaron.ballman wrote: > In https://reviews.llvm.org/D26195#584958, @flx wrote: > > > In https://reviews.llvm.org/D26195#584730, @aaron.ballman wrote: > > > > > In https://reviews.llvm.org/D26195#584724, @flx wrote: > > > > > > > In https://reviews.llvm.org/D26195#584712, @aaron.ballman wrote: > > > > > > > > > Please add a test case with an incomplete type that would exercise > > > > > this code path, otherwise, LGTM. > > > > > > > > > > > > Hi Aaron, > > > > > > > > do you have any advise on how to add an incomplete type? When debugging > > > > this I had a compilation unit that failed to compile causing it, but > > > > I'm not sure this is a good way to add a test case. > > > > > > > > > A type like `class C;` is an incomplete type, as is `void`, so perhaps > > > you can find a check that would let such a construct call through to > > > `isExpensiveToCopy()`. > > > > > > Great, this works and I was able to see the check produce a false positive > > without the proposed change here, but the test code introduces a compile > > error now due to the incomplete type used in the function definition. Is > > there a way to suppress that? > > > Unlikely -- fixing the compile error likely makes the type not expensive to > copy by using a pointer (or reference). This may be tricky to test because > the times when you would call `isExpensiveToCopy()` is with types that are > going to be logically required to be complete. I am not certain the compile > error is actually a problem though -- I would imagine your existing > false-positives (that you mentioned in the patch summary) are cases where > there is a compile error *and* a clang-tidy diagnostic, so the test may > simply be "check that there's only a compile error and no clang-tidy > diagnostic where there used to be a false-positive one." That's exactly the case, my question here is how can I make the test succeed in the face of a compile error, i.e. by expecting the error as well? Repository: rL LLVM https://reviews.llvm.org/D26195 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26207: [ClangTidy - performance-unnecessary-value-param] Only add "const" when current parameter is not already const qualified
flx added inline comments. Comment at: test/clang-tidy/performance-unnecessary-value-param.cpp:242 +// Case where parameter in declaration is already const-qualified but not in +// implementation. Make sure a second 'const' is not added to the declaration. +void PositiveConstDeclaration(const ExpensiveToCopyType A); aaron.ballman wrote: > flx wrote: > > aaron.ballman wrote: > > > This comment doesn't really match the test cases. The original code has > > > two *different* declarations (only one of which is a definition), not one > > > declaration and one redeclaration with the definition. > > > > > > I think what is really happening is that it is adding the `&` qualifier > > > to the first declaration, and adding the `const` and `&` qualifiers to > > > the second declaration, and the result is that you get harmonization. But > > > it brings up a question to me; what happens with: > > > ``` > > > void f1(ExpensiveToCopyType A) { > > > } > > > > > > void f1(const ExpensiveToCopyType A) { > > > > > > } > > > ``` > > > Does the fix-it try to create two definitions of the same function? > > Good catch. I added the reverse case as well and modified the check > > slightly to make that case work as well. > Can you add a test like this as well? > ``` > void f1(ExpensiveToCopyType A); // Declared, not defined > > void f1(const ExpensiveToCopyType A) {} > void f1(const ExpensiveToCopyType &A) {} > ``` > I'm trying to make sure this check does not suggest a fixit that breaks > existing code because of overload sets. I would expect a diagnostic for the > first two declarations, but no fixit suggestion for `void f1(const > ExpensiveToCopyType A)` because that would result in an ambiguous function > definition. The current code suggests the following fixes: -void f1(ExpensiveToCopyType A); // Declared, not defined +void f1(const ExpensiveToCopyType& A); // Declared, not defined -void f1(const ExpensiveToCopyType A) {} +void f1(const ExpensiveToCopyType& A) {} void f1(const ExpensiveToCopyType &A) {} and we get a warning message for the void f1(const ExpensiveToCopyType A) {} I think the compiler sees "void f1(const ExpensiveToCopyType A) {}" as definition of "void f1(ExpensiveToCopyType A); // Declared, not defined" and thus both places get fixed. Since the check is catching cases where the value argument is either modified or could be moved it and this is not the case here it is worth raising this issue of what looks like a very subtle difference in overrides. My inclination is to leave this as is. What do you suggest we do? Repository: rL LLVM https://reviews.llvm.org/D26207 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26207: [ClangTidy - performance-unnecessary-value-param] Only add "const" when current parameter is not already const qualified
flx marked an inline comment as done. flx added inline comments. Comment at: test/clang-tidy/performance-unnecessary-value-param.cpp:242 +// Case where parameter in declaration is already const-qualified but not in +// implementation. Make sure a second 'const' is not added to the declaration. +void PositiveConstDeclaration(const ExpensiveToCopyType A); aaron.ballman wrote: > flx wrote: > > aaron.ballman wrote: > > > flx wrote: > > > > aaron.ballman wrote: > > > > > This comment doesn't really match the test cases. The original code > > > > > has two *different* declarations (only one of which is a definition), > > > > > not one declaration and one redeclaration with the definition. > > > > > > > > > > I think what is really happening is that it is adding the `&` > > > > > qualifier to the first declaration, and adding the `const` and `&` > > > > > qualifiers to the second declaration, and the result is that you get > > > > > harmonization. But it brings up a question to me; what happens with: > > > > > ``` > > > > > void f1(ExpensiveToCopyType A) { > > > > > } > > > > > > > > > > void f1(const ExpensiveToCopyType A) { > > > > > > > > > > } > > > > > ``` > > > > > Does the fix-it try to create two definitions of the same function? > > > > Good catch. I added the reverse case as well and modified the check > > > > slightly to make that case work as well. > > > Can you add a test like this as well? > > > ``` > > > void f1(ExpensiveToCopyType A); // Declared, not defined > > > > > > void f1(const ExpensiveToCopyType A) {} > > > void f1(const ExpensiveToCopyType &A) {} > > > ``` > > > I'm trying to make sure this check does not suggest a fixit that breaks > > > existing code because of overload sets. I would expect a diagnostic for > > > the first two declarations, but no fixit suggestion for `void f1(const > > > ExpensiveToCopyType A)` because that would result in an ambiguous > > > function definition. > > The current code suggests the following fixes: > > > > -void f1(ExpensiveToCopyType A); // Declared, not defined > > +void f1(const ExpensiveToCopyType& A); // Declared, not defined > > > > -void f1(const ExpensiveToCopyType A) {} > > +void f1(const ExpensiveToCopyType& A) {} > > void f1(const ExpensiveToCopyType &A) {} > > > > and we get a warning message for the void f1(const ExpensiveToCopyType A) {} > > > > I think the compiler sees "void f1(const ExpensiveToCopyType A) {}" as > > definition of "void f1(ExpensiveToCopyType A); // Declared, not defined" > > and thus both places get fixed. > > > > Since the check is catching cases where the value argument is either > > modified or could be moved it and this is not the case here it is worth > > raising this issue of what looks like a very subtle difference in overrides. > > > > My inclination is to leave this as is. What do you suggest we do? > > > I think this behavior isn't new with your changes, so we can leave it as is. > However, we should file a bug report about the bad behavior with overload > sets (and provide the example that's failing) so that we don't forget to come > back and fix the functionality. Filed to track this: https://llvm.org/bugs/show_bug.cgi?id=30902 ( https://reviews.llvm.org/D26207 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26207: [ClangTidy - performance-unnecessary-value-param] Only add "const" when current parameter is not already const qualified
flx removed rL LLVM as the repository for this revision. flx updated this revision to Diff 76877. https://reviews.llvm.org/D26207 Files: clang-tidy/performance/UnnecessaryValueParamCheck.cpp test/clang-tidy/performance-unnecessary-value-param.cpp Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -237,3 +237,19 @@ ExpensiveToCopyType B; B = A; } + +// Case where parameter in declaration is already const-qualified but not in +// implementation. Make sure a second 'const' is not added to the declaration. +void PositiveConstDeclaration(const ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A); +void PositiveConstDeclaration(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) { +} + +void PositiveNonConstDeclaration(ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A); +void PositiveNonConstDeclaration(const ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A' + // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) { +} Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp === --- clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -128,7 +128,10 @@ const auto &CurrentParam = *FunctionDecl->getParamDecl(Index); Diag << utils::fixit::changeVarDeclToReference(CurrentParam, *Result.Context); -if (!IsConstQualified) +// The parameter of each declaration needs to be checked individually as to +// whether it is const or not as constness can differ between definition and +// declaration. +if (!CurrentParam.getType().getCanonicalType().isConstQualified()) Diag << utils::fixit::changeVarDeclToConst(CurrentParam); } } Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -237,3 +237,19 @@ ExpensiveToCopyType B; B = A; } + +// Case where parameter in declaration is already const-qualified but not in +// implementation. Make sure a second 'const' is not added to the declaration. +void PositiveConstDeclaration(const ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A); +void PositiveConstDeclaration(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) { +} + +void PositiveNonConstDeclaration(ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A); +void PositiveNonConstDeclaration(const ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A' + // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) { +} Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp === --- clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -128,7 +128,10 @@ const auto &CurrentParam = *FunctionDecl->getParamDecl(Index); Diag << utils::fixit::changeVarDeclToReference(CurrentParam, *Result.Context); -if (!IsConstQualified) +// The parameter of each declaration needs to be checked individually as to +// whether it is const or not as constness can differ between definition and +// declaration. +if (!CurrentParam.getType().getCanonicalType().isConstQualified()) Diag << utils::fixit::changeVarDeclToConst(CurrentParam); } } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26207: [ClangTidy - performance-unnecessary-value-param] Only add "const" when current parameter is not already const qualified
flx added a comment. Aaron, do you have any other comments or does the patch look good to you? https://reviews.llvm.org/D26207 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26195: Ignore incomplete types when determining whether they are expensive to copy
flx removed rL LLVM as the repository for this revision. flx updated this revision to Diff 76928. https://reviews.llvm.org/D26195 Files: clang-tidy/utils/TypeTraits.cpp test/clang-tidy/performance-unnecessary-value-param.cpp Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 // CHECK-FIXES: #include @@ -237,3 +237,8 @@ ExpensiveToCopyType B; B = A; } + +struct IncompleteType; +void NegativeForIncompleteType(IncompleteType I) { + // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] +} Index: clang-tidy/utils/TypeTraits.cpp === --- clang-tidy/utils/TypeTraits.cpp +++ clang-tidy/utils/TypeTraits.cpp @@ -41,7 +41,7 @@ llvm::Optional isExpensiveToCopy(QualType Type, const ASTContext &Context) { - if (Type->isDependentType()) + if (Type->isDependentType() || Type->isIncompleteType()) return llvm::None; return !Type.isTriviallyCopyableType(Context) && !classHasTrivialCopyAndDestroy(Type) && Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 // CHECK-FIXES: #include @@ -237,3 +237,8 @@ ExpensiveToCopyType B; B = A; } + +struct IncompleteType; +void NegativeForIncompleteType(IncompleteType I) { + // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] +} Index: clang-tidy/utils/TypeTraits.cpp === --- clang-tidy/utils/TypeTraits.cpp +++ clang-tidy/utils/TypeTraits.cpp @@ -41,7 +41,7 @@ llvm::Optional isExpensiveToCopy(QualType Type, const ASTContext &Context) { - if (Type->isDependentType()) + if (Type->isDependentType() || Type->isIncompleteType()) return llvm::None; return !Type.isTriviallyCopyableType(Context) && !classHasTrivialCopyAndDestroy(Type) && ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26195: Ignore incomplete types when determining whether they are expensive to copy
flx added a comment. In https://reviews.llvm.org/D26195#585917, @aaron.ballman wrote: > In https://reviews.llvm.org/D26195#585198, @flx wrote: > > > In https://reviews.llvm.org/D26195#585091, @aaron.ballman wrote: > > > > > In https://reviews.llvm.org/D26195#584958, @flx wrote: > > > > > > > In https://reviews.llvm.org/D26195#584730, @aaron.ballman wrote: > > > > > > > > > In https://reviews.llvm.org/D26195#584724, @flx wrote: > > > > > > > > > > > In https://reviews.llvm.org/D26195#584712, @aaron.ballman wrote: > > > > > > > > > > > > > Please add a test case with an incomplete type that would > > > > > > > exercise this code path, otherwise, LGTM. > > > > > > > > > > > > > > > > > > Hi Aaron, > > > > > > > > > > > > do you have any advise on how to add an incomplete type? When > > > > > > debugging this I had a compilation unit that failed to compile > > > > > > causing it, but I'm not sure this is a good way to add a test case. > > > > > > > > > > > > > > > A type like `class C;` is an incomplete type, as is `void`, so > > > > > perhaps you can find a check that would let such a construct call > > > > > through to `isExpensiveToCopy()`. > > > > > > > > > > > > Great, this works and I was able to see the check produce a false > > > > positive without the proposed change here, but the test code introduces > > > > a compile error now due to the incomplete type used in the function > > > > definition. Is there a way to suppress that? > > > > > > > > > Unlikely -- fixing the compile error likely makes the type not expensive > > > to copy by using a pointer (or reference). This may be tricky to test > > > because the times when you would call `isExpensiveToCopy()` is with types > > > that are going to be logically required to be complete. I am not certain > > > the compile error is actually a problem though -- I would imagine your > > > existing false-positives (that you mentioned in the patch summary) are > > > cases where there is a compile error *and* a clang-tidy diagnostic, so > > > the test may simply be "check that there's only a compile error and no > > > clang-tidy diagnostic where there used to be a false-positive one." > > > > > > That's exactly the case, my question here is how can I make the test > > succeed in the face of a compile error, i.e. by expecting the error as well? > > > Doesn't `// CHECK-MESSAGES: :[[@LINE-1]]:3: error: blah blah blah` work? Yes, that was needed. I also had to change the run command to add "-fix-errors" to still apply fixes in the face of compile errors. I also added you as reviewer, Aaron. https://reviews.llvm.org/D26195 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26195: Ignore incomplete types when determining whether they are expensive to copy
flx updated this revision to Diff 76934. https://reviews.llvm.org/D26195 Files: clang-tidy/utils/TypeTraits.cpp test/clang-tidy/performance-unnecessary-value-param.cpp Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 // CHECK-FIXES: #include @@ -237,3 +237,10 @@ ExpensiveToCopyType B; B = A; } + +// Ensure that incomplete types result in an error from the frontend and not a +// clang-tidy diagnostic about IncompleteType being expensive to copy. +struct IncompleteType; +void NegativeForIncompleteType(IncompleteType I) { + // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] +} Index: clang-tidy/utils/TypeTraits.cpp === --- clang-tidy/utils/TypeTraits.cpp +++ clang-tidy/utils/TypeTraits.cpp @@ -41,7 +41,7 @@ llvm::Optional isExpensiveToCopy(QualType Type, const ASTContext &Context) { - if (Type->isDependentType()) + if (Type->isDependentType() || Type->isIncompleteType()) return llvm::None; return !Type.isTriviallyCopyableType(Context) && !classHasTrivialCopyAndDestroy(Type) && Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 // CHECK-FIXES: #include @@ -237,3 +237,10 @@ ExpensiveToCopyType B; B = A; } + +// Ensure that incomplete types result in an error from the frontend and not a +// clang-tidy diagnostic about IncompleteType being expensive to copy. +struct IncompleteType; +void NegativeForIncompleteType(IncompleteType I) { + // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] +} Index: clang-tidy/utils/TypeTraits.cpp === --- clang-tidy/utils/TypeTraits.cpp +++ clang-tidy/utils/TypeTraits.cpp @@ -41,7 +41,7 @@ llvm::Optional isExpensiveToCopy(QualType Type, const ASTContext &Context) { - if (Type->isDependentType()) + if (Type->isDependentType() || Type->isIncompleteType()) return llvm::None; return !Type.isTriviallyCopyableType(Context) && !classHasTrivialCopyAndDestroy(Type) && ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] r286008 - [clang-tidy] Ignore incomplete types when determining whether they are expensive to copy
Author: flx Date: Fri Nov 4 15:29:22 2016 New Revision: 286008 URL: http://llvm.org/viewvc/llvm-project?rev=286008&view=rev Log: [clang-tidy] Ignore incomplete types when determining whether they are expensive to copy Summary: IsExpensiveToCopy can return false positives for incomplete types, so ignore them. All existing ClangTidy tests that depend on this function still pass as the types are complete. Reviewers: alexfh, aaron.ballman Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D26195 Modified: clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Modified: clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp?rev=286008&r1=286007&r2=286008&view=diff == --- clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp (original) +++ clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp Fri Nov 4 15:29:22 2016 @@ -41,7 +41,7 @@ bool hasDeletedCopyConstructor(QualType llvm::Optional isExpensiveToCopy(QualType Type, const ASTContext &Context) { - if (Type->isDependentType()) + if (Type->isDependentType() || Type->isIncompleteType()) return llvm::None; return !Type.isTriviallyCopyableType(Context) && !classHasTrivialCopyAndDestroy(Type) && Modified: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp?rev=286008&r1=286007&r2=286008&view=diff == --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp (original) +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Fri Nov 4 15:29:22 2016 @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 // CHECK-FIXES: #include @@ -237,3 +237,10 @@ void PositiveConstRefNotMoveAssignable(E ExpensiveToCopyType B; B = A; } + +// Ensure that incomplete types result in an error from the frontend and not a +// clang-tidy diagnostic about IncompleteType being expensive to copy. +struct IncompleteType; +void NegativeForIncompleteType(IncompleteType I) { + // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26195: Ignore incomplete types when determining whether they are expensive to copy
This revision was automatically updated to reflect the committed changes. Closed by commit rL286008: [clang-tidy] Ignore incomplete types when determining whether they are… (authored by flx). Changed prior to commit: https://reviews.llvm.org/D26195?vs=76934&id=76935#toc Repository: rL LLVM https://reviews.llvm.org/D26195 Files: clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Index: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp === --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 // CHECK-FIXES: #include @@ -237,3 +237,10 @@ ExpensiveToCopyType B; B = A; } + +// Ensure that incomplete types result in an error from the frontend and not a +// clang-tidy diagnostic about IncompleteType being expensive to copy. +struct IncompleteType; +void NegativeForIncompleteType(IncompleteType I) { + // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] +} Index: clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp === --- clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp +++ clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp @@ -41,7 +41,7 @@ llvm::Optional isExpensiveToCopy(QualType Type, const ASTContext &Context) { - if (Type->isDependentType()) + if (Type->isDependentType() || Type->isIncompleteType()) return llvm::None; return !Type.isTriviallyCopyableType(Context) && !classHasTrivialCopyAndDestroy(Type) && Index: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp === --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 // CHECK-FIXES: #include @@ -237,3 +237,10 @@ ExpensiveToCopyType B; B = A; } + +// Ensure that incomplete types result in an error from the frontend and not a +// clang-tidy diagnostic about IncompleteType being expensive to copy. +struct IncompleteType; +void NegativeForIncompleteType(IncompleteType I) { + // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] +} Index: clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp === --- clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp +++ clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp @@ -41,7 +41,7 @@ llvm::Optional isExpensiveToCopy(QualType Type, const ASTContext &Context) { - if (Type->isDependentType()) + if (Type->isDependentType() || Type->isIncompleteType()) return llvm::None; return !Type.isTriviallyCopyableType(Context) && !classHasTrivialCopyAndDestroy(Type) && ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] r286010 - [ClangTidy - performance-unnecessary-value-param] Only add "const" when current parameter is not already const qualified
Author: flx Date: Fri Nov 4 15:51:31 2016 New Revision: 286010 URL: http://llvm.org/viewvc/llvm-project?rev=286010&view=rev Log: [ClangTidy - performance-unnecessary-value-param] Only add "const" when current parameter is not already const qualified Reviewers: alexfh, sbenza, aaron.ballman Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D26207 Modified: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Modified: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp?rev=286010&r1=286009&r2=286010&view=diff == --- clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp (original) +++ clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp Fri Nov 4 15:51:31 2016 @@ -128,7 +128,10 @@ void UnnecessaryValueParamCheck::check(c const auto &CurrentParam = *FunctionDecl->getParamDecl(Index); Diag << utils::fixit::changeVarDeclToReference(CurrentParam, *Result.Context); -if (!IsConstQualified) +// The parameter of each declaration needs to be checked individually as to +// whether it is const or not as constness can differ between definition and +// declaration. +if (!CurrentParam.getType().getCanonicalType().isConstQualified()) Diag << utils::fixit::changeVarDeclToConst(CurrentParam); } } Modified: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp?rev=286010&r1=286009&r2=286010&view=diff == --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp (original) +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Fri Nov 4 15:51:31 2016 @@ -244,3 +244,19 @@ struct IncompleteType; void NegativeForIncompleteType(IncompleteType I) { // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] } + +// Case where parameter in declaration is already const-qualified but not in +// implementation. Make sure a second 'const' is not added to the declaration. +void PositiveConstDeclaration(const ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A); +void PositiveConstDeclaration(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) { +} + +void PositiveNonConstDeclaration(ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A); +void PositiveNonConstDeclaration(const ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A' + // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) { +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26207: [ClangTidy - performance-unnecessary-value-param] Only add "const" when current parameter is not already const qualified
This revision was automatically updated to reflect the committed changes. Closed by commit rL286010: [ClangTidy - performance-unnecessary-value-param] Only add "const" when current… (authored by flx). Changed prior to commit: https://reviews.llvm.org/D26207?vs=76877&id=76940#toc Repository: rL LLVM https://reviews.llvm.org/D26207 Files: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Index: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp === --- clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -128,7 +128,10 @@ const auto &CurrentParam = *FunctionDecl->getParamDecl(Index); Diag << utils::fixit::changeVarDeclToReference(CurrentParam, *Result.Context); -if (!IsConstQualified) +// The parameter of each declaration needs to be checked individually as to +// whether it is const or not as constness can differ between definition and +// declaration. +if (!CurrentParam.getType().getCanonicalType().isConstQualified()) Diag << utils::fixit::changeVarDeclToConst(CurrentParam); } } Index: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp === --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp @@ -244,3 +244,19 @@ void NegativeForIncompleteType(IncompleteType I) { // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] } + +// Case where parameter in declaration is already const-qualified but not in +// implementation. Make sure a second 'const' is not added to the declaration. +void PositiveConstDeclaration(const ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A); +void PositiveConstDeclaration(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) { +} + +void PositiveNonConstDeclaration(ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A); +void PositiveNonConstDeclaration(const ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A' + // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) { +} Index: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp === --- clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -128,7 +128,10 @@ const auto &CurrentParam = *FunctionDecl->getParamDecl(Index); Diag << utils::fixit::changeVarDeclToReference(CurrentParam, *Result.Context); -if (!IsConstQualified) +// The parameter of each declaration needs to be checked individually as to +// whether it is const or not as constness can differ between definition and +// declaration. +if (!CurrentParam.getType().getCanonicalType().isConstQualified()) Diag << utils::fixit::changeVarDeclToConst(CurrentParam); } } Index: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp === --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp @@ -244,3 +244,19 @@ void NegativeForIncompleteType(IncompleteType I) { // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] } + +// Case where parameter in declaration is already const-qualified but not in +// implementation. Make sure a second 'const' is not added to the declaration. +void PositiveConstDeclaration(const ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A); +void PositiveConstDeclaration(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) { +} + +void PositiveNonConstDeclaration(ExpensiveToCopyType A); +// CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A); +void PositiveNonConstDeclaration(const ExpensiveToCopyType A) { + // CHECK-MESSAGES: [
[PATCH] D26369: [ClangTidy] Move incomplete type test into separate test file
flx created this revision. flx added reviewers: alexfh, aaron.ballman, sbenza. flx added a subscriber: cfe-commits. flx set the repository for this revision to rL LLVM. Move in complete type test which does not compile into its own test file. Repository: rL LLVM https://reviews.llvm.org/D26369 Files: test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp test/clang-tidy/performance-unnecessary-value-param.cpp Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t // CHECK-FIXES: #include @@ -238,25 +238,11 @@ B = A; } -// Ensure that incomplete types result in an error from the frontend and not a -// clang-tidy diagnostic about IncompleteType being expensive to copy. -struct IncompleteType; -void NegativeForIncompleteType(IncompleteType I) { - // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] -} - // Case where parameter in declaration is already const-qualified but not in // implementation. Make sure a second 'const' is not added to the declaration. void PositiveConstDeclaration(const ExpensiveToCopyType A); // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A); void PositiveConstDeclaration(ExpensiveToCopyType A) { // CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) { } - -void PositiveNonConstDeclaration(ExpensiveToCopyType A); -// CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A); -void PositiveNonConstDeclaration(const ExpensiveToCopyType A) { - // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A' - // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) { -} Index: test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp === --- /dev/null +++ test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp @@ -0,0 +1,9 @@ +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 + +// Ensure that incomplete types result in an error from the frontend and not a +// clang-tidy diagnostic about IncompleteType being expensive to copy. +struct IncompleteType; +void NegativeForIncompleteType(IncompleteType I) { + // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] +} + Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t // CHECK-FIXES: #include @@ -238,25 +238,11 @@ B = A; } -// Ensure that incomplete types result in an error from the frontend and not a -// clang-tidy diagnostic about IncompleteType being expensive to copy. -struct IncompleteType; -void NegativeForIncompleteType(IncompleteType I) { - // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] -} - // Case where parameter in declaration is already const-qualified but not in // implementation. Make sure a second 'const' is not added to the declaration. void PositiveConstDeclaration(const ExpensiveToCopyType A); // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A); void PositiveConstDeclaration(ExpensiveToCopyType A) { // CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) { } - -void PositiveNonConstDeclaration(ExpensiveToCopyType A); -// CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A); -void PositiveNonConstDeclaration(const ExpensiveToCopyType A) { - // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A' - // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) { -} Index: test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp === --- /dev/null +++ test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp @@ -0,0 +1,9 @@ +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 + +// Ensure that
[PATCH] D26195: Ignore incomplete types when determining whether they are expensive to copy
flx added a comment. Comment at: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp:241 + +// Ensure that incomplete types result in an error from the frontend and not a +// clang-tidy diagnostic about IncompleteType being expensive to copy. alexfh wrote: > Please move this test to a separate test file and revert the RUN line here. Done in https://reviews.llvm.org/D26369. Repository: rL LLVM https://reviews.llvm.org/D26195 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26369: [ClangTidy] Move incomplete type test into separate test file
flx removed rL LLVM as the repository for this revision. flx updated this revision to Diff 77094. https://reviews.llvm.org/D26369 Files: test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp test/clang-tidy/performance-unnecessary-value-param.cpp Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t // CHECK-FIXES: #include @@ -238,13 +238,6 @@ B = A; } -// Ensure that incomplete types result in an error from the frontend and not a -// clang-tidy diagnostic about IncompleteType being expensive to copy. -struct IncompleteType; -void NegativeForIncompleteType(IncompleteType I) { - // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] -} - // Case where parameter in declaration is already const-qualified but not in // implementation. Make sure a second 'const' is not added to the declaration. void PositiveConstDeclaration(const ExpensiveToCopyType A); Index: test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp === --- /dev/null +++ test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp @@ -0,0 +1,9 @@ +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 + +// Ensure that incomplete types result in an error from the frontend and not a +// clang-tidy diagnostic about IncompleteType being expensive to copy. +struct IncompleteType; +void NegativeForIncompleteType(IncompleteType I) { + // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] +} + Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t // CHECK-FIXES: #include @@ -238,13 +238,6 @@ B = A; } -// Ensure that incomplete types result in an error from the frontend and not a -// clang-tidy diagnostic about IncompleteType being expensive to copy. -struct IncompleteType; -void NegativeForIncompleteType(IncompleteType I) { - // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] -} - // Case where parameter in declaration is already const-qualified but not in // implementation. Make sure a second 'const' is not added to the declaration. void PositiveConstDeclaration(const ExpensiveToCopyType A); Index: test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp === --- /dev/null +++ test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp @@ -0,0 +1,9 @@ +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 + +// Ensure that incomplete types result in an error from the frontend and not a +// clang-tidy diagnostic about IncompleteType being expensive to copy. +struct IncompleteType; +void NegativeForIncompleteType(IncompleteType I) { + // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] +} + ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26369: [ClangTidy] Move incomplete type test into separate test file
flx marked an inline comment as done. flx added inline comments. Comment at: test/clang-tidy/performance-unnecessary-value-param.cpp:257 - -void PositiveNonConstDeclaration(ExpensiveToCopyType A); -// CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A); aaron.ballman wrote: > Why are these tests being removed? They should not be removed. Restored them. https://reviews.llvm.org/D26369 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26369: [ClangTidy] Move incomplete type test into separate test file
flx marked an inline comment as done. flx added inline comments. Comment at: test/clang-tidy/performance-unnecessary-value-param.cpp:257 - -void PositiveNonConstDeclaration(ExpensiveToCopyType A); -// CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A); aaron.ballman wrote: > flx wrote: > > aaron.ballman wrote: > > > Why are these tests being removed? > > They should not be removed. Restored them. > Yay code review process! :-) Absolutely. Thanks for the quick review! https://reviews.llvm.org/D26369 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] r286155 - [clang-tidy] Move incomplete type test into separate test file
Author: flx Date: Mon Nov 7 15:45:58 2016 New Revision: 286155 URL: http://llvm.org/viewvc/llvm-project?rev=286155&view=rev Log: [clang-tidy] Move incomplete type test into separate test file Summary: Move in complete type test which does not compile into its own test file. Reviewers: alexfh, sbenza, aaron.ballman Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D26369 Added: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp Modified: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Added: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp?rev=286155&view=auto == --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp (added) +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp Mon Nov 7 15:45:58 2016 @@ -0,0 +1,9 @@ +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 + +// Ensure that incomplete types result in an error from the frontend and not a +// clang-tidy diagnostic about IncompleteType being expensive to copy. +struct IncompleteType; +void NegativeForIncompleteType(IncompleteType I) { + // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] +} + Modified: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp?rev=286155&r1=286154&r2=286155&view=diff == --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp (original) +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Mon Nov 7 15:45:58 2016 @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t // CHECK-FIXES: #include @@ -238,13 +238,6 @@ void PositiveConstRefNotMoveAssignable(E B = A; } -// Ensure that incomplete types result in an error from the frontend and not a -// clang-tidy diagnostic about IncompleteType being expensive to copy. -struct IncompleteType; -void NegativeForIncompleteType(IncompleteType I) { - // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] -} - // Case where parameter in declaration is already const-qualified but not in // implementation. Make sure a second 'const' is not added to the declaration. void PositiveConstDeclaration(const ExpensiveToCopyType A); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26369: [ClangTidy] Move incomplete type test into separate test file
This revision was automatically updated to reflect the committed changes. Closed by commit rL286155: [clang-tidy] Move incomplete type test into separate test file (authored by flx). Changed prior to commit: https://reviews.llvm.org/D26369?vs=77094&id=77095#toc Repository: rL LLVM https://reviews.llvm.org/D26369 Files: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Index: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp === --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp @@ -0,0 +1,9 @@ +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 + +// Ensure that incomplete types result in an error from the frontend and not a +// clang-tidy diagnostic about IncompleteType being expensive to copy. +struct IncompleteType; +void NegativeForIncompleteType(IncompleteType I) { + // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] +} + Index: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp === --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t // CHECK-FIXES: #include @@ -238,13 +238,6 @@ B = A; } -// Ensure that incomplete types result in an error from the frontend and not a -// clang-tidy diagnostic about IncompleteType being expensive to copy. -struct IncompleteType; -void NegativeForIncompleteType(IncompleteType I) { - // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] -} - // Case where parameter in declaration is already const-qualified but not in // implementation. Make sure a second 'const' is not added to the declaration. void PositiveConstDeclaration(const ExpensiveToCopyType A); Index: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp === --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp @@ -0,0 +1,9 @@ +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 + +// Ensure that incomplete types result in an error from the frontend and not a +// clang-tidy diagnostic about IncompleteType being expensive to copy. +struct IncompleteType; +void NegativeForIncompleteType(IncompleteType I) { + // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] +} + Index: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp === --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11 +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t // CHECK-FIXES: #include @@ -238,13 +238,6 @@ B = A; } -// Ensure that incomplete types result in an error from the frontend and not a -// clang-tidy diagnostic about IncompleteType being expensive to copy. -struct IncompleteType; -void NegativeForIncompleteType(IncompleteType I) { - // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error] -} - // Case where parameter in declaration is already const-qualified but not in // implementation. Make sure a second 'const' is not added to the declaration. void PositiveConstDeclaration(const ExpensiveToCopyType A); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26203: [ClangTidy - performance-unnecessary-value-param]: Do not issue fix for functions that are referenced outside of callExpr
flx removed rL LLVM as the repository for this revision. flx updated this revision to Diff 77343. https://reviews.llvm.org/D26203 Files: clang-tidy/performance/UnnecessaryValueParamCheck.cpp test/clang-tidy/performance-unnecessary-value-param.cpp Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -259,4 +259,21 @@ void PositiveNonConstDeclaration(const ExpensiveToCopyType A) { // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A' // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) { + +void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:75: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { +} + +void ReferenceFunctionOutsideOfCallExpr() { + void (*ptr)(ExpensiveToCopyType) = &PositiveOnlyMessageAsReferencedInCompilationUnit; +} + +void PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveMessageAndFixAsFunctionIsCalled(const ExpensiveToCopyType& A) { +} + +void ReferenceFunctionByCallingIt() { + PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType()); } Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp === --- clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -39,6 +39,14 @@ return true; } +bool isReferencedOutsideOfCallExpr(const FunctionDecl &Function, + ASTContext &Context) { + auto Matches = match(declRefExpr(to(functionDecl(equalsNode(&Function))), + unless(hasAncestor(callExpr(, + Context); + return !Matches.empty(); +} + } // namespace UnnecessaryValueParamCheck::UnnecessaryValueParamCheck( @@ -118,10 +126,14 @@ "invocation but only used as a const reference; " "consider making it a const reference") << paramNameOrIndex(Param->getName(), Index); - // Do not propose fixes in macros since we cannot place them correctly, or if - // function is virtual as it might break overrides. + // Do not propose fixes when: + // 1. the ParmVarDecl is in a macro, since we cannot place them correctly + // 2. the function is virtual as it might break overrides + // 3. the function is referenced outside of a call expression within the + //compilation unit as the signature change could introduce build errors. const auto *Method = llvm::dyn_cast(Function); - if (Param->getLocStart().isMacroID() || (Method && Method->isVirtual())) + if (Param->getLocStart().isMacroID() || (Method && Method->isVirtual()) || + isReferencedOutsideOfCallExpr(*Function, *Result.Context)) return; for (const auto *FunctionDecl = Function; FunctionDecl != nullptr; FunctionDecl = FunctionDecl->getPreviousDecl()) { Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -259,4 +259,21 @@ void PositiveNonConstDeclaration(const ExpensiveToCopyType A) { // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A' // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) { + +void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:75: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { +} + +void ReferenceFunctionOutsideOfCallExpr() { + void (*ptr)(ExpensiveToCopyType) = &PositiveOnlyMessageAsReferencedInCompilationUnit; +} + +void PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveMessageAndFixAsFunctionIsCalled(const ExpensiveToCopyType& A) { +} + +void ReferenceFunctionByCallingIt() { + PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType()); } Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp === --- clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -39,6 +39,14 @@ return true; } +bool isReferencedOutsideOfCallExpr(const FunctionDecl &Function, + ASTContext &Context) { + auto Matche
[PATCH] D26203: [ClangTidy - performance-unnecessary-value-param]: Do not issue fix for functions that are referenced outside of callExpr
flx marked an inline comment as done. flx added a comment. Thanks for the review! https://reviews.llvm.org/D26203 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26453: [clang-tidy] Remove duplicated check from move-constructor-init
flx added a comment. Is the modernize-pass-by-value check configurable in a way to only trigger when copied constructor arguments are not moved? I think our use case has been to have move-constructor-init check enabled to catch cases that can be optimized but not trigger on every constructor that uses const& instead of value + move, i.e. modernizing is not prescribed, but catching cases where the argument is already passed by value and making them faster is desirable. https://reviews.llvm.org/D26453 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] r286424 - [clang-tidy] Do not issue fix for functions that are referenced outside of callExpr
Author: flx Date: Wed Nov 9 19:28:22 2016 New Revision: 286424 URL: http://llvm.org/viewvc/llvm-project?rev=286424&view=rev Log: [clang-tidy] Do not issue fix for functions that are referenced outside of callExpr Summary: Suppress fixes for functions that are referenced within the compilation unit outside of a call expression as the signature change could break the code referencing the function. We still issue a warning in this case so that users can decide to manually change the function signature. Reviewers: alexfh, sbenza, aaron.ballman Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D26203 Modified: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Modified: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp?rev=286424&r1=286423&r2=286424&view=diff == --- clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp (original) +++ clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp Wed Nov 9 19:28:22 2016 @@ -39,6 +39,14 @@ bool isSubset(const S &SubsetCandidate, return true; } +bool isReferencedOutsideOfCallExpr(const FunctionDecl &Function, + ASTContext &Context) { + auto Matches = match(declRefExpr(to(functionDecl(equalsNode(&Function))), + unless(hasAncestor(callExpr(, + Context); + return !Matches.empty(); +} + } // namespace UnnecessaryValueParamCheck::UnnecessaryValueParamCheck( @@ -118,10 +126,14 @@ void UnnecessaryValueParamCheck::check(c "invocation but only used as a const reference; " "consider making it a const reference") << paramNameOrIndex(Param->getName(), Index); - // Do not propose fixes in macros since we cannot place them correctly, or if - // function is virtual as it might break overrides. + // Do not propose fixes when: + // 1. the ParmVarDecl is in a macro, since we cannot place them correctly + // 2. the function is virtual as it might break overrides + // 3. the function is referenced outside of a call expression within the + //compilation unit as the signature change could introduce build errors. const auto *Method = llvm::dyn_cast(Function); - if (Param->getLocStart().isMacroID() || (Method && Method->isVirtual())) + if (Param->getLocStart().isMacroID() || (Method && Method->isVirtual()) || + isReferencedOutsideOfCallExpr(*Function, *Result.Context)) return; for (const auto *FunctionDecl = Function; FunctionDecl != nullptr; FunctionDecl = FunctionDecl->getPreviousDecl()) { Modified: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp?rev=286424&r1=286423&r2=286424&view=diff == --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp (original) +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Wed Nov 9 19:28:22 2016 @@ -253,3 +253,21 @@ void PositiveNonConstDeclaration(const E // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A' // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) { } + +void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:75: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { +} + +void ReferenceFunctionOutsideOfCallExpr() { + void (*ptr)(ExpensiveToCopyType) = &PositiveOnlyMessageAsReferencedInCompilationUnit; +} + +void PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveMessageAndFixAsFunctionIsCalled(const ExpensiveToCopyType& A) { +} + +void ReferenceFunctionByCallingIt() { + PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType()); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26203: [ClangTidy - performance-unnecessary-value-param]: Do not issue fix for functions that are referenced outside of callExpr
This revision was automatically updated to reflect the committed changes. Closed by commit rL286424: [clang-tidy] Do not issue fix for functions that are referenced outside of… (authored by flx). Changed prior to commit: https://reviews.llvm.org/D26203?vs=77343&id=77430#toc Repository: rL LLVM https://reviews.llvm.org/D26203 Files: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp Index: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp === --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp @@ -253,3 +253,21 @@ // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A' // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) { } + +void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:75: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { +} + +void ReferenceFunctionOutsideOfCallExpr() { + void (*ptr)(ExpensiveToCopyType) = &PositiveOnlyMessageAsReferencedInCompilationUnit; +} + +void PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveMessageAndFixAsFunctionIsCalled(const ExpensiveToCopyType& A) { +} + +void ReferenceFunctionByCallingIt() { + PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType()); +} Index: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp === --- clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -39,6 +39,14 @@ return true; } +bool isReferencedOutsideOfCallExpr(const FunctionDecl &Function, + ASTContext &Context) { + auto Matches = match(declRefExpr(to(functionDecl(equalsNode(&Function))), + unless(hasAncestor(callExpr(, + Context); + return !Matches.empty(); +} + } // namespace UnnecessaryValueParamCheck::UnnecessaryValueParamCheck( @@ -118,10 +126,14 @@ "invocation but only used as a const reference; " "consider making it a const reference") << paramNameOrIndex(Param->getName(), Index); - // Do not propose fixes in macros since we cannot place them correctly, or if - // function is virtual as it might break overrides. + // Do not propose fixes when: + // 1. the ParmVarDecl is in a macro, since we cannot place them correctly + // 2. the function is virtual as it might break overrides + // 3. the function is referenced outside of a call expression within the + //compilation unit as the signature change could introduce build errors. const auto *Method = llvm::dyn_cast(Function); - if (Param->getLocStart().isMacroID() || (Method && Method->isVirtual())) + if (Param->getLocStart().isMacroID() || (Method && Method->isVirtual()) || + isReferencedOutsideOfCallExpr(*Function, *Result.Context)) return; for (const auto *FunctionDecl = Function; FunctionDecl != nullptr; FunctionDecl = FunctionDecl->getPreviousDecl()) { Index: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp === --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp @@ -253,3 +253,21 @@ // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A' // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) { } + +void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:75: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { +} + +void ReferenceFunctionOutsideOfCallExpr() { + void (*ptr)(ExpensiveToCopyType) = &PositiveOnlyMessageAsReferencedInCompilationUnit; +} + +void PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType A) { + // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'A' is copied + // CHECK-FIXES: void PositiveMessageAndFixAsFunctionIsCalled(const ExpensiveToCopyType& A) { +} + +void ReferenceFunctionByCallingIt() { + PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType()); +} Index: clang-tools-extra/trunk/clang-tidy/performance/UnnecessaryValuePar
[PATCH] D26453: [clang-tidy] Remove duplicated check from move-constructor-init
flx added a comment. In https://reviews.llvm.org/D26453#590720, @malcolm.parsons wrote: > Add ValuesOnly option to modernize-pass-by-value. Thanks for doing this. Alex, would this work for us? https://reviews.llvm.org/D26453 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D12839: Extend MoveConstructorInitCheck to also flag constructor arguments passed by value and can be moved assigned to fields.
flx created this revision. flx added reviewers: alexfh, sbenza, aaron.ballman. flx added a subscriber: cfe-commits. Add matcher that identifies arguments that are passed by value, are copy assigned to a class field and have a non-deleted move constructor. If the type is also expensive to copy issue diagnostic message that the field can be move constructed. http://reviews.llvm.org/D12839 Files: clang-tidy/misc/MoveConstructorInitCheck.cpp clang-tidy/misc/MoveConstructorInitCheck.h test/clang-tidy/misc-move-constructor-init.cpp Index: test/clang-tidy/misc-move-constructor-init.cpp === --- test/clang-tidy/misc-move-constructor-init.cpp +++ test/clang-tidy/misc-move-constructor-init.cpp @@ -76,3 +76,60 @@ B Mem; N(N &&RHS) : Mem(move(RHS.Mem)) {} }; + + +struct Movable { + Movable(Movable&&) = default; + Movable(const Movable&) = default; + Movable& operator =(const Movable&) = default; + ~Movable() {} +}; + +struct TriviallyCopyable { + TriviallyCopyable() = default; + TriviallyCopyable(TriviallyCopyable&&) = default; + TriviallyCopyable(const TriviallyCopyable&) = default; +}; + +struct Positive { + Positive(Movable M) : M_(M) {} + // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value parameter can be moved to avoid copy. [misc-move-constructor-init] + Movable M_; +}; + +struct NegativeMultipleInitializerReferences { + NegativeMultipleInitializerReferences(Movable M) : M_(M), n_(M) {} + Movable M_; + Movable n_; +}; + +struct NegativeReferencedInConstructorBody { + NegativeReferencedInConstructorBody(Movable M) : M_(M) { +M_ = M; + } + Movable M_; +}; + +struct NegativeParamTriviallyCopyable { + NegativeParamTriviallyCopyable(TriviallyCopyable T) : T_(T) {} + TriviallyCopyable T_; +}; + +struct NegativeNotPassedByValue { + NegativeNotPassedByValue(const Movable& M) : M_(M) {} + NegativeNotPassedByValue(const Movable M) : M_(M) {} + NegativeNotPassedByValue(Movable& M) : M_(M) {} + NegativeNotPassedByValue(Movable* M) : M_(*M) {} + NegativeNotPassedByValue(const Movable* M) : M_(*M) {} + Movable M_; +}; + +struct Immovable { + Immovable(const Immovable&) = default; + Immovable(Immovable&&) = delete; +}; + +struct NegativeImmovableParameter { + NegativeImmovableParameter(Immovable I) : I_(I) {} + Immovable I_; +}; Index: clang-tidy/misc/MoveConstructorInitCheck.h === --- clang-tidy/misc/MoveConstructorInitCheck.h +++ clang-tidy/misc/MoveConstructorInitCheck.h @@ -18,12 +18,21 @@ /// The check flags user-defined move constructors that have a ctor-initializer /// initializing a member or base class through a copy constructor instead of a /// move constructor. +/// It also flags constructor arguments that are passed by value, have a +/// non-deleted move-constructor and are assigned to a class field by copy +/// construction. class MoveConstructorInitCheck : public ClangTidyCheck { public: MoveConstructorInitCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context) {} void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + void + handleMoveConstructor(const ast_matchers::MatchFinder::MatchResult &Result); + void + handleParamNotMoved(const ast_matchers::MatchFinder::MatchResult &Result); }; } // namespace tidy Index: clang-tidy/misc/MoveConstructorInitCheck.cpp === --- clang-tidy/misc/MoveConstructorInitCheck.cpp +++ clang-tidy/misc/MoveConstructorInitCheck.cpp @@ -16,6 +16,48 @@ namespace clang { namespace tidy { +namespace { + +bool classHasTrivialCopyAndDestroy(QualType Type) { + auto *Record = Type->getAsCXXRecordDecl(); + return Record && Record->hasDefinition() && + !Record->hasNonTrivialCopyConstructor() && + !Record->hasNonTrivialDestructor(); +} + +AST_MATCHER(QualType, isExpensiveToCopy) { + // We can't reason about dependent types. Ignore them. + // If there's a template instantiation that results in what we consider + // excessive copying, we'll warn on them. + if (Node->isDependentType()) { +return false; + } + // Ignore trivially copyable types. + if (Node->isScalarType() || + Node.isTriviallyCopyableType(Finder->getASTContext()) || + classHasTrivialCopyAndDestroy(Node)) { +return false; + } + return true; +} + +int parmVarDeclRefExprOccurences(const ParmVarDecl &MovableParam, + const CXXConstructorDecl &ConstructorDecl, + ASTContext &Context) { + int Occurrences = 0; + auto AllDeclRefs = + findAll(declRefExpr(to(parmVarDecl(equalsNode(&MovableParam); + auto Matches = match(AllDeclRefs, *ConstructorDecl.getBody(), Context); + Occurrences += Matches.size(); + for (const auto* Initializer : C
Re: [PATCH] D12839: Extend MoveConstructorInitCheck to also flag constructor arguments passed by value and can be moved assigned to fields.
flx updated this revision to Diff 35204. flx marked 10 inline comments as done. http://reviews.llvm.org/D12839 Files: clang-tidy/misc/MoveConstructorInitCheck.cpp clang-tidy/misc/MoveConstructorInitCheck.h clang-tidy/utils/CMakeLists.txt clang-tidy/utils/Matchers.h clang-tidy/utils/TypeTraits.cpp clang-tidy/utils/TypeTraits.h docs/clang-tidy/checks/misc-move-constructor-init.rst test/clang-tidy/misc-move-constructor-init.cpp Index: test/clang-tidy/misc-move-constructor-init.cpp === --- test/clang-tidy/misc-move-constructor-init.cpp +++ test/clang-tidy/misc-move-constructor-init.cpp @@ -76,3 +76,59 @@ B Mem; N(N &&RHS) : Mem(move(RHS.Mem)) {} }; + +struct Movable { + Movable(Movable &&) = default; + Movable(const Movable &) = default; + Movable &operator=(const Movable &) = default; + ~Movable() {} +}; + +struct TriviallyCopyable { + TriviallyCopyable() = default; + TriviallyCopyable(TriviallyCopyable &&) = default; + TriviallyCopyable(const TriviallyCopyable &) = default; +}; + +struct Positive { + Positive(Movable M) : M_(M) {} + // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument can be moved to avoid copy [misc-move-constructor-init] + Movable M_; +}; + +struct NegativeMultipleInitializerReferences { + NegativeMultipleInitializerReferences(Movable M) : M_(M), n_(M) {} + Movable M_; + Movable n_; +}; + +struct NegativeReferencedInConstructorBody { + NegativeReferencedInConstructorBody(Movable M) : M_(M) { M_ = M; } + Movable M_; +}; + +struct NegativeParamTriviallyCopyable { + NegativeParamTriviallyCopyable(TriviallyCopyable T) : T_(T) {} + NegativeParamTriviallyCopyable(int I) : I_(I) {} + TriviallyCopyable T_; + int I_; +}; + +struct NegativeNotPassedByValue { + NegativeNotPassedByValue(const Movable &M) : M_(M) {} + NegativeNotPassedByValue(const Movable M) : M_(M) {} + NegativeNotPassedByValue(Movable &M) : M_(M) {} + NegativeNotPassedByValue(Movable *M) : M_(*M) {} + NegativeNotPassedByValue(const Movable *M) : M_(*M) {} + Movable M_; +}; + +struct Immovable { + Immovable(const Immovable &) = default; + Immovable(Immovable &&) = delete; +}; + +struct NegativeImmovableParameter { + NegativeImmovableParameter(Immovable I) : I_(I) {} + Immovable I_; +}; Index: docs/clang-tidy/checks/misc-move-constructor-init.rst === --- docs/clang-tidy/checks/misc-move-constructor-init.rst +++ docs/clang-tidy/checks/misc-move-constructor-init.rst @@ -5,3 +5,6 @@ The check flags user-defined move constructors that have a ctor-initializer initializing a member or base class through a copy constructor instead of a move constructor. + +It also flags constructor arguments that are passed by value, have a non-deleted +move-constructor and are assigned to a class field by copy construction. Index: clang-tidy/utils/TypeTraits.h === --- clang-tidy/utils/TypeTraits.h +++ clang-tidy/utils/TypeTraits.h @@ -0,0 +1,31 @@ +//===--- TypeTraits.h - clang-tidy---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_TYPETRAITS_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_TYPETRAITS_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" + +namespace clang { +namespace tidy { +namespace type_traits { + +/// Returns true if \c Type is defined has no non-trivial copy-constructor or +/// destructor. +bool classHasTrivialCopyAndDestroy(QualType Type); + +// \brief Returns true If \c Type is expensive to copy. +bool isExpensiveToCopy(QualType Type, ASTContext &Context); + +} // type_traits +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_TYPETRAITS_H Index: clang-tidy/utils/TypeTraits.cpp === --- clang-tidy/utils/TypeTraits.cpp +++ clang-tidy/utils/TypeTraits.cpp @@ -0,0 +1,38 @@ +//===--- TypeTraits.cpp - clang-tidy---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#include "TypeTraits.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" + +namespace clang { +namespace tidy { +namespace type_traits { + +bool classHasTrivialCopyAndDestroy(QualType Type) { + auto *Record = Type->getAsCXXRecordDecl(); + return Record && Record->hasDefinition() && + !Record->hasNonTrivialCopyCons
Re: [PATCH] D12839: Extend MoveConstructorInitCheck to also flag constructor arguments passed by value and can be moved assigned to fields.
flx added inline comments. Comment at: clang-tidy/misc/MoveConstructorInitCheck.cpp:38 @@ +37,3 @@ + Node.isTriviallyCopyableType(Finder->getASTContext()) || + classHasTrivialCopyAndDestroy(Node)) { +return false; aaron.ballman wrote: > Why do you need classHasTrivialCopyAndDestroy() when you're already checking > if it's a trivially copyable type? We also want to catch types that have non-trivial destructors which would be executed when the temporary copy goes out of scope. Comment at: clang-tidy/misc/MoveConstructorInitCheck.cpp:44 @@ +43,3 @@ + +int parmVarDeclRefExprOccurences(const ParmVarDecl &MovableParam, + const CXXConstructorDecl &ConstructorDecl, aaron.ballman wrote: > Should return unsigned, please. Done. Is this an llvm convention? Comment at: clang-tidy/misc/MoveConstructorInitCheck.cpp:120 @@ +119,3 @@ + } + diag(InitArg->getLocStart(), "value parameter can be moved to avoid copy."); +} alexfh wrote: > alexfh wrote: > > aaron.ballman wrote: > > > Perhaps: "argument can be moved to avoid a copy" instead? > > nit: Please remove the trailing period. > Does anything stop us from suggesting fixes here (inserting "std::move()" > around the argument and #include , if it's no there yet)? How would I tread in the IncludeOrder style (i.e. Google vs LLVM)? Should this be a flag shared by all of ClangTidy or specific to this check? Comment at: test/clang-tidy/misc-move-constructor-init.cpp:85 @@ +84,3 @@ + Movable& operator =(const Movable&) = default; + ~Movable() {} +}; aaron.ballman wrote: > Why not = default? We need to make the type non-trivially copyable by our definition above. Comment at: test/clang-tidy/misc-move-constructor-init.cpp:113 @@ +112,3 @@ + +struct NegativeParamTriviallyCopyable { + NegativeParamTriviallyCopyable(TriviallyCopyable T) : T_(T) {} aaron.ballman wrote: > Should also have a test for scalars Added. http://reviews.llvm.org/D12839 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D12839: Extend MoveConstructorInitCheck to also flag constructor arguments passed by value and can be moved assigned to fields.
flx updated this revision to Diff 35826. flx marked 7 inline comments as done. flx added a comment. I changed the check to also produce a fix that wraps the argument in std::move(). When I modified the test include -isystem %S/Inputs/Headers it broke and only produces warnings but no fixes anymore. Is there a subtle difference in how tests with includes need to be invoked? http://reviews.llvm.org/D12839 Files: clang-tidy/misc/MoveConstructorInitCheck.cpp clang-tidy/misc/MoveConstructorInitCheck.h clang-tidy/modernize/PassByValueCheck.cpp clang-tidy/modernize/ReplaceAutoPtrCheck.cpp clang-tidy/utils/CMakeLists.txt clang-tidy/utils/IncludeSorter.cpp clang-tidy/utils/IncludeSorter.h clang-tidy/utils/Matchers.h clang-tidy/utils/TypeTraits.cpp clang-tidy/utils/TypeTraits.h docs/clang-tidy/checks/misc-move-constructor-init.rst test/clang-tidy/misc-move-constructor-init.cpp Index: test/clang-tidy/misc-move-constructor-init.cpp === --- test/clang-tidy/misc-move-constructor-init.cpp +++ test/clang-tidy/misc-move-constructor-init.cpp @@ -1,4 +1,8 @@ -// RUN: %python %S/check_clang_tidy.py %s misc-move-constructor-init %t +// RUN: %python %S/check_clang_tidy.py %s misc-move-constructor-init %t -- -isystem %S/Inputs/Headers + +#include "j.h" +#include +// CHECK-FIXES: #include template struct remove_reference {typedef T type;}; template struct remove_reference {typedef T type;}; @@ -76,3 +80,66 @@ B Mem; N(N &&RHS) : Mem(move(RHS.Mem)) {} }; + +struct Movable { + Movable(Movable &&) = default; + Movable(const Movable &) = default; + Movable &operator=(const Movable &) = default; + ~Movable() {} +}; + +struct TriviallyCopyable { + TriviallyCopyable() = default; + TriviallyCopyable(TriviallyCopyable &&) = default; + TriviallyCopyable(const TriviallyCopyable &) = default; +}; + +struct Positive { + Positive(Movable M) : M_(M) {} + // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument can be moved to avoid copy [misc-move-constructor-init] + // CHECK-FIXES: Positive(Movable M) : M_(std::move(M)) {} + Movable M_; +}; + +struct NegativeMultipleInitializerReferences { + NegativeMultipleInitializerReferences(Movable M) : M_(M), n_(M) {} + Movable M_; + Movable n_; +}; + +struct NegativeReferencedInConstructorBody { + NegativeReferencedInConstructorBody(Movable M) : M_(M) { M_ = M; } + Movable M_; +}; + +struct NegativeParamTriviallyCopyable { + NegativeParamTriviallyCopyable(TriviallyCopyable T) : T_(T) {} + NegativeParamTriviallyCopyable(int I) : I_(I) {} + + TriviallyCopyable T_; + int I_; +}; + +template struct NegativeDependentType { + NegativeDependentType(T Value) : T_(Value) {} + T T_; +}; + +struct NegativeNotPassedByValue { + NegativeNotPassedByValue(const Movable &M) : M_(M) {} + NegativeNotPassedByValue(const Movable M) : M_(M) {} + NegativeNotPassedByValue(Movable &M) : M_(M) {} + NegativeNotPassedByValue(Movable *M) : M_(*M) {} + NegativeNotPassedByValue(const Movable *M) : M_(*M) {} + Movable M_; +}; + +struct Immovable { + Immovable(const Immovable &) = default; + Immovable(Immovable &&) = delete; +}; + +struct NegativeImmovableParameter { + NegativeImmovableParameter(Immovable I) : I_(I) {} + Immovable I_; +}; Index: docs/clang-tidy/checks/misc-move-constructor-init.rst === --- docs/clang-tidy/checks/misc-move-constructor-init.rst +++ docs/clang-tidy/checks/misc-move-constructor-init.rst @@ -5,3 +5,6 @@ The check flags user-defined move constructors that have a ctor-initializer initializing a member or base class through a copy constructor instead of a move constructor. + +It also flags constructor arguments that are passed by value, have a non-deleted +move-constructor and are assigned to a class field by copy construction. Index: clang-tidy/utils/TypeTraits.h === --- clang-tidy/utils/TypeTraits.h +++ clang-tidy/utils/TypeTraits.h @@ -0,0 +1,27 @@ +//===--- TypeTraits.h - clang-tidy---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_TYPETRAITS_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_TYPETRAITS_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" + +namespace clang { +namespace tidy { +namespace type_traits { + +// \brief Returns true If \c Type is expensive to copy. +bool isExpensiveToCopy(QualType Type, ASTContext &Context); + +} // type_traits +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_TYPETRAITS_H Index: clang-tidy/utils/TypeTraits.cpp
Re: [PATCH] D12839: Extend MoveConstructorInitCheck to also flag constructor arguments passed by value and can be moved assigned to fields.
flx updated this revision to Diff 36049. flx marked 3 inline comments as done. flx added a comment. I had to convert the line endings of mis-move-constructor-init.cpp to unix style otherwise the test would not correctly work. This took a long time to debug since the checks failed complaining that error messages that look exactly the same didn't match. Let me know if this needs to be converted back to DOS line endings, but it looks like most other tests have unix line endings. http://reviews.llvm.org/D12839 Files: clang-tidy/misc/MoveConstructorInitCheck.cpp clang-tidy/misc/MoveConstructorInitCheck.h clang-tidy/modernize/PassByValueCheck.cpp clang-tidy/modernize/ReplaceAutoPtrCheck.cpp clang-tidy/utils/CMakeLists.txt clang-tidy/utils/IncludeSorter.cpp clang-tidy/utils/IncludeSorter.h clang-tidy/utils/Matchers.h clang-tidy/utils/TypeTraits.cpp clang-tidy/utils/TypeTraits.h docs/clang-tidy/checks/misc-move-constructor-init.rst test/clang-tidy/misc-move-constructor-init.cpp Index: test/clang-tidy/misc-move-constructor-init.cpp === --- test/clang-tidy/misc-move-constructor-init.cpp +++ test/clang-tidy/misc-move-constructor-init.cpp @@ -1,78 +1,145 @@ -// RUN: %python %S/check_clang_tidy.py %s misc-move-constructor-init %t - -template struct remove_reference {typedef T type;}; -template struct remove_reference {typedef T type;}; -template struct remove_reference {typedef T type;}; - -template -typename remove_reference::type&& move(T&& arg) { - return static_cast::type&&>(arg); -} - -struct C { - C() = default; - C(const C&) = default; -}; - -struct B { - B() {} - B(const B&) {} - B(B &&) {} -}; - -struct D : B { - D() : B() {} - D(const D &RHS) : B(RHS) {} - // CHECK-MESSAGES: :[[@LINE+3]]:16: warning: move constructor initializes base class by calling a copy constructor [misc-move-constructor-init] - // CHECK-MESSAGES: 19:3: note: copy constructor being called - // CHECK-MESSAGES: 20:3: note: candidate move constructor here - D(D &&RHS) : B(RHS) {} -}; - -struct E : B { - E() : B() {} - E(const E &RHS) : B(RHS) {} - E(E &&RHS) : B(move(RHS)) {} // ok -}; - -struct F { - C M; - - F(F &&) : M(C()) {} // ok -}; - -struct G { - G() = default; - G(const G&) = default; - G(G&&) = delete; -}; - -struct H : G { - H() = default; - H(const H&) = default; - H(H &&RHS) : G(RHS) {} // ok -}; - -struct I { - I(const I &) = default; // suppresses move constructor creation -}; - -struct J : I { - J(J &&RHS) : I(RHS) {} // ok -}; - -struct K {}; // Has implicit copy and move constructors, is trivially copyable -struct L : K { - L(L &&RHS) : K(RHS) {} // ok -}; - -struct M { - B Mem; - // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: move constructor initializes class member by calling a copy constructor [misc-move-constructor-init] - M(M &&RHS) : Mem(RHS.Mem) {} -}; - -struct N { - B Mem; - N(N &&RHS) : Mem(move(RHS.Mem)) {} -}; +// RUN: %python %S/check_clang_tidy.py %s misc-move-constructor-init %t -- -std=c++11 -isystem %S/Inputs/Headers + +#include + +// CHECK-FIXES: #include + +template struct remove_reference {typedef T type;}; +template struct remove_reference {typedef T type;}; +template struct remove_reference {typedef T type;}; + +template +typename remove_reference::type&& move(T&& arg) { + return static_cast::type&&>(arg); +} + +struct C { + C() = default; + C(const C&) = default; +}; + +struct B { + B() {} + B(const B&) {} + B(B &&) {} +}; + +struct D : B { + D() : B() {} + D(const D &RHS) : B(RHS) {} + // CHECK-MESSAGES: :[[@LINE+3]]:16: warning: move constructor initializes base class by calling a copy constructor [misc-move-constructor-init] + // CHECK-MESSAGES: 23:3: note: copy constructor being called + // CHECK-MESSAGES: 24:3: note: candidate move constructor here + D(D &&RHS) : B(RHS) {} +}; + +struct E : B { + E() : B() {} + E(const E &RHS) : B(RHS) {} + E(E &&RHS) : B(move(RHS)) {} // ok +}; + +struct F { + C M; + + F(F &&) : M(C()) {} // ok +}; + +struct G { + G() = default; + G(const G&) = default; + G(G&&) = delete; +}; + +struct H : G { + H() = default; + H(const H&) = default; + H(H &&RHS) : G(RHS) {} // ok +}; + +struct I { + I(const I &) = default; // suppresses move constructor creation +}; + +struct J : I { + J(J &&RHS) : I(RHS) {} // ok +}; + +struct K {}; // Has implicit copy and move constructors, is trivially copyable +struct L : K { + L(L &&RHS) : K(RHS) {} // ok +}; + +struct M { + B Mem; + // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: move constructor initializes class member by calling a copy constructor [misc-move-constructor-init] + M(M &&RHS) : Mem(RHS.Mem) {} +}; + +struct N { + B Mem; + N(N &&RHS) : Mem(move(RHS.Mem)) {} +}; + +struct Movable { + Movable(Movable &&) = default; + Movable(const Movable &) = default; + Movable &operator=(const Movable &) = default; + ~Movable() {} +}; + +struct TriviallyCopya
Re: [PATCH] D12839: Extend MoveConstructorInitCheck to also flag constructor arguments passed by value and can be moved assigned to fields.
flx updated this revision to Diff 36151. flx marked an inline comment as done. flx added a comment. Thanks for catching the last issues, Alex. I rebuilt and ran all tests using llvm-lit -v . for clang-tidy and they pass. http://reviews.llvm.org/D12839 Files: clang-tidy/misc/MoveConstructorInitCheck.cpp clang-tidy/misc/MoveConstructorInitCheck.h clang-tidy/modernize/PassByValueCheck.cpp clang-tidy/modernize/ReplaceAutoPtrCheck.cpp clang-tidy/utils/CMakeLists.txt clang-tidy/utils/IncludeSorter.cpp clang-tidy/utils/IncludeSorter.h clang-tidy/utils/Matchers.h clang-tidy/utils/TypeTraits.cpp clang-tidy/utils/TypeTraits.h docs/clang-tidy/checks/misc-move-constructor-init.rst test/clang-tidy/misc-move-constructor-init.cpp Index: test/clang-tidy/misc-move-constructor-init.cpp === --- test/clang-tidy/misc-move-constructor-init.cpp +++ test/clang-tidy/misc-move-constructor-init.cpp @@ -1,78 +1,145 @@ -// RUN: %python %S/check_clang_tidy.py %s misc-move-constructor-init %t - -template struct remove_reference {typedef T type;}; -template struct remove_reference {typedef T type;}; -template struct remove_reference {typedef T type;}; - -template -typename remove_reference::type&& move(T&& arg) { - return static_cast::type&&>(arg); -} - -struct C { - C() = default; - C(const C&) = default; -}; - -struct B { - B() {} - B(const B&) {} - B(B &&) {} -}; - -struct D : B { - D() : B() {} - D(const D &RHS) : B(RHS) {} - // CHECK-MESSAGES: :[[@LINE+3]]:16: warning: move constructor initializes base class by calling a copy constructor [misc-move-constructor-init] - // CHECK-MESSAGES: 19:3: note: copy constructor being called - // CHECK-MESSAGES: 20:3: note: candidate move constructor here - D(D &&RHS) : B(RHS) {} -}; - -struct E : B { - E() : B() {} - E(const E &RHS) : B(RHS) {} - E(E &&RHS) : B(move(RHS)) {} // ok -}; - -struct F { - C M; - - F(F &&) : M(C()) {} // ok -}; - -struct G { - G() = default; - G(const G&) = default; - G(G&&) = delete; -}; - -struct H : G { - H() = default; - H(const H&) = default; - H(H &&RHS) : G(RHS) {} // ok -}; - -struct I { - I(const I &) = default; // suppresses move constructor creation -}; - -struct J : I { - J(J &&RHS) : I(RHS) {} // ok -}; - -struct K {}; // Has implicit copy and move constructors, is trivially copyable -struct L : K { - L(L &&RHS) : K(RHS) {} // ok -}; - -struct M { - B Mem; - // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: move constructor initializes class member by calling a copy constructor [misc-move-constructor-init] - M(M &&RHS) : Mem(RHS.Mem) {} -}; - -struct N { - B Mem; - N(N &&RHS) : Mem(move(RHS.Mem)) {} -}; +// RUN: %python %S/check_clang_tidy.py %s misc-move-constructor-init %t -- -std=c++11 -isystem %S/Inputs/Headers + +#include + +// CHECK-FIXES: #include + +template struct remove_reference {typedef T type;}; +template struct remove_reference {typedef T type;}; +template struct remove_reference {typedef T type;}; + +template +typename remove_reference::type&& move(T&& arg) { + return static_cast::type&&>(arg); +} + +struct C { + C() = default; + C(const C&) = default; +}; + +struct B { + B() {} + B(const B&) {} + B(B &&) {} +}; + +struct D : B { + D() : B() {} + D(const D &RHS) : B(RHS) {} + // CHECK-MESSAGES: :[[@LINE+3]]:16: warning: move constructor initializes base class by calling a copy constructor [misc-move-constructor-init] + // CHECK-MESSAGES: 23:3: note: copy constructor being called + // CHECK-MESSAGES: 24:3: note: candidate move constructor here + D(D &&RHS) : B(RHS) {} +}; + +struct E : B { + E() : B() {} + E(const E &RHS) : B(RHS) {} + E(E &&RHS) : B(move(RHS)) {} // ok +}; + +struct F { + C M; + + F(F &&) : M(C()) {} // ok +}; + +struct G { + G() = default; + G(const G&) = default; + G(G&&) = delete; +}; + +struct H : G { + H() = default; + H(const H&) = default; + H(H &&RHS) : G(RHS) {} // ok +}; + +struct I { + I(const I &) = default; // suppresses move constructor creation +}; + +struct J : I { + J(J &&RHS) : I(RHS) {} // ok +}; + +struct K {}; // Has implicit copy and move constructors, is trivially copyable +struct L : K { + L(L &&RHS) : K(RHS) {} // ok +}; + +struct M { + B Mem; + // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: move constructor initializes class member by calling a copy constructor [misc-move-constructor-init] + M(M &&RHS) : Mem(RHS.Mem) {} +}; + +struct N { + B Mem; + N(N &&RHS) : Mem(move(RHS.Mem)) {} +}; + +struct Movable { + Movable(Movable &&) = default; + Movable(const Movable &) = default; + Movable &operator=(const Movable &) = default; + ~Movable() {} +}; + +struct TriviallyCopyable { + TriviallyCopyable() = default; + TriviallyCopyable(TriviallyCopyable &&) = default; + TriviallyCopyable(const TriviallyCopyable &) = default; +}; + +struct Positive { + Positive(Movable M) : M_(M) {} + // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value
Re: [PATCH] D12839: Extend MoveConstructorInitCheck to also flag constructor arguments passed by value and can be moved assigned to fields.
flx updated this revision to Diff 36433. flx added a comment. Updated patch to new cxx* matcher variants. http://reviews.llvm.org/D12839 Files: clang-tidy/misc/MoveConstructorInitCheck.cpp clang-tidy/misc/MoveConstructorInitCheck.h clang-tidy/modernize/PassByValueCheck.cpp clang-tidy/modernize/ReplaceAutoPtrCheck.cpp clang-tidy/utils/CMakeLists.txt clang-tidy/utils/IncludeSorter.cpp clang-tidy/utils/IncludeSorter.h clang-tidy/utils/Matchers.h clang-tidy/utils/TypeTraits.cpp clang-tidy/utils/TypeTraits.h docs/clang-tidy/checks/misc-move-constructor-init.rst test/clang-tidy/misc-move-constructor-init.cpp Index: test/clang-tidy/misc-move-constructor-init.cpp === --- test/clang-tidy/misc-move-constructor-init.cpp +++ test/clang-tidy/misc-move-constructor-init.cpp @@ -1,78 +1,145 @@ -// RUN: %python %S/check_clang_tidy.py %s misc-move-constructor-init %t - -template struct remove_reference {typedef T type;}; -template struct remove_reference {typedef T type;}; -template struct remove_reference {typedef T type;}; - -template -typename remove_reference::type&& move(T&& arg) { - return static_cast::type&&>(arg); -} - -struct C { - C() = default; - C(const C&) = default; -}; - -struct B { - B() {} - B(const B&) {} - B(B &&) {} -}; - -struct D : B { - D() : B() {} - D(const D &RHS) : B(RHS) {} - // CHECK-MESSAGES: :[[@LINE+3]]:16: warning: move constructor initializes base class by calling a copy constructor [misc-move-constructor-init] - // CHECK-MESSAGES: 19:3: note: copy constructor being called - // CHECK-MESSAGES: 20:3: note: candidate move constructor here - D(D &&RHS) : B(RHS) {} -}; - -struct E : B { - E() : B() {} - E(const E &RHS) : B(RHS) {} - E(E &&RHS) : B(move(RHS)) {} // ok -}; - -struct F { - C M; - - F(F &&) : M(C()) {} // ok -}; - -struct G { - G() = default; - G(const G&) = default; - G(G&&) = delete; -}; - -struct H : G { - H() = default; - H(const H&) = default; - H(H &&RHS) : G(RHS) {} // ok -}; - -struct I { - I(const I &) = default; // suppresses move constructor creation -}; - -struct J : I { - J(J &&RHS) : I(RHS) {} // ok -}; - -struct K {}; // Has implicit copy and move constructors, is trivially copyable -struct L : K { - L(L &&RHS) : K(RHS) {} // ok -}; - -struct M { - B Mem; - // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: move constructor initializes class member by calling a copy constructor [misc-move-constructor-init] - M(M &&RHS) : Mem(RHS.Mem) {} -}; - -struct N { - B Mem; - N(N &&RHS) : Mem(move(RHS.Mem)) {} -}; +// RUN: %python %S/check_clang_tidy.py %s misc-move-constructor-init %t -- -std=c++11 -isystem %S/Inputs/Headers + +#include + +// CHECK-FIXES: #include + +template struct remove_reference {typedef T type;}; +template struct remove_reference {typedef T type;}; +template struct remove_reference {typedef T type;}; + +template +typename remove_reference::type&& move(T&& arg) { + return static_cast::type&&>(arg); +} + +struct C { + C() = default; + C(const C&) = default; +}; + +struct B { + B() {} + B(const B&) {} + B(B &&) {} +}; + +struct D : B { + D() : B() {} + D(const D &RHS) : B(RHS) {} + // CHECK-MESSAGES: :[[@LINE+3]]:16: warning: move constructor initializes base class by calling a copy constructor [misc-move-constructor-init] + // CHECK-MESSAGES: 23:3: note: copy constructor being called + // CHECK-MESSAGES: 24:3: note: candidate move constructor here + D(D &&RHS) : B(RHS) {} +}; + +struct E : B { + E() : B() {} + E(const E &RHS) : B(RHS) {} + E(E &&RHS) : B(move(RHS)) {} // ok +}; + +struct F { + C M; + + F(F &&) : M(C()) {} // ok +}; + +struct G { + G() = default; + G(const G&) = default; + G(G&&) = delete; +}; + +struct H : G { + H() = default; + H(const H&) = default; + H(H &&RHS) : G(RHS) {} // ok +}; + +struct I { + I(const I &) = default; // suppresses move constructor creation +}; + +struct J : I { + J(J &&RHS) : I(RHS) {} // ok +}; + +struct K {}; // Has implicit copy and move constructors, is trivially copyable +struct L : K { + L(L &&RHS) : K(RHS) {} // ok +}; + +struct M { + B Mem; + // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: move constructor initializes class member by calling a copy constructor [misc-move-constructor-init] + M(M &&RHS) : Mem(RHS.Mem) {} +}; + +struct N { + B Mem; + N(N &&RHS) : Mem(move(RHS.Mem)) {} +}; + +struct Movable { + Movable(Movable &&) = default; + Movable(const Movable &) = default; + Movable &operator=(const Movable &) = default; + ~Movable() {} +}; + +struct TriviallyCopyable { + TriviallyCopyable() = default; + TriviallyCopyable(TriviallyCopyable &&) = default; + TriviallyCopyable(const TriviallyCopyable &) = default; +}; + +struct Positive { + Positive(Movable M) : M_(M) {} + // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument can be moved to avoid copy [misc-move-constructor-init] + // CHECK-FIXES: Positive(Movable M) : M_(std::m
Re: [PATCH] D12839: Extend MoveConstructorInitCheck to also flag constructor arguments passed by value and can be moved assigned to fields.
flx added a comment. I don't have access, so that'd be great if you or Alex could submit the patch, thanks! Comment at: clang-tidy/misc/MoveConstructorInitCheck.cpp:11 @@ -10,2 +10,3 @@ #include "MoveConstructorInitCheck.h" +#include "../utils/Matchers.h" #include "clang/AST/ASTContext.h" aaron.ballman wrote: > Errr, I'm not certain that we typically use relative paths for this sort of > thing. I see we do use relative paths for other things in clang-tidy, but > this is definitely an uncommon thing in the rest of the code base (outside of > test or example code). > > Not saying you should change anything here, but we may want to consider > changing the paths at some point so we are more in line with the rest of the > LLVM projects in not using relative include paths. Leaving this as is for now as all other ClangTidy specific includes I could find were relative as well. Not sure if non-relative includes require extra work in the build rules. Comment at: clang-tidy/misc/MoveConstructorInitCheck.cpp:96 @@ +95,3 @@ + +void MoveConstructorInitCheck::handleMoveConstructor( +const MatchFinder::MatchResult &Result) { alexfh wrote: > Other checks have separate options for the include style (see > `PassByValueCheck.cpp`, for example), so this one should have its own option > too. If we ever decide to introduce a common option instead, it will be > easier to do this, if all usages of the `IncludeInserter` do the same thing > with the include style. > > One thing I would change though, is to add the IncludeStyle <-> string > conversion functions instead of doing this in each check. Done. I moved the conversion into IncludeSorter where the the enum is defined. Comment at: clang-tidy/modernize/PassByValueCheck.cpp:121 @@ -120,4 +120,3 @@ : ClangTidyCheck(Name, Context), - IncludeStyle(Options.get("IncludeStyle", "llvm") == "llvm" ? - IncludeSorter::IS_LLVM : IncludeSorter::IS_Google) {} + IncludeStyle(IncludeSorter::toIncludeStyle(Options.get("IncludeStyle", "llvm"))) {} alexfh wrote: > clang-format? This is how clang-format formatted it. I used the following invocation: clang-format --style=LLVM MoveConstructorInitCheck.cpp > formatted And then diffed to only update format changes in code I added. Comment at: clang-tidy/utils/IncludeSorter.h:29 @@ +28,3 @@ + // Converts "llvm" to IS_LLVM, otherwise returns IS_Google. + static IncludeStyle toIncludeStyle(const std::string &Value); + alexfh wrote: > nit: The current name gives no hints at what is being converted to > IncludeStyle, but `parseIncludeStyle` would make it clear that the source is > a string. Done, although the argument type uniquely identifies a function. Comment at: clang-tidy/utils/Matchers.h:1 @@ +1,2 @@ +//===--- Matchers.h - clang-tidy---===// +// aaron.ballman wrote: > You are missing header include guards. Thanks for catching that. Done. Comment at: clang-tidy/utils/TypeTraits.cpp:32 @@ +31,3 @@ + // Ignore trivially copyable types. + return !(Type->isScalarType() || Type.isTriviallyCopyableType(Context) || + classHasTrivialCopyAndDestroy(Type)); aaron.ballman wrote: > No need to check for isScalarType() because isTriviallyCopyableType() already > does that correctly. Done. Also demorganized the expression to make it easier to understand. Comment at: clang-tidy/utils/TypeTraits.h:22 @@ +21,3 @@ +/// destructor. +bool classHasTrivialCopyAndDestroy(QualType Type); + aaron.ballman wrote: > I think this is an implementation detail more than a trait we want to expose. Removed from header. http://reviews.llvm.org/D12839 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D16517: ClangTidy check to flag uninitialized builtin and pointer fields.
flx added a comment. Hi Alex, could you take a look at the questions I posted in my last comment. Maybe there is some renaming work I can tackle while you review the change in more detail. http://reviews.llvm.org/D16517 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D16517: ClangTidy check to flag uninitialized builtin and pointer fields.
flx updated this revision to Diff 47159. flx marked 12 inline comments as done. flx added a comment. Thanks for the review, Alex! This is an intermediate updated patch that addresses your detailed comments. I'll rename the whole check in the next couple of days and will re-upload again. http://reviews.llvm.org/D16517 Files: clang-tidy/misc/CMakeLists.txt clang-tidy/misc/MiscTidyModule.cpp clang-tidy/misc/UninitializedFieldCheck.cpp clang-tidy/misc/UninitializedFieldCheck.h docs/clang-tidy/checks/misc-uninitialized-field.rst test/clang-tidy/misc-uninitialized-field-cxx98.cpp test/clang-tidy/misc-uninitialized-field.cpp Index: test/clang-tidy/misc-uninitialized-field.cpp === --- /dev/null +++ test/clang-tidy/misc-uninitialized-field.cpp @@ -0,0 +1,87 @@ +// RUN: %check_clang_tidy %s misc-uninitialized-field %t + +struct PositiveFieldBeforeConstructor { + int F; + // CHECK-FIXES: int F{}; + PositiveFieldBeforeConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + // CHECK-FIXES: PositiveFieldBeforeConstructor() {} +}; + +struct PositiveFieldAfterConstructor { + PositiveFieldAfterConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G + // CHECK-FIXES: PositiveFieldAfterConstructor() {} + int F; + // CHECK-FIXES: int F{}; + bool G /* with comment */; + // CHECK-FIXES: bool G{} /* with comment */; + PositiveFieldBeforeConstructor IgnoredField; +}; + +struct PositiveSeparateDefinition { + PositiveSeparateDefinition(); + int F; + // CHECK-FIXES: int F{}; +}; + +PositiveSeparateDefinition::PositiveSeparateDefinition() {} +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: F +// CHECK-FIXES: PositiveSeparateDefinition::PositiveSeparateDefinition() {} + +struct PositiveMixedFieldOrder { + PositiveMixedFieldOrder() : J(0) {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: I, K + // CHECK-FIXES: PositiveMixedFieldOrder() : J(0) {} + int I; + // CHECK-FIXES: int I{}; + int J; + int K; + // CHECK-FIXES: int K{}; +}; + +template +struct Template { + Template() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + int F; + // CHECK-FIXES: int F{}; + T T1; + // CHECK-FIXES: T T1; +}; + +void instantiate() { + Template TInt; +} + +struct NegativeFieldInitialized { + int F; + + NegativeFieldInitialized() : F() {} +}; + +struct NegativeFieldInitializedInDefinition { + int F; + + NegativeFieldInitializedInDefinition(); +}; +NegativeFieldInitializedInDefinition::NegativeFieldInitializedInDefinition() : F() {} + + +struct NegativeInClassInitialized { + int F = 0; + + NegativeInClassInitialized() {} +}; + +struct NegativeConstructorDelegated { + int F; + + NegativeConstructorDelegated(int F) : F(F) {} + NegativeConstructorDelegated() : NegativeConstructorDelegated(0) {} +}; + +struct NegativeInitializedInBody { + NegativeInitializedInBody() { I = 0; } + int I; +}; Index: test/clang-tidy/misc-uninitialized-field-cxx98.cpp === --- /dev/null +++ test/clang-tidy/misc-uninitialized-field-cxx98.cpp @@ -0,0 +1,65 @@ +// RUN: %check_clang_tidy %s misc-uninitialized-field %t -- -- -std=c++98 + +struct PositiveFieldBeforeConstructor { + int F; + PositiveFieldBeforeConstructor() /* some comment */ {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + // CHECK-FIXES: PositiveFieldBeforeConstructor() : F() /* some comment */ {} +}; + +struct PositiveFieldAfterConstructor { + PositiveFieldAfterConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G, H + // CHECK-FIXES: PositiveFieldAfterConstructor() : F(), G(), H() {} + int F; + bool G /* with comment */; + int *H; + PositiveFieldBeforeConstructor IgnoredField; +}; + +struct PositiveSeparateDefinition { + PositiveSeparateDefinition(); + int F; +}; + +PositiveSeparateDefinition::PositiveSeparateDefinition() {} +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: F +// CHECK-FIXES: PositiveSeparateDefinition::PositiveSeparateDefinition() : F() {} + +struct PositiveMixedFieldOrder { + PositiveMixedFieldOrder() : /* some comment */ J(0), L(0), M(0) {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: I, K, N + // CHECK-FIXES: PositiveMixedFieldOrder() : I(), /* some comment */ J(0), K(), L(0), M(0), N() {} + int I; + int J; + int K; + int L; + int M; + int N; +}; + +struct PositiveAfterBaseInitializer : public Positiv
Re: [PATCH] D16517: ClangTidy check to flag uninitialized builtin and pointer fields.
flx added inline comments. Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:178 @@ +177,3 @@ + + SmallPtrSet FieldsToInit; + fieldsRequiringInit(MemberFields, FieldsToInit); alexfh wrote: > What about this? (relates to line 184 now) My comment on this was not submitted, just in case. Here it is again: I think he idea is to return immediately if we're delegating to another constructor here. Am I misunderstanding the API call? The important part is that we return in that case. Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:124 @@ +123,3 @@ + std::vector OrderedFields; + OrderedFields.push_back({LastWrittenNonMemberInit, nullptr, {}}); + alexfh wrote: > `.emplace_back(...)`? Gave a compile error. Probably because there is no explicit constructor with the 3 arguments. Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:177 @@ +176,3 @@ + for (CXXCtorInitializer *Init : Ctor->inits()) { +if (Init->isDelegatingInitializer()) + return; alexfh wrote: > I think, this is superfluous. `isMemberInitializer()` should be enough. I think he idea is to return immediately if we're delegating to another constructor here. Is this covered through some other check? Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:199 @@ +198,3 @@ + +for (const auto *Field : FieldsToInit) + Builder << FixItHint::CreateInsertion( alexfh wrote: > nit: We don't use braces only for single-line `if/for` bodies. Same below. Done. This seems really subtle though when it depends on line length instead of single statement inside of loop. Comment at: test/clang-tidy/misc-uninitialized-field.cpp:1 @@ +1,2 @@ +// RUN: %check_clang_tidy %s misc-uninitialized-field %t + alexfh wrote: > As usual: tests with templates and macros, please ;) Thanks for the reminder. Added early return for code inside of macros. Added template test which revealed I had to suppress the check inside of instantiated constructors. http://reviews.llvm.org/D16517 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D16517: ClangTidy check to flag uninitialized builtin and pointer fields.
flx updated this revision to Diff 47280. flx added a comment. Renamed the check to: cppcoreguidelines-pro-type-member-init, note the extra dash between member and init to be consistent with the camelcase notation of the class name ProTypeMemberInitCheck. http://reviews.llvm.org/D16517 Files: clang-tidy/cppcoreguidelines/CMakeLists.txt clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h clang-tidy/misc/CMakeLists.txt clang-tidy/misc/MiscTidyModule.cpp docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst docs/clang-tidy/checks/list.rst test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp Index: test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp === --- /dev/null +++ test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp @@ -0,0 +1,87 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t + +struct PositiveFieldBeforeConstructor { + int F; + // CHECK-FIXES: int F{}; + PositiveFieldBeforeConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + // CHECK-FIXES: PositiveFieldBeforeConstructor() {} +}; + +struct PositiveFieldAfterConstructor { + PositiveFieldAfterConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G + // CHECK-FIXES: PositiveFieldAfterConstructor() {} + int F; + // CHECK-FIXES: int F{}; + bool G /* with comment */; + // CHECK-FIXES: bool G{} /* with comment */; + PositiveFieldBeforeConstructor IgnoredField; +}; + +struct PositiveSeparateDefinition { + PositiveSeparateDefinition(); + int F; + // CHECK-FIXES: int F{}; +}; + +PositiveSeparateDefinition::PositiveSeparateDefinition() {} +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: F +// CHECK-FIXES: PositiveSeparateDefinition::PositiveSeparateDefinition() {} + +struct PositiveMixedFieldOrder { + PositiveMixedFieldOrder() : J(0) {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: I, K + // CHECK-FIXES: PositiveMixedFieldOrder() : J(0) {} + int I; + // CHECK-FIXES: int I{}; + int J; + int K; + // CHECK-FIXES: int K{}; +}; + +template +struct Template { + Template() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + int F; + // CHECK-FIXES: int F{}; + T T1; + // CHECK-FIXES: T T1; +}; + +void instantiate() { + Template TInt; +} + +struct NegativeFieldInitialized { + int F; + + NegativeFieldInitialized() : F() {} +}; + +struct NegativeFieldInitializedInDefinition { + int F; + + NegativeFieldInitializedInDefinition(); +}; +NegativeFieldInitializedInDefinition::NegativeFieldInitializedInDefinition() : F() {} + + +struct NegativeInClassInitialized { + int F = 0; + + NegativeInClassInitialized() {} +}; + +struct NegativeConstructorDelegated { + int F; + + NegativeConstructorDelegated(int F) : F(F) {} + NegativeConstructorDelegated() : NegativeConstructorDelegated(0) {} +}; + +struct NegativeInitializedInBody { + NegativeInitializedInBody() { I = 0; } + int I; +}; Index: test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp === --- /dev/null +++ test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp @@ -0,0 +1,67 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -std=c++98 + +struct PositiveFieldBeforeConstructor { + int F; + PositiveFieldBeforeConstructor() /* some comment */ {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + // CHECK-FIXES: PositiveFieldBeforeConstructor() : F() /* some comment */ {} +}; + +struct PositiveFieldAfterConstructor { + PositiveFieldAfterConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G, H + // CHECK-FIXES: PositiveFieldAfterConstructor() : F(), G(), H() {} + int F; + bool G /* with comment */; + int *H; + PositiveFieldBeforeConstructor IgnoredField; +}; + +struct PositiveSeparateDefinition { + PositiveSeparateDefinition(); + int F; +}; + +PositiveSeparateDefinition::PositiveSeparateDefinition() {} +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: F +// CHECK-FIXES: PositiveSeparateDefinition::PositiveSeparateDefinition() : F() {} + +struct PositiveMixedFieldOrder { + PositiveMixedFieldOrder() : /* some comment */ J(0), L(0), M(0) {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize
[PATCH] D17064: Only invoke ForRangeCopyCheck on expensive-to-copy types.
flx created this revision. flx added a reviewer: alexfh. flx added a subscriber: cfe-commits. flx set the repository for this revision to rL LLVM. Fix oversight not checking the value of the Optional returned by isExpensiveToCopy(). Repository: rL LLVM http://reviews.llvm.org/D17064 Files: clang-tidy/performance/ForRangeCopyCheck.cpp test/clang-tidy/performance-for-range-copy.cpp Index: test/clang-tidy/performance-for-range-copy.cpp === --- test/clang-tidy/performance-for-range-copy.cpp +++ test/clang-tidy/performance-for-range-copy.cpp @@ -127,6 +127,7 @@ } void use(const Mutable &M); +void use(int I); void useTwice(const Mutable &M1, const Mutable &M2); void useByValue(Mutable M); void useByConstValue(const Mutable M); @@ -170,6 +171,30 @@ } } +void negativeConstCheapToCopy() { + for (const int I : View>()) { + } +} + +void negativeConstCheapToCopyTypedef() { + typedef const int ConstInt; + for (ConstInt C : View>()) { + } +} + +void negativeCheapToCopy() { + for (int I : View>()) { +use(I); + } +} + +void negativeCheapToCopyTypedef() { + typedef int Int; + for (Int I : View>()) { +use(I); + } +} + void positiveOnlyConstMethodInvoked() { for (auto M : View>()) { // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy] Index: clang-tidy/performance/ForRangeCopyCheck.cpp === --- clang-tidy/performance/ForRangeCopyCheck.cpp +++ clang-tidy/performance/ForRangeCopyCheck.cpp @@ -135,7 +135,9 @@ } else if (!LoopVar.getType().isConstQualified()) { return false; } - if (!type_traits::isExpensiveToCopy(LoopVar.getType(), Context)) + llvm::Optional Expensive = + type_traits::isExpensiveToCopy(LoopVar.getType(), Context); + if (!Expensive || !*Expensive) return false; auto Diagnostic = diag(LoopVar.getLocation(), @@ -150,8 +152,9 @@ bool ForRangeCopyCheck::handleCopyIsOnlyConstReferenced( const VarDecl &LoopVar, const CXXForRangeStmt &ForRange, ASTContext &Context) { - if (LoopVar.getType().isConstQualified() || - !type_traits::isExpensiveToCopy(LoopVar.getType(), Context)) { + llvm::Optional Expensive = + type_traits::isExpensiveToCopy(LoopVar.getType(), Context); + if (LoopVar.getType().isConstQualified() || !Expensive || !*Expensive) { return false; } // Collect all DeclRefExprs to the loop variable and all CallExprs and Index: test/clang-tidy/performance-for-range-copy.cpp === --- test/clang-tidy/performance-for-range-copy.cpp +++ test/clang-tidy/performance-for-range-copy.cpp @@ -127,6 +127,7 @@ } void use(const Mutable &M); +void use(int I); void useTwice(const Mutable &M1, const Mutable &M2); void useByValue(Mutable M); void useByConstValue(const Mutable M); @@ -170,6 +171,30 @@ } } +void negativeConstCheapToCopy() { + for (const int I : View>()) { + } +} + +void negativeConstCheapToCopyTypedef() { + typedef const int ConstInt; + for (ConstInt C : View>()) { + } +} + +void negativeCheapToCopy() { + for (int I : View>()) { +use(I); + } +} + +void negativeCheapToCopyTypedef() { + typedef int Int; + for (Int I : View>()) { +use(I); + } +} + void positiveOnlyConstMethodInvoked() { for (auto M : View>()) { // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy] Index: clang-tidy/performance/ForRangeCopyCheck.cpp === --- clang-tidy/performance/ForRangeCopyCheck.cpp +++ clang-tidy/performance/ForRangeCopyCheck.cpp @@ -135,7 +135,9 @@ } else if (!LoopVar.getType().isConstQualified()) { return false; } - if (!type_traits::isExpensiveToCopy(LoopVar.getType(), Context)) + llvm::Optional Expensive = + type_traits::isExpensiveToCopy(LoopVar.getType(), Context); + if (!Expensive || !*Expensive) return false; auto Diagnostic = diag(LoopVar.getLocation(), @@ -150,8 +152,9 @@ bool ForRangeCopyCheck::handleCopyIsOnlyConstReferenced( const VarDecl &LoopVar, const CXXForRangeStmt &ForRange, ASTContext &Context) { - if (LoopVar.getType().isConstQualified() || - !type_traits::isExpensiveToCopy(LoopVar.getType(), Context)) { + llvm::Optional Expensive = + type_traits::isExpensiveToCopy(LoopVar.getType(), Context); + if (LoopVar.getType().isConstQualified() || !Expensive || !*Expensive) { return false; } // Collect all DeclRefExprs to the loop variable and all CallExprs and ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D16517: ClangTidy check to flag uninitialized builtin and pointer fields.
flx added inline comments. Comment at: clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp:205 @@ +204,3 @@ + Diag << FixItHint::CreateInsertion( + Field->getSourceRange().getEnd().getLocWithOffset( + Field->getName().size()), alexfh wrote: > Maybe Lexer::getLocForEndOfToken? Tried: Lexer::getLocForEndOfToken(Field->getSourceRange().getEnd(), Field->getName().size(), Result.Context->getSourceManager(), Result.Context->getLangOpts()), but that placed the {} before the field name: - bool G /* with comment */; + bool {}G /* with comment */; http://reviews.llvm.org/D16517 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D16517: ClangTidy check to flag uninitialized builtin and pointer fields.
flx updated this revision to Diff 47590. flx marked 3 inline comments as done. http://reviews.llvm.org/D16517 Files: clang-tidy/cppcoreguidelines/CMakeLists.txt clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst docs/clang-tidy/checks/list.rst test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp Index: test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp === --- /dev/null +++ test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp @@ -0,0 +1,107 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t + +struct PositiveFieldBeforeConstructor { + int F; + // CHECK-FIXES: int F{}; + PositiveFieldBeforeConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + // CHECK-FIXES: PositiveFieldBeforeConstructor() {} +}; + +struct PositiveFieldAfterConstructor { + PositiveFieldAfterConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G + // CHECK-FIXES: PositiveFieldAfterConstructor() {} + int F; + // CHECK-FIXES: int F{}; + bool G /* with comment */; + // CHECK-FIXES: bool G{} /* with comment */; + PositiveFieldBeforeConstructor IgnoredField; +}; + +struct PositiveSeparateDefinition { + PositiveSeparateDefinition(); + int F; + // CHECK-FIXES: int F{}; +}; + +PositiveSeparateDefinition::PositiveSeparateDefinition() {} +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: F +// CHECK-FIXES: PositiveSeparateDefinition::PositiveSeparateDefinition() {} + +struct PositiveMixedFieldOrder { + PositiveMixedFieldOrder() : J(0) {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: I, K + // CHECK-FIXES: PositiveMixedFieldOrder() : J(0) {} + int I; + // CHECK-FIXES: int I{}; + int J; + int K; + // CHECK-FIXES: int K{}; +}; + +template +struct Template { + Template() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + int F; + // CHECK-FIXES: int F{}; + T T1; + // CHECK-FIXES: T T1; +}; + +void instantiate() { + Template TInt; +} + +struct NegativeFieldInitialized { + int F; + + NegativeFieldInitialized() : F() {} +}; + +struct NegativeFieldInitializedInDefinition { + int F; + + NegativeFieldInitializedInDefinition(); +}; +NegativeFieldInitializedInDefinition::NegativeFieldInitializedInDefinition() : F() {} + + +struct NegativeInClassInitialized { + int F = 0; + + NegativeInClassInitialized() {} +}; + +struct NegativeConstructorDelegated { + int F; + + NegativeConstructorDelegated(int F) : F(F) {} + NegativeConstructorDelegated() : NegativeConstructorDelegated(0) {} +}; + +struct NegativeInitializedInBody { + NegativeInitializedInBody() { I = 0; } + int I; +}; + +#define UNINITIALIZED_FIELD_IN_MACRO_BODY(FIELD) \ + struct UninitializedField##FIELD { \ +UninitializedField##FIELD() {} \ +int FIELD; \ + }; \ + +UNINITIALIZED_FIELD_IN_MACRO_BODY(F); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: F +UNINITIALIZED_FIELD_IN_MACRO_BODY(G); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: G + +#define UNINITIALIZED_FIELD_IN_MACRO_ARGUMENT(ARGUMENT) \ + ARGUMENT \ + +UNINITIALIZED_FIELD_IN_MACRO_ARGUMENT(struct UninitializedFieldInMacroArg { + UninitializedFieldInMacroArg() {} + int Field; +}); +// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: constructor does not initialize these built-in/pointer fields: Field Index: test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp === --- /dev/null +++ test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp @@ -0,0 +1,67 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -std=c++98 + +struct PositiveFieldBeforeConstructor { + int F; + PositiveFieldBeforeConstructor() /* some comment */ {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + // CHECK-FIXES: PositiveFieldBeforeConstructor() : F() /* some comment */ {} +}; + +struct PositiveFieldAfterConstructor { + PositiveFieldAfterConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G, H + // CHECK-FIXES: PositiveFieldAfterConstructor() : F(), G(), H() {} + int F; + bool G /* with comment */; + int *H; + PositiveFieldBeforeCon
Re: [PATCH] D16517: ClangTidy check to flag uninitialized builtin and pointer fields.
flx updated this revision to Diff 47594. flx added a comment. Added comment that we're returning early if this constructor simply delegates to another constructor. http://reviews.llvm.org/D16517 Files: clang-tidy/cppcoreguidelines/CMakeLists.txt clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst docs/clang-tidy/checks/list.rst test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp Index: test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp === --- /dev/null +++ test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp @@ -0,0 +1,107 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t + +struct PositiveFieldBeforeConstructor { + int F; + // CHECK-FIXES: int F{}; + PositiveFieldBeforeConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + // CHECK-FIXES: PositiveFieldBeforeConstructor() {} +}; + +struct PositiveFieldAfterConstructor { + PositiveFieldAfterConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G + // CHECK-FIXES: PositiveFieldAfterConstructor() {} + int F; + // CHECK-FIXES: int F{}; + bool G /* with comment */; + // CHECK-FIXES: bool G{} /* with comment */; + PositiveFieldBeforeConstructor IgnoredField; +}; + +struct PositiveSeparateDefinition { + PositiveSeparateDefinition(); + int F; + // CHECK-FIXES: int F{}; +}; + +PositiveSeparateDefinition::PositiveSeparateDefinition() {} +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: F +// CHECK-FIXES: PositiveSeparateDefinition::PositiveSeparateDefinition() {} + +struct PositiveMixedFieldOrder { + PositiveMixedFieldOrder() : J(0) {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: I, K + // CHECK-FIXES: PositiveMixedFieldOrder() : J(0) {} + int I; + // CHECK-FIXES: int I{}; + int J; + int K; + // CHECK-FIXES: int K{}; +}; + +template +struct Template { + Template() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + int F; + // CHECK-FIXES: int F{}; + T T1; + // CHECK-FIXES: T T1; +}; + +void instantiate() { + Template TInt; +} + +struct NegativeFieldInitialized { + int F; + + NegativeFieldInitialized() : F() {} +}; + +struct NegativeFieldInitializedInDefinition { + int F; + + NegativeFieldInitializedInDefinition(); +}; +NegativeFieldInitializedInDefinition::NegativeFieldInitializedInDefinition() : F() {} + + +struct NegativeInClassInitialized { + int F = 0; + + NegativeInClassInitialized() {} +}; + +struct NegativeConstructorDelegated { + int F; + + NegativeConstructorDelegated(int F) : F(F) {} + NegativeConstructorDelegated() : NegativeConstructorDelegated(0) {} +}; + +struct NegativeInitializedInBody { + NegativeInitializedInBody() { I = 0; } + int I; +}; + +#define UNINITIALIZED_FIELD_IN_MACRO_BODY(FIELD) \ + struct UninitializedField##FIELD { \ +UninitializedField##FIELD() {} \ +int FIELD; \ + }; \ + +UNINITIALIZED_FIELD_IN_MACRO_BODY(F); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: F +UNINITIALIZED_FIELD_IN_MACRO_BODY(G); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: G + +#define UNINITIALIZED_FIELD_IN_MACRO_ARGUMENT(ARGUMENT) \ + ARGUMENT \ + +UNINITIALIZED_FIELD_IN_MACRO_ARGUMENT(struct UninitializedFieldInMacroArg { + UninitializedFieldInMacroArg() {} + int Field; +}); +// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: constructor does not initialize these built-in/pointer fields: Field Index: test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp === --- /dev/null +++ test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp @@ -0,0 +1,67 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -std=c++98 + +struct PositiveFieldBeforeConstructor { + int F; + PositiveFieldBeforeConstructor() /* some comment */ {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + // CHECK-FIXES: PositiveFieldBeforeConstructor() : F() /* some comment */ {} +}; + +struct PositiveFieldAfterConstructor { + PositiveFieldAfterConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G, H + // CHECK-FIXES: PositiveFieldAfterConstructor() : F(),
Re: [PATCH] D16517: ClangTidy check to flag uninitialized builtin and pointer fields.
flx updated this revision to Diff 47757. flx marked 2 inline comments as done. http://reviews.llvm.org/D16517 Files: clang-tidy/cppcoreguidelines/CMakeLists.txt clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst docs/clang-tidy/checks/list.rst test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp Index: test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp === --- /dev/null +++ test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp @@ -0,0 +1,111 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t + +struct PositiveFieldBeforeConstructor { + int F; + // CHECK-FIXES: int F{}; + PositiveFieldBeforeConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + // CHECK-FIXES: PositiveFieldBeforeConstructor() {} +}; + +struct PositiveFieldAfterConstructor { + PositiveFieldAfterConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G + // CHECK-FIXES: PositiveFieldAfterConstructor() {} + int F; + // CHECK-FIXES: int F{}; + bool G /* with comment */; + // CHECK-FIXES: bool G{} /* with comment */; + PositiveFieldBeforeConstructor IgnoredField; +}; + +struct PositiveSeparateDefinition { + PositiveSeparateDefinition(); + int F; + // CHECK-FIXES: int F{}; +}; + +PositiveSeparateDefinition::PositiveSeparateDefinition() {} +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: F +// CHECK-FIXES: PositiveSeparateDefinition::PositiveSeparateDefinition() {} + +struct PositiveMixedFieldOrder { + PositiveMixedFieldOrder() : J(0) {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: I, K + // CHECK-FIXES: PositiveMixedFieldOrder() : J(0) {} + int I; + // CHECK-FIXES: int I{}; + int J; + int K; + // CHECK-FIXES: int K{}; +}; + +template +struct Template { + Template() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + int F; + // CHECK-FIXES: int F{}; + T T1; + // CHECK-FIXES: T T1; +}; + +void instantiate() { + Template TInt; +} + +struct NegativeFieldInitialized { + int F; + + NegativeFieldInitialized() : F() {} +}; + +struct NegativeFieldInitializedInDefinition { + int F; + + NegativeFieldInitializedInDefinition(); +}; +NegativeFieldInitializedInDefinition::NegativeFieldInitializedInDefinition() : F() {} + + +struct NegativeInClassInitialized { + int F = 0; + + NegativeInClassInitialized() {} +}; + +struct NegativeConstructorDelegated { + int F; + + NegativeConstructorDelegated(int F) : F(F) {} + NegativeConstructorDelegated() : NegativeConstructorDelegated(0) {} +}; + +struct NegativeInitializedInBody { + NegativeInitializedInBody() { I = 0; } + int I; +}; + +#define UNINITIALIZED_FIELD_IN_MACRO_BODY(FIELD) \ + struct UninitializedField##FIELD { \ +UninitializedField##FIELD() {} \ +int FIELD; \ + }; \ +// Ensure FIELD is not initialized since fixes inside of macros are disabled. +// CHECK-FIXES: int FIELD; + +UNINITIALIZED_FIELD_IN_MACRO_BODY(F); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: F +UNINITIALIZED_FIELD_IN_MACRO_BODY(G); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: G + +#define UNINITIALIZED_FIELD_IN_MACRO_ARGUMENT(ARGUMENT) \ + ARGUMENT \ + +UNINITIALIZED_FIELD_IN_MACRO_ARGUMENT(struct UninitializedFieldInMacroArg { + UninitializedFieldInMacroArg() {} + int Field; +}); +// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: constructor does not initialize these built-in/pointer fields: Field +// Ensure FIELD is not initialized since fixes inside of macros are disabled. +// CHECK-FIXES: int Field; Index: test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp === --- /dev/null +++ test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp @@ -0,0 +1,67 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -std=c++98 + +struct PositiveFieldBeforeConstructor { + int F; + PositiveFieldBeforeConstructor() /* some comment */ {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + // CHECK-FIXES: PositiveFieldBeforeConstructor() : F() /* some comment */ {} +}; + +struct PositiveFieldAfterConstructor { + PositiveFieldAfterConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: c
Re: [PATCH] D16517: ClangTidy check to flag uninitialized builtin and pointer fields.
flx added inline comments. Comment at: clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp:206 @@ +205,3 @@ + // Do not propose fixes in macros since we cannot place them correctly. + if (Ctor->getLocStart().isMacroID()) +return; alexfh wrote: > IIUC what this is doing, the offset should be `0` instead of > `Field->getName().size()`. I've tried > `Lexer::getLocForEndOfToken(Field->getSourceRange().getEnd(), 0, > *Result.SourceManager, Result.Context->getLangOpts())` and it seems to work > fine on your tests. Great, that worked. http://reviews.llvm.org/D16517 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] r260869 - Improve documentation
Author: flx Date: Sun Feb 14 21:27:54 2016 New Revision: 260869 URL: http://llvm.org/viewvc/llvm-project?rev=260869&view=rev Log: Improve documentation Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/performance-for-range-copy.rst Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/performance-for-range-copy.rst URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/performance-for-range-copy.rst?rev=260869&r1=260868&r2=260869&view=diff == --- clang-tools-extra/trunk/docs/clang-tidy/checks/performance-for-range-copy.rst (original) +++ clang-tools-extra/trunk/docs/clang-tidy/checks/performance-for-range-copy.rst Sun Feb 14 21:27:54 2016 @@ -10,8 +10,8 @@ The check is only applied to loop variab which means they are not trivially copyable or have a non-trivial copy constructor or destructor. -To ensure that it is safe to replace the copy with const reference the following -heuristic is employed: +To ensure that it is safe to replace the copy with a const reference the +following heuristic is employed: 1. The loop variable is const qualified. 2. The loop variable is not const, but only const methods or operators are ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] r260870 - [clang-tidy] Only invoke ForRangeCopyCheck on expensive-to-copy types.
Author: flx Date: Sun Feb 14 21:36:23 2016 New Revision: 260870 URL: http://llvm.org/viewvc/llvm-project?rev=260870&view=rev Log: [clang-tidy] Only invoke ForRangeCopyCheck on expensive-to-copy types. Summary: Fix oversight not checking the value of the Optional returned by isExpensiveToCopy(). Reviewers: alexfh Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D17064 Modified: clang-tools-extra/trunk/clang-tidy/performance/ForRangeCopyCheck.cpp clang-tools-extra/trunk/test/clang-tidy/performance-for-range-copy.cpp Modified: clang-tools-extra/trunk/clang-tidy/performance/ForRangeCopyCheck.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/performance/ForRangeCopyCheck.cpp?rev=260870&r1=260869&r2=260870&view=diff == --- clang-tools-extra/trunk/clang-tidy/performance/ForRangeCopyCheck.cpp (original) +++ clang-tools-extra/trunk/clang-tidy/performance/ForRangeCopyCheck.cpp Sun Feb 14 21:36:23 2016 @@ -135,7 +135,9 @@ bool ForRangeCopyCheck::handleConstValue } else if (!LoopVar.getType().isConstQualified()) { return false; } - if (!type_traits::isExpensiveToCopy(LoopVar.getType(), Context)) + llvm::Optional Expensive = + type_traits::isExpensiveToCopy(LoopVar.getType(), Context); + if (!Expensive || !*Expensive) return false; auto Diagnostic = diag(LoopVar.getLocation(), @@ -150,8 +152,9 @@ bool ForRangeCopyCheck::handleConstValue bool ForRangeCopyCheck::handleCopyIsOnlyConstReferenced( const VarDecl &LoopVar, const CXXForRangeStmt &ForRange, ASTContext &Context) { - if (LoopVar.getType().isConstQualified() || - !type_traits::isExpensiveToCopy(LoopVar.getType(), Context)) { + llvm::Optional Expensive = + type_traits::isExpensiveToCopy(LoopVar.getType(), Context); + if (LoopVar.getType().isConstQualified() || !Expensive || !*Expensive) { return false; } // Collect all DeclRefExprs to the loop variable and all CallExprs and Modified: clang-tools-extra/trunk/test/clang-tidy/performance-for-range-copy.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/performance-for-range-copy.cpp?rev=260870&r1=260869&r2=260870&view=diff == --- clang-tools-extra/trunk/test/clang-tidy/performance-for-range-copy.cpp (original) +++ clang-tools-extra/trunk/test/clang-tidy/performance-for-range-copy.cpp Sun Feb 14 21:36:23 2016 @@ -127,6 +127,7 @@ bool operator!=(const Mutable& M1, const } void use(const Mutable &M); +void use(int I); void useTwice(const Mutable &M1, const Mutable &M2); void useByValue(Mutable M); void useByConstValue(const Mutable M); @@ -170,6 +171,30 @@ void negativeNonConstNonMemberOperatorIn } } +void negativeConstCheapToCopy() { + for (const int I : View>()) { + } +} + +void negativeConstCheapToCopyTypedef() { + typedef const int ConstInt; + for (ConstInt C : View>()) { + } +} + +void negativeCheapToCopy() { + for (int I : View>()) { +use(I); + } +} + +void negativeCheapToCopyTypedef() { + typedef int Int; + for (Int I : View>()) { +use(I); + } +} + void positiveOnlyConstMethodInvoked() { for (auto M : View>()) { // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy] ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D17064: Only invoke ForRangeCopyCheck on expensive-to-copy types.
This revision was automatically updated to reflect the committed changes. Closed by commit rL260870: [clang-tidy] Only invoke ForRangeCopyCheck on expensive-to-copy types. (authored by flx). Changed prior to commit: http://reviews.llvm.org/D17064?vs=47419&id=47940#toc Repository: rL LLVM http://reviews.llvm.org/D17064 Files: clang-tools-extra/trunk/clang-tidy/performance/ForRangeCopyCheck.cpp clang-tools-extra/trunk/test/clang-tidy/performance-for-range-copy.cpp Index: clang-tools-extra/trunk/test/clang-tidy/performance-for-range-copy.cpp === --- clang-tools-extra/trunk/test/clang-tidy/performance-for-range-copy.cpp +++ clang-tools-extra/trunk/test/clang-tidy/performance-for-range-copy.cpp @@ -127,6 +127,7 @@ } void use(const Mutable &M); +void use(int I); void useTwice(const Mutable &M1, const Mutable &M2); void useByValue(Mutable M); void useByConstValue(const Mutable M); @@ -170,6 +171,30 @@ } } +void negativeConstCheapToCopy() { + for (const int I : View>()) { + } +} + +void negativeConstCheapToCopyTypedef() { + typedef const int ConstInt; + for (ConstInt C : View>()) { + } +} + +void negativeCheapToCopy() { + for (int I : View>()) { +use(I); + } +} + +void negativeCheapToCopyTypedef() { + typedef int Int; + for (Int I : View>()) { +use(I); + } +} + void positiveOnlyConstMethodInvoked() { for (auto M : View>()) { // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy] Index: clang-tools-extra/trunk/clang-tidy/performance/ForRangeCopyCheck.cpp === --- clang-tools-extra/trunk/clang-tidy/performance/ForRangeCopyCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/performance/ForRangeCopyCheck.cpp @@ -135,7 +135,9 @@ } else if (!LoopVar.getType().isConstQualified()) { return false; } - if (!type_traits::isExpensiveToCopy(LoopVar.getType(), Context)) + llvm::Optional Expensive = + type_traits::isExpensiveToCopy(LoopVar.getType(), Context); + if (!Expensive || !*Expensive) return false; auto Diagnostic = diag(LoopVar.getLocation(), @@ -150,8 +152,9 @@ bool ForRangeCopyCheck::handleCopyIsOnlyConstReferenced( const VarDecl &LoopVar, const CXXForRangeStmt &ForRange, ASTContext &Context) { - if (LoopVar.getType().isConstQualified() || - !type_traits::isExpensiveToCopy(LoopVar.getType(), Context)) { + llvm::Optional Expensive = + type_traits::isExpensiveToCopy(LoopVar.getType(), Context); + if (LoopVar.getType().isConstQualified() || !Expensive || !*Expensive) { return false; } // Collect all DeclRefExprs to the loop variable and all CallExprs and Index: clang-tools-extra/trunk/test/clang-tidy/performance-for-range-copy.cpp === --- clang-tools-extra/trunk/test/clang-tidy/performance-for-range-copy.cpp +++ clang-tools-extra/trunk/test/clang-tidy/performance-for-range-copy.cpp @@ -127,6 +127,7 @@ } void use(const Mutable &M); +void use(int I); void useTwice(const Mutable &M1, const Mutable &M2); void useByValue(Mutable M); void useByConstValue(const Mutable M); @@ -170,6 +171,30 @@ } } +void negativeConstCheapToCopy() { + for (const int I : View>()) { + } +} + +void negativeConstCheapToCopyTypedef() { + typedef const int ConstInt; + for (ConstInt C : View>()) { + } +} + +void negativeCheapToCopy() { + for (int I : View>()) { +use(I); + } +} + +void negativeCheapToCopyTypedef() { + typedef int Int; + for (Int I : View>()) { +use(I); + } +} + void positiveOnlyConstMethodInvoked() { for (auto M : View>()) { // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy] Index: clang-tools-extra/trunk/clang-tidy/performance/ForRangeCopyCheck.cpp === --- clang-tools-extra/trunk/clang-tidy/performance/ForRangeCopyCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/performance/ForRangeCopyCheck.cpp @@ -135,7 +135,9 @@ } else if (!LoopVar.getType().isConstQualified()) { return false; } - if (!type_traits::isExpensiveToCopy(LoopVar.getType(), Context)) + llvm::Optional Expensive = + type_traits::isExpensiveToCopy(LoopVar.getType(), Context); + if (!Expensive || !*Expensive) return false; auto Diagnostic = diag(LoopVar.getLocation(), @@ -150,8 +152,9 @@ bool ForRangeCopyCheck::handleCopyIsOnlyConstReferenced( const VarDecl &LoopVar, const CXXForRangeStmt &ForRange, ASTContext &Context) { - if (LoopVar.getType().isConstQualified() || - !type_traits::isExpensiveToCopy(LoopVar.getType(), Context)) { + llvm::Optional Expensive = + type_traits::isExpen
r260872 - Add isAnyPointer() matchers. Register missing matchers.
Author: flx Date: Sun Feb 14 22:00:39 2016 New Revision: 260872 URL: http://llvm.org/viewvc/llvm-project?rev=260872&view=rev Log: Add isAnyPointer() matchers. Register missing matchers. Summary: The isAnyPointer() matcher is useful for http://reviews.llvm.org/D15623. Reviewers: alexfh, klimek Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D15819 Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=260872&r1=260871&r2=260872&view=diff == --- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original) +++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Sun Feb 14 22:00:39 2016 @@ -3673,6 +3673,19 @@ AST_MATCHER(QualType, isAnyCharacter) { return Node->isAnyCharacterType(); } + \brief Matches QualType nodes that are of any pointer type. +/// +/// Given +/// \code +/// int *i = nullptr; +/// int j; +/// \endcode +/// varDecl(hasType(isAnyPointer())) +/// matches "int *i", but not "int j". +AST_MATCHER(QualType, isAnyPointer) { + return Node->isAnyPointerType(); +} + /// \brief Matches QualType nodes that are const-qualified, i.e., that /// include "top-level" const. /// Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=260872&r1=260871&r2=260872&view=diff == --- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original) +++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Sun Feb 14 22:00:39 2016 @@ -264,6 +264,8 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(innerType); REGISTER_MATCHER(integerLiteral); REGISTER_MATCHER(isAnonymous); + REGISTER_MATCHER(isAnyCharacter); + REGISTER_MATCHER(isAnyPointer); REGISTER_MATCHER(isArrow); REGISTER_MATCHER(isBaseInitializer); REGISTER_MATCHER(isCatchAll); Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=260872&r1=260871&r2=260872&view=diff == --- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original) +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Sun Feb 14 22:00:39 2016 @@ -1479,6 +1479,14 @@ TEST(IsInteger, ReportsNoFalsePositives) to(varDecl(hasType(isInteger(); } +TEST(IsAnyPointer, MatchesPointers) { + EXPECT_TRUE(matches("int* i = nullptr;", varDecl(hasType(isAnyPointer(); +} + +TEST(IsAnyPointer, ReportsNoFalsePositives) { + EXPECT_TRUE(notMatches("int i = 0;", varDecl(hasType(isAnyPointer(); +} + TEST(IsAnyCharacter, MatchesCharacters) { EXPECT_TRUE(matches("char i = 0;", varDecl(hasType(isAnyCharacter(); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D16517: ClangTidy check to flag uninitialized builtin and pointer fields.
This revision was automatically updated to reflect the committed changes. Closed by commit rL260873: [clang-tidy] ClangTidy check to flag uninitialized builtin and pointer fields. (authored by flx). Changed prior to commit: http://reviews.llvm.org/D16517?vs=47757&id=47942#toc Repository: rL LLVM http://reviews.llvm.org/D16517 Files: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp Index: clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp === --- clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp +++ clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp @@ -0,0 +1,67 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -std=c++98 + +struct PositiveFieldBeforeConstructor { + int F; + PositiveFieldBeforeConstructor() /* some comment */ {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + // CHECK-FIXES: PositiveFieldBeforeConstructor() : F() /* some comment */ {} +}; + +struct PositiveFieldAfterConstructor { + PositiveFieldAfterConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G, H + // CHECK-FIXES: PositiveFieldAfterConstructor() : F(), G(), H() {} + int F; + bool G /* with comment */; + int *H; + PositiveFieldBeforeConstructor IgnoredField; +}; + +struct PositiveSeparateDefinition { + PositiveSeparateDefinition(); + int F; +}; + +PositiveSeparateDefinition::PositiveSeparateDefinition() {} +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: F +// CHECK-FIXES: PositiveSeparateDefinition::PositiveSeparateDefinition() : F() {} + +struct PositiveMixedFieldOrder { + PositiveMixedFieldOrder() : /* some comment */ J(0), L(0), M(0) {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: I, K, N + // CHECK-FIXES: PositiveMixedFieldOrder() : I(), /* some comment */ J(0), K(), L(0), M(0), N() {} + int I; + int J; + int K; + int L; + int M; + int N; +}; + +struct PositiveAfterBaseInitializer : public PositiveMixedFieldOrder { + PositiveAfterBaseInitializer() : PositiveMixedFieldOrder() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + // CHECK-FIXES: PositiveAfterBaseInitializer() : PositiveMixedFieldOrder(), F() {} + int F; +}; + +struct NegativeFieldInitialized { + int F; + + NegativeFieldInitialized() : F() {} +}; + +struct NegativeFieldInitializedInDefinition { + int F; + + NegativeFieldInitializedInDefinition(); +}; + +NegativeFieldInitializedInDefinition::NegativeFieldInitializedInDefinition() : F() {} + +struct NegativeInitializedInBody { + NegativeInitializedInBody() { I = 0; } + int I; +}; + + Index: clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp === --- clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp +++ clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp @@ -0,0 +1,111 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t + +struct PositiveFieldBeforeConstructor { + int F; + // CHECK-FIXES: int F{}; + PositiveFieldBeforeConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F + // CHECK-FIXES: PositiveFieldBeforeConstructor() {} +}; + +struct PositiveFieldAfterConstructor { + PositiveFieldAfterConstructor() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G + // CHECK-FIXES: PositiveFieldAfterConstructor() {} + int F; + // CHECK-FIXES: int F{}; + bool G /* with comment */; + // CHECK-FIXES: bool G{} /* with comment */; + PositiveFieldBeforeConstructor IgnoredField; +}; + +struct PositiveSeparateDefinition { + PositiveSeparateDefinition(); + int F; + // CHECK-FIXES: int F{}; +}; + +PositiveSeparateDefinition::PositiveSeparateDefinition() {} +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/po
[clang-tools-extra] r260873 - [clang-tidy] ClangTidy check to flag uninitialized builtin and pointer fields.
Author: flx Date: Sun Feb 14 22:27:56 2016 New Revision: 260873 URL: http://llvm.org/viewvc/llvm-project?rev=260873&view=rev Log: [clang-tidy] ClangTidy check to flag uninitialized builtin and pointer fields. Summary: This patch is a continuation of http://reviews.llvm.org/D10553 by Jonathan B Coe. The main additions are: 1. For C++11 the check suggests in-class field initialization as fix. This makes the fields future proof towards the addition of new constructors. 2 For older language versions the fields are added in the right position in the initializer list with more tests. 3. User documentation. Reviewers: alexfh, jbcoe Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D16517 Added: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp Modified: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst Modified: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt?rev=260873&r1=260872&r2=260873&view=diff == --- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt (original) +++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt Sun Feb 14 22:27:56 2016 @@ -7,6 +7,7 @@ add_clang_library(clangTidyCppCoreGuidel ProBoundsPointerArithmeticCheck.cpp ProTypeConstCastCheck.cpp ProTypeCstyleCastCheck.cpp + ProTypeMemberInitCheck.cpp ProTypeReinterpretCastCheck.cpp ProTypeStaticCastDowncastCheck.cpp ProTypeUnionAccessCheck.cpp Modified: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp?rev=260873&r1=260872&r2=260873&view=diff == --- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp (original) +++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp Sun Feb 14 22:27:56 2016 @@ -16,6 +16,7 @@ #include "ProBoundsPointerArithmeticCheck.h" #include "ProTypeConstCastCheck.h" #include "ProTypeCstyleCastCheck.h" +#include "ProTypeMemberInitCheck.h" #include "ProTypeReinterpretCastCheck.h" #include "ProTypeStaticCastDowncastCheck.h" #include "ProTypeUnionAccessCheck.h" @@ -39,6 +40,8 @@ public: "cppcoreguidelines-pro-type-const-cast"); CheckFactories.registerCheck( "cppcoreguidelines-pro-type-cstyle-cast"); +CheckFactories.registerCheck( +"cppcoreguidelines-pro-type-member-init"); CheckFactories.registerCheck( "cppcoreguidelines-pro-type-reinterpret-cast"); CheckFactories.registerCheck( Added: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp?rev=260873&view=auto == --- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp (added) +++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp Sun Feb 14 22:27:56 2016 @@ -0,0 +1,231 @@ +//===--- ProTypeMemberInitCheck.cpp - clang-tidy---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// + +#include "ProTypeMemberInitCheck.h" +#include "../utils/LexerUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" +#include "llvm/ADT/SmallPtrSet.h" + +using namespace clang::ast_matchers; +using llvm::SmallPtrSet; +using llvm::SmallPtrSetImpl; + +namespace clang { +namespace tidy { +namespace cppcoreguidelines { + +namespace { + +AST_MATCHER(CXXConstructorDecl, isUserProvided) { + return Node.isUserProvided(); +} + +static void +fieldsRequiringInit(const RecordDecl::field_range &Fields, +SmallPtrSetImpl &FieldsToInit) { + for (const FieldDecl *F : Fields) { +QualType Type = F->getType()
Re: r260872 - Add isAnyPointer() matchers. Register missing matchers.
On Mon, Feb 15, 2016 at 8:05 AM, Aaron Ballman wrote: > On Sun, Feb 14, 2016 at 11:00 PM, Felix Berger via cfe-commits > wrote: > > Author: flx > > Date: Sun Feb 14 22:00:39 2016 > > New Revision: 260872 > > > > URL: http://llvm.org/viewvc/llvm-project?rev=260872&view=rev > > Log: > > Add isAnyPointer() matchers. Register missing matchers. > > > > Summary: > > The isAnyPointer() matcher is useful for http://reviews.llvm.org/D15623. > > > > Reviewers: alexfh, klimek > > > > Subscribers: cfe-commits > > > > Differential Revision: http://reviews.llvm.org/D15819 > > > > Modified: > > cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h > > cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp > > cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp > > > > Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h > > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=260872&r1=260871&r2=260872&view=diff > > > == > > --- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original) > > +++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Sun Feb 14 > 22:00:39 2016 > > @@ -3673,6 +3673,19 @@ AST_MATCHER(QualType, isAnyCharacter) { > > return Node->isAnyCharacterType(); > > } > > > > + \brief Matches QualType nodes that are of any pointer type. > > +/// > > +/// Given > > +/// \code > > +/// int *i = nullptr; > > +/// int j; > > +/// \endcode > > +/// varDecl(hasType(isAnyPointer())) > > +/// matches "int *i", but not "int j". > > +AST_MATCHER(QualType, isAnyPointer) { > > + return Node->isAnyPointerType(); > > +} > > The whole point to isAnyPointer() is for objective C types, where > pointers are modeled differently. Can you add documentation, an > example, and tests for that fact? > > Thanks for making me look into this further. After looking through the existing test cases and matchers I found there is already a pointerType() matcher which is the matcher I originally wanted to expose. I can do one of two things now: 1. Keep the new isAnyPointer() matcher if we think it's useful and add an objc pointer test for it which is already in the works. 2. Remove the matcher again since there is no real need for it and users could get the same by writing anyOf(pointerType(), objcObjectPointerType()) What do you think? > ~Aaron > > > + > > /// \brief Matches QualType nodes that are const-qualified, i.e., that > > /// include "top-level" const. > > /// > > > > Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp > > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=260872&r1=260871&r2=260872&view=diff > > > == > > --- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original) > > +++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Sun Feb 14 22:00:39 > 2016 > > @@ -264,6 +264,8 @@ RegistryMaps::RegistryMaps() { > >REGISTER_MATCHER(innerType); > >REGISTER_MATCHER(integerLiteral); > >REGISTER_MATCHER(isAnonymous); > > + REGISTER_MATCHER(isAnyCharacter); > > + REGISTER_MATCHER(isAnyPointer); > >REGISTER_MATCHER(isArrow); > >REGISTER_MATCHER(isBaseInitializer); > >REGISTER_MATCHER(isCatchAll); > > > > Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp > > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=260872&r1=260871&r2=260872&view=diff > > > == > > --- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original) > > +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Sun Feb 14 > 22:00:39 2016 > > @@ -1479,6 +1479,14 @@ TEST(IsInteger, ReportsNoFalsePositives) > >to(varDecl(hasType(isInteger(); > > } > > > > +TEST(IsAnyPointer, MatchesPointers) { > > + EXPECT_TRUE(matches("int* i = nullptr;", > varDecl(hasType(isAnyPointer(); > > +} > > + > > +TEST(IsAnyPointer, ReportsNoFalsePositives) { > > + EXPECT_TRUE(notMatches("int i = 0;", > varDecl(hasType(isAnyPointer(); > > +} > > + > > TEST(IsAnyCharacter, MatchesCharacters) { > >EXPECT_TRUE(matches("char i = 0;", > varDecl(hasType(isAnyCharacter(); > > } > > > > > > ___ > > cfe-commits mailing list > > cfe-commits@lists.llvm.org > > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits > ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D17488: Extend UnnecessaryCopyInitialization check to trigger on non-const copies that can be safely converted to const references.
flx created this revision. flx added a reviewer: alexfh. flx added a subscriber: cfe-commits. flx set the repository for this revision to rL LLVM. Move code shared between UnnecessaryCopyInitialization and ForRangeCopyCheck into utilities files. Add more test cases for UnnecessaryCopyInitialization and disable fixes inside of macros. Repository: rL LLVM http://reviews.llvm.org/D17488 Files: clang-tidy/performance/ForRangeCopyCheck.cpp clang-tidy/performance/UnnecessaryCopyInitialization.cpp clang-tidy/performance/UnnecessaryCopyInitialization.h clang-tidy/utils/CMakeLists.txt clang-tidy/utils/DeclRefExprUtils.cpp clang-tidy/utils/DeclRefExprUtils.h clang-tidy/utils/FixItHintUtils.cpp clang-tidy/utils/FixItHintUtils.h test/clang-tidy/performance-unnecessary-copy-initialization.cpp Index: test/clang-tidy/performance-unnecessary-copy-initialization.cpp === --- test/clang-tidy/performance-unnecessary-copy-initialization.cpp +++ test/clang-tidy/performance-unnecessary-copy-initialization.cpp @@ -4,6 +4,7 @@ ExpensiveToCopyType() {} virtual ~ExpensiveToCopyType() {} const ExpensiveToCopyType &reference() const { return *this; } + void nonConstMethod() {} }; struct TrivialToCopyType { @@ -20,6 +21,11 @@ return *Type; } +void mutate(ExpensiveToCopyType &); +void mutate(ExpensiveToCopyType *); +void useAsConstReference(const ExpensiveToCopyType &); +void useByValue(ExpensiveToCopyType); + void PositiveFunctionCall() { const auto AutoAssigned = ExpensiveTypeReference(); // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' is copy-constructed from a const reference; consider making it a const reference [performance-unnecessary-copy-initialization] @@ -114,11 +120,53 @@ static const auto StaticVar = Obj.reference(); } -void NegativeFunctionCallExpensiveTypeNonConstVariable() { +void PositiveFunctionCallExpensiveTypeNonConstVariable() { auto AutoAssigned = ExpensiveTypeReference(); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'AutoAssigned' is copy-constructed from a const reference but is only used as const reference; consider making it a const reference [performance-unnecessary-copy-initialization] + // CHECK-FIXES: const auto& AutoAssigned = ExpensiveTypeReference(); auto AutoCopyConstructed(ExpensiveTypeReference()); + // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable + // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveTypeReference()); ExpensiveToCopyType VarAssigned = ExpensiveTypeReference(); + // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable + // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveTypeReference(); ExpensiveToCopyType VarCopyConstructed(ExpensiveTypeReference()); + // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable + // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveTypeReference()); +} + +void positiveNonConstVarInCodeBlock(const ExpensiveToCopyType &Obj) { + { +auto Assigned = Obj.reference(); +// CHECK-MESSAGES: [[@LINE-1]]:10: warning: the variable +// CHECK-FIXES: const auto& Assigned = Obj.reference(); +Assigned.reference(); +useAsConstReference(Assigned); +useByValue(Assigned); + } +} + +void negativeNonConstVarWithNonConstUse(const ExpensiveToCopyType &Obj) { + { +auto NonConstInvoked = Obj.reference(); +// CHECK-FIXES: auto NonConstInvoked = Obj.reference(); +NonConstInvoked.nonConstMethod(); + } + { +auto Reassigned = Obj.reference(); +// CHECK-FIXES: auto Reassigned = Obj.reference(); +Reassigned = ExpensiveToCopyType(); + } + { +auto MutatedByReference = Obj.reference(); +// CHECK-FIXES: auto MutatedByReference = Obj.reference(); +mutate(MutatedByReference); + } + { +auto MutatedByPointer = Obj.reference(); +// CHECK-FIXES: auto MutatedByPointer = Obj.reference(); +mutate(&MutatedByPointer); + } } void NegativeMethodCallNonConstRef(ExpensiveToCopyType &Obj) { @@ -146,11 +194,32 @@ ExpensiveToCopyType Obj; const auto AutoAssigned = Obj.reference(); const auto AutoCopyConstructed(Obj.reference()); - const ExpensiveToCopyType VarAssigned = Obj.reference(); - const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); + ExpensiveToCopyType VarAssigned = Obj.reference(); + ExpensiveToCopyType VarCopyConstructed(Obj.reference()); } struct NegativeConstructor { NegativeConstructor(const ExpensiveToCopyType &Obj) : Obj(Obj) {} ExpensiveToCopyType Obj; }; + +#define UNNECESSARY_COPY_INIT_IN_MACRO_BODY(TYPE) \ + void functionWith##TYPE(const TYPE& T) { \ +auto AssignedInMacro = T.reference(); \ + } \ +// Ensure fix is not applied. +// CHECK-FIXES: auto AssignedInMacro = T.reference(); + + +UNNECESSARY_COPY_INIT_IN_MACRO_BODY(ExpensiveToCopyType) +// CHECK-MESSAGES: [[@LINE-1]]:1: warning: the variable 'AssignedInMacro' is
[PATCH] D17491: Add performance check to flag function parameters of expensive to copy types that can be safely converted to const references.
flx created this revision. flx added a reviewer: alexfh. flx added a subscriber: cfe-commits. flx set the repository for this revision to rL LLVM. The patch uses [[ http://reviews.llvm.org/D17488 | D17488 ]] as diff base. Once D17488 is submitted I'll update the diffbase to head. Repository: rL LLVM http://reviews.llvm.org/D17491 Files: clang-tidy/performance/CMakeLists.txt clang-tidy/performance/PerformanceTidyModule.cpp clang-tidy/performance/UnnecessaryValueParamCheck.cpp clang-tidy/performance/UnnecessaryValueParamCheck.h docs/clang-tidy/checks/list.rst docs/clang-tidy/checks/performance-unnecessary-value-param.rst test/clang-tidy/performance-unnecessary-value-param.cpp Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- /dev/null +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -0,0 +1,160 @@ +// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t + +struct ExpensiveToCopyType { + const ExpensiveToCopyType & constReference() const { +return *this; + } + void nonConstMethod() {} + virtual ~ExpensiveToCopyType() {} +}; + +void mutate(ExpensiveToCopyType &); +void mutate(ExpensiveToCopyType *); +void useAsConstReference(const ExpensiveToCopyType &); +void useByValue(ExpensiveToCopyType); + +// This class simulates std::pair<>. It is trivially copy constructible +// and trivially destructible, but not trivially copy assignable. +class SomewhatTrivial { + public: + SomewhatTrivial(); + SomewhatTrivial(const SomewhatTrivial&) = default; + ~SomewhatTrivial() = default; + SomewhatTrivial& operator=(const SomewhatTrivial&); +}; + +void positiveExpensiveConstValue(const ExpensiveToCopyType Obj); +// CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj); +void positiveExpensiveConstValue(const ExpensiveToCopyType Obj) { + // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'Obj' is copied for each invocation; consider making this a reference [performance-unnecessary-value-param] + // CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj) { +} + +void positiveExpensiveValue(ExpensiveToCopyType Obj); +// CHECK-FIXES: void positiveExpensiveValue(const ExpensiveToCopyType& Obj); +void positiveExpensiveValue(ExpensiveToCopyType Obj) { + // CHECK-MESSAGES: [[@LINE-1]]:49: warning: the parameter 'Obj' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param] + // CHECK-FIXES: void positiveExpensiveValue(const ExpensiveToCopyType& Obj) { + Obj.constReference(); + useAsConstReference(Obj); + auto Copy = Obj; + useByValue(Obj); +} + +void positiveWithComment(const ExpensiveToCopyType /* important */ S); +// CHECK-FIXES: void positiveWithComment(const ExpensiveToCopyType& /* important */ S); +void positiveWithComment(const ExpensiveToCopyType /* important */ S) { + // CHECK-MESSAGES: [[@LINE-1]]:68: warning: the const qualified + // CHECK-FIXES: void positiveWithComment(const ExpensiveToCopyType& /* important */ S) { +} + +void positiveAndNegative(const ExpensiveToCopyType ConstCopy, const ExpensiveToCopyType& ConstRef, ExpensiveToCopyType Copy); +// CHECK-FIXES: void positiveAndNegative(const ExpensiveToCopyType& ConstCopy, const ExpensiveToCopyType& ConstRef, const ExpensiveToCopyType& Copy); +void positiveAndNegative(const ExpensiveToCopyType ConstCopy, const ExpensiveToCopyType& ConstRef, ExpensiveToCopyType Copy) { + // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the const qualified parameter 'ConstCopy' + // CHECK-MESSAGES: [[@LINE-2]]:120: warning: the parameter 'Copy' + // CHECK-FIXES: void positiveAndNegative(const ExpensiveToCopyType& ConstCopy, const ExpensiveToCopyType& ConstRef, const ExpensiveToCopyType& Copy) { +} + +struct PositiveConstValueConstructor { + PositiveConstValueConstructor(const ExpensiveToCopyType ConstCopy) {} + // CHECK-MESSAGES: [[@LINE-1]]:59: warning: the const qualified parameter 'ConstCopy' +}; + +template void templateWithNonTemplatizedParameter(const ExpensiveToCopyType S, T V) { + // CHECK-MESSAGES: [[@LINE-1]]:90: warning: the const qualified parameter 'S' + // CHECK-FIXES: template void templateWithNonTemplatizedParameter(const ExpensiveToCopyType& S, T V) { +} + +void instantiated() { + templateWithNonTemplatizedParameter(ExpensiveToCopyType(), ExpensiveToCopyType()); + templateWithNonTemplatizedParameter(ExpensiveToCopyType(), 5); +} + +template void negativeTemplateType(const T V) { +} + +void negativeArray(const ExpensiveToCopyType[]) { +} + +void negativePointer(ExpensiveToCopyType* Obj) { +} + +void negativeConstPointer(const ExpensiveToCopyType* Obj) { +} + +void negativeConstReference(const ExpensiveToCopyType& Obj) { +} + +void negativeReference(ExpensiveToCopyType& Obj) { +} + +void negativeUniversalReference(ExpensiveToCopyType&& Obj) { +} + +void negativeSomewh
[clang-tools-extra] r268352 - [clang-tidy] ProTypeMemberInitCheck - check that field decls do not have in-class initializer.
Author: flx Date: Mon May 2 20:41:19 2016 New Revision: 268352 URL: http://llvm.org/viewvc/llvm-project?rev=268352&view=rev Log: [clang-tidy] ProTypeMemberInitCheck - check that field decls do not have in-class initializer. Reviewers: alexfh, JVApen, aaron.ballman Subscribers: flx, aaron.ballman, cfe-commits Differential Revision: http://reviews.llvm.org/D18300 Modified: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp Modified: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp?rev=268352&r1=268351&r2=268352&view=diff == --- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp (original) +++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp Mon May 2 20:41:19 2016 @@ -31,6 +31,8 @@ void fieldsRequiringInit(const RecordDec ASTContext &Context, SmallPtrSetImpl &FieldsToInit) { for (const FieldDecl *F : Fields) { +if (F->hasInClassInitializer()) + continue; QualType Type = F->getType(); if (!F->hasInClassInitializer() && type_traits::isTriviallyDefaultConstructible(Type, Context)) Modified: clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp?rev=268352&r1=268351&r2=268352&view=diff == --- clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp (original) +++ clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp Mon May 2 20:41:19 2016 @@ -85,6 +85,14 @@ struct NegativeInitializedInBody { int I; }; +struct A {}; +template class AA; +template class NegativeTemplateConstructor { + NegativeTemplateConstructor(const AA &, A) {} + bool Bool{false}; + // CHECK-FIXES: bool Bool{false}; +}; + #define UNINITIALIZED_FIELD_IN_MACRO_BODY(FIELD) \ struct UninitializedField##FIELD { \ UninitializedField##FIELD() {} \ ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D18300: [clang-tidy] ProTypeMemberInitCheck - check that field decls do not have in-class initializer
This revision was automatically updated to reflect the committed changes. Closed by commit rL268352: [clang-tidy] ProTypeMemberInitCheck - check that field decls do not have in… (authored by flx). Changed prior to commit: http://reviews.llvm.org/D18300?vs=51123&id=55934#toc Repository: rL LLVM http://reviews.llvm.org/D18300 Files: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp Index: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp === --- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp @@ -31,6 +31,8 @@ ASTContext &Context, SmallPtrSetImpl &FieldsToInit) { for (const FieldDecl *F : Fields) { +if (F->hasInClassInitializer()) + continue; QualType Type = F->getType(); if (!F->hasInClassInitializer() && type_traits::isTriviallyDefaultConstructible(Type, Context)) Index: clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp === --- clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp +++ clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp @@ -85,6 +85,14 @@ int I; }; +struct A {}; +template class AA; +template class NegativeTemplateConstructor { + NegativeTemplateConstructor(const AA &, A) {} + bool Bool{false}; + // CHECK-FIXES: bool Bool{false}; +}; + #define UNINITIALIZED_FIELD_IN_MACRO_BODY(FIELD) \ struct UninitializedField##FIELD { \ UninitializedField##FIELD() {} \ Index: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp === --- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp @@ -31,6 +31,8 @@ ASTContext &Context, SmallPtrSetImpl &FieldsToInit) { for (const FieldDecl *F : Fields) { +if (F->hasInClassInitializer()) + continue; QualType Type = F->getType(); if (!F->hasInClassInitializer() && type_traits::isTriviallyDefaultConstructible(Type, Context)) Index: clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp === --- clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp +++ clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp @@ -85,6 +85,14 @@ int I; }; +struct A {}; +template class AA; +template class NegativeTemplateConstructor { + NegativeTemplateConstructor(const AA &, A) {} + bool Bool{false}; + // CHECK-FIXES: bool Bool{false}; +}; + #define UNINITIALIZED_FIELD_IN_MACRO_BODY(FIELD) \ struct UninitializedField##FIELD { \ UninitializedField##FIELD() {} \ ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D19849: [clang-tidy] MoveConstructorInitCheck - Add parameter name to check message.
flx created this revision. flx added a reviewer: alexfh. flx added a subscriber: cfe-commits. flx set the repository for this revision to rL LLVM. Repository: rL LLVM http://reviews.llvm.org/D19849 Files: clang-tidy/misc/MoveConstructorInitCheck.cpp test/clang-tidy/misc-move-constructor-init.cpp Index: test/clang-tidy/misc-move-constructor-init.cpp === --- test/clang-tidy/misc-move-constructor-init.cpp +++ test/clang-tidy/misc-move-constructor-init.cpp @@ -96,7 +96,7 @@ struct Positive { Positive(Movable M) : M_(M) {} - // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument can be moved to avoid copy [misc-move-constructor-init] + // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument M can be moved to avoid copy [misc-move-constructor-init] // CHECK-FIXES: Positive(Movable M) : M_(std::move(M)) {} Movable M_; }; Index: clang-tidy/misc/MoveConstructorInitCheck.cpp === --- clang-tidy/misc/MoveConstructorInitCheck.cpp +++ clang-tidy/misc/MoveConstructorInitCheck.cpp @@ -109,8 +109,9 @@ if (parmVarDeclRefExprOccurences(*MovableParam, *ConstructorDecl, *Result.Context) > 1) return; - auto DiagOut = - diag(InitArg->getLocStart(), "value argument can be moved to avoid copy"); + auto DiagOut = diag(InitArg->getLocStart(), + "value argument %0 can be moved to avoid copy") + << MovableParam->getName(); DiagOut << FixItHint::CreateReplacement( InitArg->getSourceRange(), (Twine("std::move(") + MovableParam->getName() + ")").str()); Index: test/clang-tidy/misc-move-constructor-init.cpp === --- test/clang-tidy/misc-move-constructor-init.cpp +++ test/clang-tidy/misc-move-constructor-init.cpp @@ -96,7 +96,7 @@ struct Positive { Positive(Movable M) : M_(M) {} - // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument can be moved to avoid copy [misc-move-constructor-init] + // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument M can be moved to avoid copy [misc-move-constructor-init] // CHECK-FIXES: Positive(Movable M) : M_(std::move(M)) {} Movable M_; }; Index: clang-tidy/misc/MoveConstructorInitCheck.cpp === --- clang-tidy/misc/MoveConstructorInitCheck.cpp +++ clang-tidy/misc/MoveConstructorInitCheck.cpp @@ -109,8 +109,9 @@ if (parmVarDeclRefExprOccurences(*MovableParam, *ConstructorDecl, *Result.Context) > 1) return; - auto DiagOut = - diag(InitArg->getLocStart(), "value argument can be moved to avoid copy"); + auto DiagOut = diag(InitArg->getLocStart(), + "value argument %0 can be moved to avoid copy") + << MovableParam->getName(); DiagOut << FixItHint::CreateReplacement( InitArg->getSourceRange(), (Twine("std::move(") + MovableParam->getName() + ")").str()); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19849: [clang-tidy] MoveConstructorInitCheck - Add parameter name to check message.
flx removed rL LLVM as the repository for this revision. flx updated this revision to Diff 55975. http://reviews.llvm.org/D19849 Files: clang-tidy/misc/MoveConstructorInitCheck.cpp test/clang-tidy/misc-move-constructor-init.cpp Index: test/clang-tidy/misc-move-constructor-init.cpp === --- test/clang-tidy/misc-move-constructor-init.cpp +++ test/clang-tidy/misc-move-constructor-init.cpp @@ -96,7 +96,7 @@ struct Positive { Positive(Movable M) : M_(M) {} - // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument can be moved to avoid copy [misc-move-constructor-init] + // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument 'M' can be moved to avoid copy [misc-move-constructor-init] // CHECK-FIXES: Positive(Movable M) : M_(std::move(M)) {} Movable M_; }; Index: clang-tidy/misc/MoveConstructorInitCheck.cpp === --- clang-tidy/misc/MoveConstructorInitCheck.cpp +++ clang-tidy/misc/MoveConstructorInitCheck.cpp @@ -109,8 +109,9 @@ if (parmVarDeclRefExprOccurences(*MovableParam, *ConstructorDecl, *Result.Context) > 1) return; - auto DiagOut = - diag(InitArg->getLocStart(), "value argument can be moved to avoid copy"); + auto DiagOut = diag(InitArg->getLocStart(), + "value argument %0 can be moved to avoid copy") + << MovableParam; DiagOut << FixItHint::CreateReplacement( InitArg->getSourceRange(), (Twine("std::move(") + MovableParam->getName() + ")").str()); Index: test/clang-tidy/misc-move-constructor-init.cpp === --- test/clang-tidy/misc-move-constructor-init.cpp +++ test/clang-tidy/misc-move-constructor-init.cpp @@ -96,7 +96,7 @@ struct Positive { Positive(Movable M) : M_(M) {} - // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument can be moved to avoid copy [misc-move-constructor-init] + // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument 'M' can be moved to avoid copy [misc-move-constructor-init] // CHECK-FIXES: Positive(Movable M) : M_(std::move(M)) {} Movable M_; }; Index: clang-tidy/misc/MoveConstructorInitCheck.cpp === --- clang-tidy/misc/MoveConstructorInitCheck.cpp +++ clang-tidy/misc/MoveConstructorInitCheck.cpp @@ -109,8 +109,9 @@ if (parmVarDeclRefExprOccurences(*MovableParam, *ConstructorDecl, *Result.Context) > 1) return; - auto DiagOut = - diag(InitArg->getLocStart(), "value argument can be moved to avoid copy"); + auto DiagOut = diag(InitArg->getLocStart(), + "value argument %0 can be moved to avoid copy") + << MovableParam; DiagOut << FixItHint::CreateReplacement( InitArg->getSourceRange(), (Twine("std::move(") + MovableParam->getName() + ")").str()); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19849: [clang-tidy] MoveConstructorInitCheck - Add parameter name to check message.
flx marked an inline comment as done. flx added a comment. Done. http://reviews.llvm.org/D19849 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19849: [clang-tidy] MoveConstructorInitCheck - Add parameter name to check message.
flx added a comment. In http://reviews.llvm.org/D19849#419751, @aaron.ballman wrote: > I'm not opposed to showing the name, but I'm not certain I understand under > what circumstances the name would be useful. Since this is triggering on move > constructors, and move constructors can only have one parameter, the name > seems wholly redundant, isn't it? The case this is covering is when a value parameter can be moved, of which there can be many. http://reviews.llvm.org/D19849 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D19865: [clang-tidy] - PerformanceUnnecesaryCopyInitialization - only trigger for decl stmts with single VarDecl.
flx created this revision. flx added a reviewer: alexfh. flx added a subscriber: cfe-commits. flx set the repository for this revision to rL LLVM. This fixes bug: https://llvm.org/bugs/show_bug.cgi?id=27325 Repository: rL LLVM http://reviews.llvm.org/D19865 Files: clang-tidy/performance/UnnecessaryCopyInitialization.cpp test/clang-tidy/performance-unnecessary-copy-initialization.cpp Index: test/clang-tidy/performance-unnecessary-copy-initialization.cpp === --- test/clang-tidy/performance-unnecessary-copy-initialization.cpp +++ test/clang-tidy/performance-unnecessary-copy-initialization.cpp @@ -338,3 +338,8 @@ WeirdCopyCtorType neg_weird_1(orig, false); WeirdCopyCtorType neg_weird_2(orig, true); } + +void NegativeMultiDeclStmt() { + ExpensiveToCopyType orig; + ExpensiveToCopyType copy = orig, copy2; +} Index: clang-tidy/performance/UnnecessaryCopyInitialization.cpp === --- clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -56,16 +56,15 @@ auto localVarCopiedFrom = [](const internal::Matcher &CopyCtorArg) { return compoundStmt( - forEachDescendant( + forEachDescendant(declStmt(hasSingleDecl( varDecl(hasLocalStorage(), hasType(matchers::isExpensiveToCopy()), hasInitializer(cxxConstructExpr( hasDeclaration(cxxConstructorDecl( isCopyConstructor())), hasArgument(0, CopyCtorArg)) .bind("ctorCall"))) - .bind("newVarDecl"))) -.bind("blockStmt"); + .bind("newVarDecl").bind("blockStmt"); }; Finder->addMatcher( Index: test/clang-tidy/performance-unnecessary-copy-initialization.cpp === --- test/clang-tidy/performance-unnecessary-copy-initialization.cpp +++ test/clang-tidy/performance-unnecessary-copy-initialization.cpp @@ -338,3 +338,8 @@ WeirdCopyCtorType neg_weird_1(orig, false); WeirdCopyCtorType neg_weird_2(orig, true); } + +void NegativeMultiDeclStmt() { + ExpensiveToCopyType orig; + ExpensiveToCopyType copy = orig, copy2; +} Index: clang-tidy/performance/UnnecessaryCopyInitialization.cpp === --- clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -56,16 +56,15 @@ auto localVarCopiedFrom = [](const internal::Matcher &CopyCtorArg) { return compoundStmt( - forEachDescendant( + forEachDescendant(declStmt(hasSingleDecl( varDecl(hasLocalStorage(), hasType(matchers::isExpensiveToCopy()), hasInitializer(cxxConstructExpr( hasDeclaration(cxxConstructorDecl( isCopyConstructor())), hasArgument(0, CopyCtorArg)) .bind("ctorCall"))) - .bind("newVarDecl"))) -.bind("blockStmt"); + .bind("newVarDecl").bind("blockStmt"); }; Finder->addMatcher( ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19865: [clang-tidy] - PerformanceUnnecesaryCopyInitialization - only trigger for decl stmts with single VarDecl.
flx added a comment. In http://reviews.llvm.org/D19865#419830, @alexfh wrote: > Is it a workaround to avoid breaking the code by incorrect fixes? Yes. We can't simply change the type of DeclStmt when we only look one of the VarDecls and how it is initialized. Repository: rL LLVM http://reviews.llvm.org/D19865 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] r268461 - [clang-tidy] MoveConstructorInitCheck - Add parameter name to check message.
Author: flx Date: Tue May 3 18:07:44 2016 New Revision: 268461 URL: http://llvm.org/viewvc/llvm-project?rev=268461&view=rev Log: [clang-tidy] MoveConstructorInitCheck - Add parameter name to check message. Reviewers: alexfh Subscribers: aaron.ballman, cfe-commits Differential Revision: http://reviews.llvm.org/D19849 Modified: clang-tools-extra/trunk/clang-tidy/misc/MoveConstructorInitCheck.cpp clang-tools-extra/trunk/test/clang-tidy/misc-move-constructor-init.cpp Modified: clang-tools-extra/trunk/clang-tidy/misc/MoveConstructorInitCheck.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/MoveConstructorInitCheck.cpp?rev=268461&r1=268460&r2=268461&view=diff == --- clang-tools-extra/trunk/clang-tidy/misc/MoveConstructorInitCheck.cpp (original) +++ clang-tools-extra/trunk/clang-tidy/misc/MoveConstructorInitCheck.cpp Tue May 3 18:07:44 2016 @@ -109,8 +109,9 @@ void MoveConstructorInitCheck::handlePar if (parmVarDeclRefExprOccurences(*MovableParam, *ConstructorDecl, *Result.Context) > 1) return; - auto DiagOut = - diag(InitArg->getLocStart(), "value argument can be moved to avoid copy"); + auto DiagOut = diag(InitArg->getLocStart(), + "value argument %0 can be moved to avoid copy") + << MovableParam; DiagOut << FixItHint::CreateReplacement( InitArg->getSourceRange(), (Twine("std::move(") + MovableParam->getName() + ")").str()); Modified: clang-tools-extra/trunk/test/clang-tidy/misc-move-constructor-init.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/misc-move-constructor-init.cpp?rev=268461&r1=268460&r2=268461&view=diff == --- clang-tools-extra/trunk/test/clang-tidy/misc-move-constructor-init.cpp (original) +++ clang-tools-extra/trunk/test/clang-tidy/misc-move-constructor-init.cpp Tue May 3 18:07:44 2016 @@ -96,7 +96,7 @@ struct TriviallyCopyable { struct Positive { Positive(Movable M) : M_(M) {} - // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument can be moved to avoid copy [misc-move-constructor-init] + // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument 'M' can be moved to avoid copy [misc-move-constructor-init] // CHECK-FIXES: Positive(Movable M) : M_(std::move(M)) {} Movable M_; }; ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19849: [clang-tidy] MoveConstructorInitCheck - Add parameter name to check message.
This revision was automatically updated to reflect the committed changes. Closed by commit rL268461: [clang-tidy] MoveConstructorInitCheck - Add parameter name to check message. (authored by flx). Changed prior to commit: http://reviews.llvm.org/D19849?vs=55975&id=56076#toc Repository: rL LLVM http://reviews.llvm.org/D19849 Files: clang-tools-extra/trunk/clang-tidy/misc/MoveConstructorInitCheck.cpp clang-tools-extra/trunk/test/clang-tidy/misc-move-constructor-init.cpp Index: clang-tools-extra/trunk/test/clang-tidy/misc-move-constructor-init.cpp === --- clang-tools-extra/trunk/test/clang-tidy/misc-move-constructor-init.cpp +++ clang-tools-extra/trunk/test/clang-tidy/misc-move-constructor-init.cpp @@ -96,7 +96,7 @@ struct Positive { Positive(Movable M) : M_(M) {} - // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument can be moved to avoid copy [misc-move-constructor-init] + // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument 'M' can be moved to avoid copy [misc-move-constructor-init] // CHECK-FIXES: Positive(Movable M) : M_(std::move(M)) {} Movable M_; }; Index: clang-tools-extra/trunk/clang-tidy/misc/MoveConstructorInitCheck.cpp === --- clang-tools-extra/trunk/clang-tidy/misc/MoveConstructorInitCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/misc/MoveConstructorInitCheck.cpp @@ -109,8 +109,9 @@ if (parmVarDeclRefExprOccurences(*MovableParam, *ConstructorDecl, *Result.Context) > 1) return; - auto DiagOut = - diag(InitArg->getLocStart(), "value argument can be moved to avoid copy"); + auto DiagOut = diag(InitArg->getLocStart(), + "value argument %0 can be moved to avoid copy") + << MovableParam; DiagOut << FixItHint::CreateReplacement( InitArg->getSourceRange(), (Twine("std::move(") + MovableParam->getName() + ")").str()); Index: clang-tools-extra/trunk/test/clang-tidy/misc-move-constructor-init.cpp === --- clang-tools-extra/trunk/test/clang-tidy/misc-move-constructor-init.cpp +++ clang-tools-extra/trunk/test/clang-tidy/misc-move-constructor-init.cpp @@ -96,7 +96,7 @@ struct Positive { Positive(Movable M) : M_(M) {} - // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument can be moved to avoid copy [misc-move-constructor-init] + // CHECK-MESSAGES: [[@LINE-1]]:28: warning: value argument 'M' can be moved to avoid copy [misc-move-constructor-init] // CHECK-FIXES: Positive(Movable M) : M_(std::move(M)) {} Movable M_; }; Index: clang-tools-extra/trunk/clang-tidy/misc/MoveConstructorInitCheck.cpp === --- clang-tools-extra/trunk/clang-tidy/misc/MoveConstructorInitCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/misc/MoveConstructorInitCheck.cpp @@ -109,8 +109,9 @@ if (parmVarDeclRefExprOccurences(*MovableParam, *ConstructorDecl, *Result.Context) > 1) return; - auto DiagOut = - diag(InitArg->getLocStart(), "value argument can be moved to avoid copy"); + auto DiagOut = diag(InitArg->getLocStart(), + "value argument %0 can be moved to avoid copy") + << MovableParam; DiagOut << FixItHint::CreateReplacement( InitArg->getSourceRange(), (Twine("std::move(") + MovableParam->getName() + ")").str()); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19865: [clang-tidy] - PerformanceUnnecesaryCopyInitialization - only trigger for decl stmts with single VarDecl.
flx added a comment. In http://reviews.llvm.org/D19865#419905, @flx wrote: > In http://reviews.llvm.org/D19865#419830, @alexfh wrote: > > > Is it a workaround to avoid breaking the code by incorrect fixes? > > > Yes. We can't simply change the type of DeclStmt when we only look one of the > VarDecls and how it is initialized. Also, all tests still pass. Alex, do you have any particular concern with this approach? Repository: rL LLVM http://reviews.llvm.org/D19865 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D20010: [clang-tidy] UnnecessaryCopyInitialization - Extend to trigger on non-const "this" object argument if it is not modified
flx created this revision. flx added a subscriber: cfe-commits. flx set the repository for this revision to rL LLVM. Also trigger the check in the following case: void foo() { ExpensiveToCopy Obj; const auto UnnecessaryCopy = Obj.constReference(); Obj.onlyUsedAsConst(); } i.e. when the object the method is called on is not const but is never modified. Repository: rL LLVM http://reviews.llvm.org/D20010 Files: clang-tidy/performance/UnnecessaryCopyInitialization.cpp clang-tidy/performance/UnnecessaryCopyInitialization.h test/clang-tidy/performance-unnecessary-copy-initialization.cpp Index: test/clang-tidy/performance-unnecessary-copy-initialization.cpp === --- test/clang-tidy/performance-unnecessary-copy-initialization.cpp +++ test/clang-tidy/performance-unnecessary-copy-initialization.cpp @@ -174,33 +174,57 @@ } } -void NegativeMethodCallNonConstRef(ExpensiveToCopyType &Obj) { +void PositiveMethodCallNonConstRefNotModified(ExpensiveToCopyType &Obj) { const auto AutoAssigned = Obj.reference(); - const auto AutoCopyConstructed(Obj.reference()); - const ExpensiveToCopyType VarAssigned = Obj.reference(); - const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const + // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); } -void NegativeMethodCallNonConst(ExpensiveToCopyType Obj) { +void NegativeMethodCallNonConstRefIsModified(ExpensiveToCopyType &Obj) { const auto AutoAssigned = Obj.reference(); const auto AutoCopyConstructed(Obj.reference()); const ExpensiveToCopyType VarAssigned = Obj.reference(); const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); + mutate(&Obj); +} + +void PositiveMethodCallNonConstNotModified(ExpensiveToCopyType Obj) { + const auto AutoAssigned = Obj.reference(); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const + // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); +} + +void NegativeMethodCallNonConstValueArgumentIsModified(ExpensiveToCopyType Obj) { + Obj.nonConstMethod(); + const auto AutoAssigned = Obj.reference(); } -void NegativeMethodCallNonConstPointer(ExpensiveToCopyType *const Obj) { +void PositiveMethodCallNonConstPointerNotModified(ExpensiveToCopyType *const Obj) { + const auto AutoAssigned = Obj->reference(); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const + // CHECK-FIXES: const auto& AutoAssigned = Obj->reference(); + Obj->constMethod(); +} + +void NegativeMethodCallNonConstPointerIsModified(ExpensiveToCopyType *const Obj) { const auto AutoAssigned = Obj->reference(); const auto AutoCopyConstructed(Obj->reference()); const ExpensiveToCopyType VarAssigned = Obj->reference(); const ExpensiveToCopyType VarCopyConstructed(Obj->reference()); + mutate(Obj); +} + +void PositiveLocalVarIsNotModified() { + ExpensiveToCopyType LocalVar; + const auto AutoAssigned = LocalVar.reference(); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const + // CHECK-FIXES: const auto& AutoAssigned = LocalVar.reference(); } -void NegativeObjIsNotParam() { +void NegativeLocalVarIsModified() { ExpensiveToCopyType Obj; const auto AutoAssigned = Obj.reference(); - const auto AutoCopyConstructed(Obj.reference()); - ExpensiveToCopyType VarAssigned = Obj.reference(); - ExpensiveToCopyType VarCopyConstructed(Obj.reference()); + Obj = AutoAssigned; } struct NegativeConstructor { Index: clang-tidy/performance/UnnecessaryCopyInitialization.h === --- clang-tidy/performance/UnnecessaryCopyInitialization.h +++ clang-tidy/performance/UnnecessaryCopyInitialization.h @@ -33,6 +33,7 @@ private: void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt, + const VarDecl *ObjectArg, ASTContext &Context); void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt, ASTContext &Context); Index: clang-tidy/performance/UnnecessaryCopyInitialization.cpp === --- clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -42,14 +42,14 @@ unless(allOf(pointerType(), unless(pointerType(pointee( qualType(isConstQualified(; - // Match method call expressions where the this argument is a const - // type or const reference. This returned const reference is highly likely to - // outlive the local const reference of the variable being declared. - // The assumption is that the const reference being returned either points - // to a global static variable or to a member of the called object. - auto ConstRefReturningMethodCallOfConstParam = cxxMemberCallExpr( + // Matc
Re: [PATCH] D19865: [clang-tidy] - PerformanceUnnecesaryCopyInitialization - only trigger for decl stmts with single VarDecl.
flx added a comment. In http://reviews.llvm.org/D19865#423140, @flx wrote: > In http://reviews.llvm.org/D19865#419905, @flx wrote: > > > In http://reviews.llvm.org/D19865#419830, @alexfh wrote: > > > > > Is it a workaround to avoid breaking the code by incorrect fixes? > > > > > > Yes. We can't simply change the type of DeclStmt when we only look one of > > the VarDecls and how it is initialized. > > > Also, all tests still pass. Alex, do you have any particular concern with > this approach? In http://reviews.llvm.org/D19865#423286, @alexfh wrote: > In http://reviews.llvm.org/D19865#423140, @flx wrote: > > > In http://reviews.llvm.org/D19865#419905, @flx wrote: > > > > > In http://reviews.llvm.org/D19865#419830, @alexfh wrote: > > > > > > > Is it a workaround to avoid breaking the code by incorrect fixes? > > > > > > > > > Yes. We can't simply change the type of DeclStmt when we only look one of > > > the VarDecls and how it is initialized. > > > > > > Also, all tests still pass. Alex, do you have any particular concern with > > this approach? > > > Even if we can't easily provide an automated fix (we could teach the check to > split declarations, but it might not worth the effort), we could still emit a > warning. WDYT? Sounds good. Done. We now still issue the warning, but don't issue fixes when it's not a single decl. http://reviews.llvm.org/D19865 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19865: [clang-tidy] - PerformanceUnnecesaryCopyInitialization - only trigger for decl stmts with single VarDecl.
flx removed rL LLVM as the repository for this revision. flx updated this revision to Diff 56573. http://reviews.llvm.org/D19865 Files: clang-tidy/performance/UnnecessaryCopyInitialization.cpp clang-tidy/performance/UnnecessaryCopyInitialization.h test/clang-tidy/performance-unnecessary-copy-initialization.cpp Index: test/clang-tidy/performance-unnecessary-copy-initialization.cpp === --- test/clang-tidy/performance-unnecessary-copy-initialization.cpp +++ test/clang-tidy/performance-unnecessary-copy-initialization.cpp @@ -338,3 +338,10 @@ WeirdCopyCtorType neg_weird_1(orig, false); WeirdCopyCtorType neg_weird_2(orig, true); } + +void WarningOnlyMultiDeclStmt() { + ExpensiveToCopyType orig; + ExpensiveToCopyType copy = orig, copy2; + // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy' of the variable 'orig' is never modified; consider avoiding the copy [performance-unnecessary-copy-initialization] + // CHECK-FIXES: ExpensiveToCopyType copy = orig, copy2; +} Index: clang-tidy/performance/UnnecessaryCopyInitialization.h === --- clang-tidy/performance/UnnecessaryCopyInitialization.h +++ clang-tidy/performance/UnnecessaryCopyInitialization.h @@ -33,9 +33,10 @@ private: void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt, - ASTContext &Context); + bool IssueFix, ASTContext &Context); void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar, - const Stmt &BlockStmt, ASTContext &Context); + const Stmt &BlockStmt, bool IssueFix, + ASTContext &Context); }; } // namespace performance Index: clang-tidy/performance/UnnecessaryCopyInitialization.cpp === --- clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -20,10 +20,6 @@ void recordFixes(const VarDecl &Var, ASTContext &Context, DiagnosticBuilder &Diagnostic) { - // Do not propose fixes in macros since we cannot place them correctly. - if (Var.getLocation().isMacroID()) -return; - Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context); if (!Var.getType().isLocalConstQualified()) Diagnostic << utils::fixit::changeVarDeclToConst(Var); @@ -57,14 +53,16 @@ auto localVarCopiedFrom = [](const internal::Matcher &CopyCtorArg) { return compoundStmt( forEachDescendant( - varDecl(hasLocalStorage(), - hasType(matchers::isExpensiveToCopy()), - hasInitializer(cxxConstructExpr( - hasDeclaration(cxxConstructorDecl( - isCopyConstructor())), - hasArgument(0, CopyCtorArg)) - .bind("ctorCall"))) - .bind("newVarDecl"))) + declStmt( + has(varDecl(hasLocalStorage(), + hasType(matchers::isExpensiveToCopy()), + hasInitializer( + cxxConstructExpr( + hasDeclaration(cxxConstructorDecl( + isCopyConstructor())), + hasArgument(0, CopyCtorArg)) + .bind("ctorCall"))) + .bind("newVarDecl"))).bind("declStmt"))) .bind("blockStmt"); }; @@ -84,6 +82,11 @@ const auto *OldVar = Result.Nodes.getNodeAs("oldVarDecl"); const auto *BlockStmt = Result.Nodes.getNodeAs("blockStmt"); const auto *CtorCall = Result.Nodes.getNodeAs("ctorCall"); + // Do not propose fixes if the DeclStmt has multiple VarDecls or in macros + // since we cannot place them correctly. + bool IssueFix = + Result.Nodes.getNodeAs("declStmt")->isSingleDecl() && + !NewVar->getLocation().isMacroID(); // A constructor that looks like T(const T& t, bool arg = false) counts as a // copy only when it is called with default arguments for the arguments after @@ -93,14 +96,16 @@ return; if (OldVar == nullptr) { -handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Result.Context); +handleCopyFromMethodReturn(*NewVar, *BlockStmt, IssueFix, *Result.Context); } else { -handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Result.Context); +handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, IssueFix, + *Result.Context); } } void UnnecessaryCopyInitialization::handleCopyFromMethodReturn
[PATCH] D20170: [clang-tidy] TypeTraits - Type is not expensive to copy when it has a deleted copy constructor.
flx created this revision. flx added reviewers: alexfh, sbenza. flx added a subscriber: cfe-commits. flx set the repository for this revision to rL LLVM. Repository: rL LLVM http://reviews.llvm.org/D20170 Files: clang-tidy/utils/TypeTraits.cpp test/clang-tidy/performance-unnecessary-value-param.cpp Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -23,6 +23,12 @@ SomewhatTrivial& operator=(const SomewhatTrivial&); }; +struct MoveOnlyType { + MoveOnlyType(const MoveOnlyType&) = delete; + ~MoveOnlyType(); + void constMethod() const; +}; + void positiveExpensiveConstValue(const ExpensiveToCopyType Obj); // CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj); void positiveExpensiveConstValue(const ExpensiveToCopyType Obj) { @@ -169,3 +175,7 @@ NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete; // CHECK-FIXES: NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete; }; + +void NegativeMoveOnlyTypePassedByValue(MoveOnlyType M) { + M.constMethod(); +} Index: clang-tidy/utils/TypeTraits.cpp === --- clang-tidy/utils/TypeTraits.cpp +++ clang-tidy/utils/TypeTraits.cpp @@ -10,26 +10,42 @@ #include "TypeTraits.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" namespace clang { namespace tidy { namespace utils { namespace type_traits { +using namespace ::clang::ast_matchers; + namespace { bool classHasTrivialCopyAndDestroy(QualType Type) { auto *Record = Type->getAsCXXRecordDecl(); return Record && Record->hasDefinition() && !Record->hasNonTrivialCopyConstructor() && !Record->hasNonTrivialDestructor(); } + +bool hasDeletedCopyConstructor(QualType Type, ASTContext &Context) { + auto *Record = Type->getAsCXXRecordDecl(); + if (Record == nullptr || !Record->hasDefinition()) +return false; + auto Matches = match(cxxRecordDecl(hasMethod( + cxxConstructorDecl(isCopyConstructor(), isDeleted()) + .bind("constructor"))), + *Record, Context); + return !Matches.empty(); +} + } // namespace llvm::Optional isExpensiveToCopy(QualType Type, ASTContext &Context) { if (Type->isDependentType()) return llvm::None; return !Type.isTriviallyCopyableType(Context) && - !classHasTrivialCopyAndDestroy(Type); + !classHasTrivialCopyAndDestroy(Type) && + !hasDeletedCopyConstructor(Type, Context); } bool recordIsTriviallyDefaultConstructible(const RecordDecl &RecordDecl, Index: test/clang-tidy/performance-unnecessary-value-param.cpp === --- test/clang-tidy/performance-unnecessary-value-param.cpp +++ test/clang-tidy/performance-unnecessary-value-param.cpp @@ -23,6 +23,12 @@ SomewhatTrivial& operator=(const SomewhatTrivial&); }; +struct MoveOnlyType { + MoveOnlyType(const MoveOnlyType&) = delete; + ~MoveOnlyType(); + void constMethod() const; +}; + void positiveExpensiveConstValue(const ExpensiveToCopyType Obj); // CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj); void positiveExpensiveConstValue(const ExpensiveToCopyType Obj) { @@ -169,3 +175,7 @@ NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete; // CHECK-FIXES: NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete; }; + +void NegativeMoveOnlyTypePassedByValue(MoveOnlyType M) { + M.constMethod(); +} Index: clang-tidy/utils/TypeTraits.cpp === --- clang-tidy/utils/TypeTraits.cpp +++ clang-tidy/utils/TypeTraits.cpp @@ -10,26 +10,42 @@ #include "TypeTraits.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" namespace clang { namespace tidy { namespace utils { namespace type_traits { +using namespace ::clang::ast_matchers; + namespace { bool classHasTrivialCopyAndDestroy(QualType Type) { auto *Record = Type->getAsCXXRecordDecl(); return Record && Record->hasDefinition() && !Record->hasNonTrivialCopyConstructor() && !Record->hasNonTrivialDestructor(); } + +bool hasDeletedCopyConstructor(QualType Type, ASTContext &Context) { + auto *Record = Type->getAsCXXRecordDecl(); + if (Record == nullptr || !Record->hasDefinition()) +return false; + auto Matches = match(cxxRecordDecl(hasMethod( + cxxConstructorDecl(isCopyConstructor(), isDeleted()) + .bind("constructor"))), + *Record, Context); + return !Matches.empty(); +} + } // namespace llvm::