diff options
author | Alexander Kornienko <alexfh@google.com> | 2016-06-16 14:32:41 +0000 |
---|---|---|
committer | Alexander Kornienko <alexfh@google.com> | 2016-06-16 14:32:41 +0000 |
commit | 28b34b043ea282523c4f1dc1db858093ab8de7ac (patch) | |
tree | 56b77f9cff853b4222b15c9c81277f4680b7f778 /clang-tools-extra/test/clang-tidy/misc-move-const-arg.cpp | |
parent | 22ec97fb24a4d16f1f6b073d7cec45314758029e (diff) | |
download | bcm5719-llvm-28b34b043ea282523c4f1dc1db858093ab8de7ac.tar.gz bcm5719-llvm-28b34b043ea282523c4f1dc1db858093ab8de7ac.zip |
[clang-tidy] misc-move-const-arg: Detect if result of std::move() is being passed as a const ref argument
Summary:
Conceptually, this is very close to the existing functionality of misc-move-const-arg, which is why I'm adding it here and not creating a new check. For example, for a type A that is both movable and copyable, this
const A a1;
A a2(std::move(a1));
is not only a case where a const argument is being passed to std::move(), but the result of std::move() is also being passed as a const reference (due to overload resolution).
The new check typically triggers (exclusively) in cases where people think they're dealing with a movable type, but in fact the type is not movable.
Reviewers: hokein, aaron.ballman, alexfh
Subscribers: aaron.ballman, cfe-commits
Patch by Martin Boehme!
Differential Revision: http://reviews.llvm.org/D21223
llvm-svn: 272896
Diffstat (limited to 'clang-tools-extra/test/clang-tidy/misc-move-const-arg.cpp')
-rw-r--r-- | clang-tools-extra/test/clang-tidy/misc-move-const-arg.cpp | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/clang-tools-extra/test/clang-tidy/misc-move-const-arg.cpp b/clang-tools-extra/test/clang-tidy/misc-move-const-arg.cpp index beb4078bdbe..d39f7258e62 100644 --- a/clang-tools-extra/test/clang-tidy/misc-move-const-arg.cpp +++ b/clang-tools-extra/test/clang-tidy/misc-move-const-arg.cpp @@ -71,3 +71,90 @@ void f11() { f10<int>(1); f10<double>(1); } + +class NoMoveSemantics { + public: + NoMoveSemantics(); + NoMoveSemantics(const NoMoveSemantics &); + + NoMoveSemantics &operator=(const NoMoveSemantics &); +}; + +void callByConstRef(const NoMoveSemantics &); +void callByConstRef(int i, const NoMoveSemantics &); + +void moveToConstReferencePositives() { + NoMoveSemantics obj; + + // Basic case. + callByConstRef(std::move(obj)); + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as + // CHECK-FIXES: callByConstRef(obj); + + // Also works for second argument. + callByConstRef(1, std::move(obj)); + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: passing result of std::move() as + // CHECK-FIXES: callByConstRef(1, obj); + + // Works if std::move() applied to a temporary. + callByConstRef(std::move(NoMoveSemantics())); + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as + // CHECK-FIXES: callByConstRef(NoMoveSemantics()); + + // Works if calling a copy constructor. + NoMoveSemantics other(std::move(obj)); + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: passing result of std::move() as + // CHECK-FIXES: NoMoveSemantics other(obj); + + // Works if calling assignment operator. + other = std::move(obj); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing result of std::move() as + // CHECK-FIXES: other = obj; +} + +class MoveSemantics { + public: + MoveSemantics(); + MoveSemantics(MoveSemantics &&); + + MoveSemantics &operator=(MoveSemantics &&); +}; + +void callByValue(MoveSemantics); + +void callByRValueRef(MoveSemantics &&); + +template <class T> +void templateFunction(T obj) { + T other = std::move(obj); +} + +#define M3(T, obj) \ + do { \ + T other = std::move(obj); \ + } while (true) + +#define CALL(func) (func)() + +void moveToConstReferenceNegatives() { + // No warning when actual move takes place. + MoveSemantics move_semantics; + callByValue(std::move(move_semantics)); + callByRValueRef(std::move(move_semantics)); + MoveSemantics other(std::move(move_semantics)); + other = std::move(move_semantics); + + // No warning if std::move() not used. + NoMoveSemantics no_move_semantics; + callByConstRef(no_move_semantics); + + // No warning if instantiating a template. + templateFunction(no_move_semantics); + + // No warning inside of macro expansions. + M3(NoMoveSemantics, no_move_semantics); + + // No warning inside of macro expansion, even if the macro expansion is inside + // a lambda that is, in turn, an argument to a macro. + CALL([no_move_semantics] { M3(NoMoveSemantics, no_move_semantics); }); +} |