Re: r321099 - [driver][darwin] Take the OS version specified in "-target" as the target

2017-12-21 Thread Martin Böhme via cfe-commits
This is causing problems in some internal builds that specify both
-mios-simulator-version-min=9.0 and --target=x86_64-apple-ios

My expectation would be for the code to take the minimum OS version number
from the -mios-simulator-version-min flag. In fact, however, the code seems
to be completely ignoring this flag.

Is my expectation wrong or does the code need to be modified to take this
situation into account?


On 19 December 2017 at 20:05, Alex Lorenz via cfe-commits <
cfe-commits@lists.llvm.org> wrote:

> Author: arphaman
> Date: Tue Dec 19 11:05:04 2017
> New Revision: 321099
>
> URL: http://llvm.org/viewvc/llvm-project?rev=321099&view=rev
> Log:
> [driver][darwin] Take the OS version specified in "-target" as the target
> OS instead of inferring it from SDK / environment
>
> The OS version is specified in -target should be used instead of the one
> in an
> environment variable / SDK name.
>
> rdar://35813850
>
> Differential Revision: https://reviews.llvm.org/D40998
>
> Modified:
> cfe/trunk/lib/Driver/ToolChains/Darwin.cpp
> cfe/trunk/test/Driver/darwin-version.c
> cfe/trunk/test/Driver/objc-weak.m
> cfe/trunk/test/Driver/pic.c
> cfe/trunk/test/Driver/unavailable_aligned_allocation.cpp
>
> Modified: cfe/trunk/lib/Driver/ToolChains/Darwin.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/
> ToolChains/Darwin.cpp?rev=321099&r1=321098&r2=321099&view=diff
> 
> ==
> --- cfe/trunk/lib/Driver/ToolChains/Darwin.cpp (original)
> +++ cfe/trunk/lib/Driver/ToolChains/Darwin.cpp Tue Dec 19 11:05:04 2017
> @@ -1233,6 +1233,10 @@ struct DarwinPlatform {
>  llvm_unreachable("Unsupported Darwin Source Kind");
>}
>
> +  static DarwinPlatform createFromTarget(llvm::Triple::OSType OS,
> + StringRef OSVersion, Arg *A) {
> +return DarwinPlatform(TargetArg, getPlatformFromOS(OS), OSVersion, A);
> +  }
>static DarwinPlatform createOSVersionArg(DarwinPlatformKind Platform,
> Arg *A) {
>  return DarwinPlatform(OSVersionArg, Platform, A);
> @@ -1250,33 +1254,32 @@ struct DarwinPlatform {
>}
>static DarwinPlatform createFromArch(llvm::Triple::OSType OS,
> StringRef Value) {
> -DarwinPlatformKind Platform;
> +return DarwinPlatform(InferredFromArch, getPlatformFromOS(OS),
> Value);
> +  }
> +
> +private:
> +  DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, Arg
> *Argument)
> +  : Kind(Kind), Platform(Platform), Argument(Argument) {}
> +  DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, StringRef
> Value,
> + Arg *Argument = nullptr)
> +  : Kind(Kind), Platform(Platform), OSVersion(Value),
> Argument(Argument) {}
> +
> +  static DarwinPlatformKind getPlatformFromOS(llvm::Triple::OSType OS) {
>  switch (OS) {
>  case llvm::Triple::Darwin:
>  case llvm::Triple::MacOSX:
> -  Platform = DarwinPlatformKind::MacOS;
> -  break;
> +  return DarwinPlatformKind::MacOS;
>  case llvm::Triple::IOS:
> -  Platform = DarwinPlatformKind::IPhoneOS;
> -  break;
> +  return DarwinPlatformKind::IPhoneOS;
>  case llvm::Triple::TvOS:
> -  Platform = DarwinPlatformKind::TvOS;
> -  break;
> +  return DarwinPlatformKind::TvOS;
>  case llvm::Triple::WatchOS:
> -  Platform = DarwinPlatformKind::WatchOS;
> -  break;
> +  return DarwinPlatformKind::WatchOS;
>  default:
>llvm_unreachable("Unable to infer Darwin variant");
>  }
> -return DarwinPlatform(InferredFromArch, Platform, Value);
>}
>
> -private:
> -  DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, Arg
> *Argument)
> -  : Kind(Kind), Platform(Platform), Argument(Argument) {}
> -  DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, StringRef
> Value)
> -  : Kind(Kind), Platform(Platform), OSVersion(Value),
> Argument(nullptr) {}
> -
>SourceKind Kind;
>DarwinPlatformKind Platform;
>std::string OSVersion;
> @@ -1449,20 +1452,15 @@ inferDeploymentTargetFromArch(DerivedArg
>const Driver &TheDriver) {
>llvm::Triple::OSType OSTy = llvm::Triple::UnknownOS;
>
> -  // Set the OSTy based on -target if -arch isn't present.
> -  if (Args.hasArg(options::OPT_target) && !Args.hasArg(options::OPT_arch))
> {
> -OSTy = Triple.getOS();
> -  } else {
> -StringRef MachOArchName = Toolchain.getMachOArchName(Args);
> -if (MachOArchName == "armv7" || MachOArchName == "armv7s" ||
> -MachOArchName == "arm64")
> -  OSTy = llvm::Triple::IOS;
> -else if (MachOArchName == "armv7k")
> -  OSTy = llvm::Triple::WatchOS;
> -else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" &&
> - MachOArchName != "armv7em")
> -  OSTy = llvm::Triple::MacOSX;
> -  }
> +  StringRef MachOArchName = Toolc

Re: r321099 - [driver][darwin] Take the OS version specified in "-target" as the target

2017-12-21 Thread Martin Böhme via cfe-commits
Thanks for the quick response and your suggestions!

I believe the workaround you suggest in 1) will work for us, so there's no
need for an urgent change. Thanks again!

On 21 December 2017 at 20:11, Alex L  wrote:

> Thanks for raising your concerns.
>
> We decided to avoid -m-version-min flag in favor of -target to
> simplify the driver logic and to encourage the adoption of -target. Now
> after r321145 we only warn about -m-version-min flag when the OS
> version specified in it is different to the OS version specified in target,
> or when target has no OS version.
>
> There are two possible solutions here:
> 1) You can still use -target with -mios-simulator-version-min as before
> but you'd have to use '-target=x86_64-apple-darwin' to ensure that the iOS
> version specified by  '-mios-simulator-version-min' is used.
> 2) I also do have a patch that implements the logic that you propose (use
> the OS version in -m-version-min flag if target has none). If you
> believe that the first solution is not suitable for your code then I can
> commit it. At the same time I believe that we would rather not use this
> patch, but if it's urgent for your projects then maybe I can land it now
> and then we can establish some sort of timeline for when it can be reverted?
>
> Thanks,
> Alex
>
>
> On 21 December 2017 at 08:00, James Y Knight  wrote:
>
>> I think if a version number isn't explicitly specified in the -target
>> value, the value from -m-version-min ought to still be used, as
>> it was before.
>>
>> Currently, clang will ignore the -m-version-min version number
>> if the target has a particular OS specified, even if it has no version
>> number as part of it.
>>
>> (We should be able to workaround this change backwards-compatibly by
>> specifying in both the -target argument and in the -m-version-min
>> arguments, but I do think the behavior should be fixed.)
>>
>> On Thu, Dec 21, 2017 at 10:45 AM, Martin Böhme 
>> wrote:
>>
>>> This is causing problems in some internal builds that specify both
>>> -mios-simulator-version-min=9.0 and --target=x86_64-apple-ios
>>>
>>> My expectation would be for the code to take the minimum OS version
>>> number from the -mios-simulator-version-min flag. In fact, however, the
>>> code seems to be completely ignoring this flag.
>>>
>>> Is my expectation wrong or does the code need to be modified to take
>>> this situation into account?
>>>
>>>
>>> On 19 December 2017 at 20:05, Alex Lorenz via cfe-commits <
>>> cfe-commits@lists.llvm.org> wrote:
>>>
 Author: arphaman
 Date: Tue Dec 19 11:05:04 2017
 New Revision: 321099

 URL: http://llvm.org/viewvc/llvm-project?rev=321099&view=rev
 Log:
 [driver][darwin] Take the OS version specified in "-target" as the
 target
 OS instead of inferring it from SDK / environment

 The OS version is specified in -target should be used instead of the
 one in an
 environment variable / SDK name.

 rdar://35813850

 Differential Revision: https://reviews.llvm.org/D40998

 Modified:
 cfe/trunk/lib/Driver/ToolChains/Darwin.cpp
 cfe/trunk/test/Driver/darwin-version.c
 cfe/trunk/test/Driver/objc-weak.m
 cfe/trunk/test/Driver/pic.c
 cfe/trunk/test/Driver/unavailable_aligned_allocation.cpp

 Modified: cfe/trunk/lib/Driver/ToolChains/Darwin.cpp
 URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Too
 lChains/Darwin.cpp?rev=321099&r1=321098&r2=321099&view=diff
 
 ==
 --- cfe/trunk/lib/Driver/ToolChains/Darwin.cpp (original)
 +++ cfe/trunk/lib/Driver/ToolChains/Darwin.cpp Tue Dec 19 11:05:04 2017
 @@ -1233,6 +1233,10 @@ struct DarwinPlatform {
  llvm_unreachable("Unsupported Darwin Source Kind");
}

 +  static DarwinPlatform createFromTarget(llvm::Triple::OSType OS,
 + StringRef OSVersion, Arg *A) {
 +return DarwinPlatform(TargetArg, getPlatformFromOS(OS), OSVersion,
 A);
 +  }
static DarwinPlatform createOSVersionArg(DarwinPlatformKind
 Platform,
 Arg *A) {
  return DarwinPlatform(OSVersionArg, Platform, A);
 @@ -1250,33 +1254,32 @@ struct DarwinPlatform {
}
static DarwinPlatform createFromArch(llvm::Triple::OSType OS,
 StringRef Value) {
 -DarwinPlatformKind Platform;
 +return DarwinPlatform(InferredFromArch, getPlatformFromOS(OS),
 Value);
 +  }
 +
 +private:
 +  DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, Arg
 *Argument)
 +  : Kind(Kind), Platform(Platform), Argument(Argument) {}
 +  DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform,
 StringRef Value,
 + Arg *Argument = nullptr)
 +  : Kind(Kind), Pla

[PATCH] D24962: [ASTMatchers] Let registerMatcher() take a const char * instead of a StringRef

2016-09-27 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: klimek.
mboehme added a subscriber: cfe-commits.
Herald added a subscriber: klimek.

r282433 added LLVM_ATTRIBUTE_ALWAYS_INLINE to the StringRef(const char *)
constructor. This causes the size of the stack frame for
RegistryMaps::RegistryMaps() to become excessive when compiling with gcc. This
change avoids inlining the StringRef constructor for every REGISTER_MATCHER
line.

https://reviews.llvm.org/D24962

Files:
  lib/ASTMatchers/Dynamic/Registry.cpp

Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -40,11 +40,11 @@
   const ConstructorMap &constructors() const { return Constructors; }
 
 private:
-  void registerMatcher(StringRef MatcherName, MatcherDescriptor *Callback);
+  void registerMatcher(const char *MatcherName, MatcherDescriptor *Callback);
   ConstructorMap Constructors;
 };
 
-void RegistryMaps::registerMatcher(StringRef MatcherName,
+void RegistryMaps::registerMatcher(const char *MatcherName,
MatcherDescriptor *Callback) {
   assert(Constructors.find(MatcherName) == Constructors.end());
   Constructors[MatcherName] = Callback;


Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -40,11 +40,11 @@
   const ConstructorMap &constructors() const { return Constructors; }
 
 private:
-  void registerMatcher(StringRef MatcherName, MatcherDescriptor *Callback);
+  void registerMatcher(const char *MatcherName, MatcherDescriptor *Callback);
   ConstructorMap Constructors;
 };
 
-void RegistryMaps::registerMatcher(StringRef MatcherName,
+void RegistryMaps::registerMatcher(const char *MatcherName,
MatcherDescriptor *Callback) {
   assert(Constructors.find(MatcherName) == Constructors.end());
   Constructors[MatcherName] = Callback;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D24962: [ASTMatchers] Let registerMatcher() take a const char * instead of a StringRef

2016-09-27 Thread Martin Böhme via cfe-commits
mboehme abandoned this revision.
mboehme added a comment.

Abandoning after discussion with klimek.


https://reviews.llvm.org/D24962



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D25612: [clang-tidy] Add additional diagnostic to misc-use-after-move

2016-10-14 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: hokein.
mboehme added a subscriber: cfe-commits.

This adds a diagnostic to the misc-use-after-move check that is output when the
use happens on a later loop iteration than the move, for example:

  A a;
  for (int i = 0; i < 10; ++i) {
a.foo();
std::move(a);
  }

This situation can be confusing to users because, in terms of source code
location, the use is above the move. This can make it look as if the warning
is a false positive, particularly if the loop is long but the use and move are
close together.

In cases like these, misc-use-after-move will now output an additional
diagnostic:

  a.cpp:393:7: note: the use happens in a later loop iteration than the move


https://reviews.llvm.org/D25612

Files:
  clang-tidy/misc/UseAfterMoveCheck.cpp
  test/clang-tidy/misc-use-after-move.cpp


Index: test/clang-tidy/misc-use-after-move.cpp
===
--- test/clang-tidy/misc-use-after-move.cpp
+++ test/clang-tidy/misc-use-after-move.cpp
@@ -133,6 +133,7 @@
   std::move(a);
   // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'a' used after it was moved
   // CHECK-MESSAGES: [[@LINE-2]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE-3]]:17: note: the use happens in a later loop
 }
   }
 }
@@ -391,7 +392,8 @@
 for (int i = 0; i < 10; ++i) {
   a.foo();
   // CHECK-MESSAGES: [[@LINE-1]]:7: warning: 'a' used after it was moved
-  // CHECK-MESSAGES: [[@LINE+1]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE+2]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE-3]]:7: note: the use happens in a later loop
   std::move(a);
 }
   }
@@ -586,7 +588,7 @@
   }
 }
 
-// Passing the object to a function through a non-const pointer or refernce
+// Passing the object to a function through a non-const pointer or reference
 // counts as a re-initialization.
 void passByNonConstPointer(A *);
 void passByNonConstReference(A &);
Index: clang-tidy/misc/UseAfterMoveCheck.cpp
===
--- clang-tidy/misc/UseAfterMoveCheck.cpp
+++ clang-tidy/misc/UseAfterMoveCheck.cpp
@@ -562,18 +562,24 @@
 }
 
 static void emitDiagnostic(const Expr *MovingCall,
-   const ValueDecl *MovedVariable,
+   const DeclRefExpr *MoveArg,
const UseAfterMove &Use, ClangTidyCheck *Check,
ASTContext *Context) {
-  Check->diag(Use.DeclRef->getExprLoc(), "'%0' used after it was moved")
-  << MovedVariable->getName();
-  Check->diag(MovingCall->getExprLoc(), "move occurred here",
-  DiagnosticIDs::Note);
+  SourceLocation UseLoc = Use.DeclRef->getExprLoc();
+  SourceLocation MoveLoc = MovingCall->getExprLoc();
+
+  Check->diag(UseLoc, "'%0' used after it was moved")
+  << MoveArg->getDecl()->getName();
+  Check->diag(MoveLoc, "move occurred here", DiagnosticIDs::Note);
   if (Use.EvaluationOrderUndefined) {
-Check->diag(Use.DeclRef->getExprLoc(),
+Check->diag(UseLoc,
 "the use and move are unsequenced, i.e. there is no guarantee "
 "about the order in which they are evaluated",
 DiagnosticIDs::Note);
+  } else if(UseLoc < MoveLoc || Use.DeclRef == MoveArg) {
+Check->diag(UseLoc,
+"the use happens in a later loop iteration than the move",
+DiagnosticIDs::Note);
   }
 }
 
@@ -625,17 +631,15 @@
   else
 return;
 
-  const ValueDecl *MovedVariable = Arg->getDecl();
-
   // Ignore the std::move if the variable that was passed to it isn't a local
   // variable.
   if (!Arg->getDecl()->getDeclContext()->isFunctionOrMethod())
 return;
 
   UseAfterMoveFinder finder(Result.Context);
   UseAfterMove Use;
-  if (finder.find(FunctionBody, MovingCall, MovedVariable, &Use))
-emitDiagnostic(MovingCall, MovedVariable, Use, this, Result.Context);
+  if (finder.find(FunctionBody, MovingCall, Arg->getDecl(), &Use))
+emitDiagnostic(MovingCall, Arg, Use, this, Result.Context);
 }
 
 } // namespace misc


Index: test/clang-tidy/misc-use-after-move.cpp
===
--- test/clang-tidy/misc-use-after-move.cpp
+++ test/clang-tidy/misc-use-after-move.cpp
@@ -133,6 +133,7 @@
   std::move(a);
   // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'a' used after it was moved
   // CHECK-MESSAGES: [[@LINE-2]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE-3]]:17: note: the use happens in a later loop
 }
   }
 }
@@ -391,7 +392,8 @@
 for (int i = 0; i < 10; ++i) {
   a.foo();
   // CHECK-MESSAGES: [[@LINE-1]]:7: warning: 'a' used after it was moved
-  // CHECK-MESSAGES: [[@LINE+1]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE+2]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE-3]]:7: note: the use

[PATCH] D25612: [clang-tidy] Add additional diagnostic to misc-use-after-move

2016-10-14 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 74671.
mboehme added a comment.

- Responses to reviewer comments


https://reviews.llvm.org/D25612

Files:
  clang-tidy/misc/UseAfterMoveCheck.cpp
  test/clang-tidy/misc-use-after-move.cpp


Index: test/clang-tidy/misc-use-after-move.cpp
===
--- test/clang-tidy/misc-use-after-move.cpp
+++ test/clang-tidy/misc-use-after-move.cpp
@@ -133,6 +133,7 @@
   std::move(a);
   // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'a' used after it was moved
   // CHECK-MESSAGES: [[@LINE-2]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE-3]]:17: note: the use happens in a later loop
 }
   }
 }
@@ -391,7 +392,8 @@
 for (int i = 0; i < 10; ++i) {
   a.foo();
   // CHECK-MESSAGES: [[@LINE-1]]:7: warning: 'a' used after it was moved
-  // CHECK-MESSAGES: [[@LINE+1]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE+2]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE-3]]:7: note: the use happens in a later loop
   std::move(a);
 }
   }
@@ -586,7 +588,7 @@
   }
 }
 
-// Passing the object to a function through a non-const pointer or refernce
+// Passing the object to a function through a non-const pointer or reference
 // counts as a re-initialization.
 void passByNonConstPointer(A *);
 void passByNonConstReference(A &);
Index: clang-tidy/misc/UseAfterMoveCheck.cpp
===
--- clang-tidy/misc/UseAfterMoveCheck.cpp
+++ clang-tidy/misc/UseAfterMoveCheck.cpp
@@ -562,18 +562,24 @@
 }
 
 static void emitDiagnostic(const Expr *MovingCall,
-   const ValueDecl *MovedVariable,
+   const DeclRefExpr *MoveArg,
const UseAfterMove &Use, ClangTidyCheck *Check,
ASTContext *Context) {
-  Check->diag(Use.DeclRef->getExprLoc(), "'%0' used after it was moved")
-  << MovedVariable->getName();
-  Check->diag(MovingCall->getExprLoc(), "move occurred here",
-  DiagnosticIDs::Note);
+  SourceLocation UseLoc = Use.DeclRef->getExprLoc();
+  SourceLocation MoveLoc = MovingCall->getExprLoc();
+
+  Check->diag(UseLoc, "'%0' used after it was moved")
+  << MoveArg->getDecl()->getName();
+  Check->diag(MoveLoc, "move occurred here", DiagnosticIDs::Note);
   if (Use.EvaluationOrderUndefined) {
-Check->diag(Use.DeclRef->getExprLoc(),
+Check->diag(UseLoc,
 "the use and move are unsequenced, i.e. there is no guarantee "
 "about the order in which they are evaluated",
 DiagnosticIDs::Note);
+  } else if (UseLoc < MoveLoc || Use.DeclRef == MoveArg) {
+Check->diag(UseLoc,
+"the use happens in a later loop iteration than the move",
+DiagnosticIDs::Note);
   }
 }
 
@@ -625,17 +631,15 @@
   else
 return;
 
-  const ValueDecl *MovedVariable = Arg->getDecl();
-
   // Ignore the std::move if the variable that was passed to it isn't a local
   // variable.
   if (!Arg->getDecl()->getDeclContext()->isFunctionOrMethod())
 return;
 
   UseAfterMoveFinder finder(Result.Context);
   UseAfterMove Use;
-  if (finder.find(FunctionBody, MovingCall, MovedVariable, &Use))
-emitDiagnostic(MovingCall, MovedVariable, Use, this, Result.Context);
+  if (finder.find(FunctionBody, MovingCall, Arg->getDecl(), &Use))
+emitDiagnostic(MovingCall, Arg, Use, this, Result.Context);
 }
 
 } // namespace misc


Index: test/clang-tidy/misc-use-after-move.cpp
===
--- test/clang-tidy/misc-use-after-move.cpp
+++ test/clang-tidy/misc-use-after-move.cpp
@@ -133,6 +133,7 @@
   std::move(a);
   // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'a' used after it was moved
   // CHECK-MESSAGES: [[@LINE-2]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE-3]]:17: note: the use happens in a later loop
 }
   }
 }
@@ -391,7 +392,8 @@
 for (int i = 0; i < 10; ++i) {
   a.foo();
   // CHECK-MESSAGES: [[@LINE-1]]:7: warning: 'a' used after it was moved
-  // CHECK-MESSAGES: [[@LINE+1]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE+2]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE-3]]:7: note: the use happens in a later loop
   std::move(a);
 }
   }
@@ -586,7 +588,7 @@
   }
 }
 
-// Passing the object to a function through a non-const pointer or refernce
+// Passing the object to a function through a non-const pointer or reference
 // counts as a re-initialization.
 void passByNonConstPointer(A *);
 void passByNonConstReference(A &);
Index: clang-tidy/misc/UseAfterMoveCheck.cpp
===
--- clang-tidy/misc/UseAfterMoveCheck.cpp
+++ clang-tidy/misc/UseAfterMoveCheck.cpp
@@ -562,18 +562,24 @@
 }
 
 static void emitDiagnostic(const Expr *MovingCall,
-

[PATCH] D25612: [clang-tidy] Add additional diagnostic to misc-use-after-move

2016-10-14 Thread Martin Böhme via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL284235: [clang-tidy] Add additional diagnostic to 
misc-use-after-move (authored by mboehme).

Changed prior to commit:
  https://reviews.llvm.org/D25612?vs=74671&id=74673#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D25612

Files:
  clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
  clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp


Index: clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
@@ -562,18 +562,24 @@
 }
 
 static void emitDiagnostic(const Expr *MovingCall,
-   const ValueDecl *MovedVariable,
+   const DeclRefExpr *MoveArg,
const UseAfterMove &Use, ClangTidyCheck *Check,
ASTContext *Context) {
-  Check->diag(Use.DeclRef->getExprLoc(), "'%0' used after it was moved")
-  << MovedVariable->getName();
-  Check->diag(MovingCall->getExprLoc(), "move occurred here",
-  DiagnosticIDs::Note);
+  SourceLocation UseLoc = Use.DeclRef->getExprLoc();
+  SourceLocation MoveLoc = MovingCall->getExprLoc();
+
+  Check->diag(UseLoc, "'%0' used after it was moved")
+  << MoveArg->getDecl()->getName();
+  Check->diag(MoveLoc, "move occurred here", DiagnosticIDs::Note);
   if (Use.EvaluationOrderUndefined) {
-Check->diag(Use.DeclRef->getExprLoc(),
+Check->diag(UseLoc,
 "the use and move are unsequenced, i.e. there is no guarantee "
 "about the order in which they are evaluated",
 DiagnosticIDs::Note);
+  } else if (UseLoc < MoveLoc || Use.DeclRef == MoveArg) {
+Check->diag(UseLoc,
+"the use happens in a later loop iteration than the move",
+DiagnosticIDs::Note);
   }
 }
 
@@ -625,17 +631,15 @@
   else
 return;
 
-  const ValueDecl *MovedVariable = Arg->getDecl();
-
   // Ignore the std::move if the variable that was passed to it isn't a local
   // variable.
   if (!Arg->getDecl()->getDeclContext()->isFunctionOrMethod())
 return;
 
   UseAfterMoveFinder finder(Result.Context);
   UseAfterMove Use;
-  if (finder.find(FunctionBody, MovingCall, MovedVariable, &Use))
-emitDiagnostic(MovingCall, MovedVariable, Use, this, Result.Context);
+  if (finder.find(FunctionBody, MovingCall, Arg->getDecl(), &Use))
+emitDiagnostic(MovingCall, Arg, Use, this, Result.Context);
 }
 
 } // namespace misc
Index: clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp
@@ -133,6 +133,7 @@
   std::move(a);
   // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'a' used after it was moved
   // CHECK-MESSAGES: [[@LINE-2]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE-3]]:17: note: the use happens in a later loop
 }
   }
 }
@@ -391,7 +392,8 @@
 for (int i = 0; i < 10; ++i) {
   a.foo();
   // CHECK-MESSAGES: [[@LINE-1]]:7: warning: 'a' used after it was moved
-  // CHECK-MESSAGES: [[@LINE+1]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE+2]]:7: note: move occurred here
+  // CHECK-MESSAGES: [[@LINE-3]]:7: note: the use happens in a later loop
   std::move(a);
 }
   }
@@ -586,7 +588,7 @@
   }
 }
 
-// Passing the object to a function through a non-const pointer or refernce
+// Passing the object to a function through a non-const pointer or reference
 // counts as a re-initialization.
 void passByNonConstPointer(A *);
 void passByNonConstReference(A &);


Index: clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
@@ -562,18 +562,24 @@
 }
 
 static void emitDiagnostic(const Expr *MovingCall,
-   const ValueDecl *MovedVariable,
+   const DeclRefExpr *MoveArg,
const UseAfterMove &Use, ClangTidyCheck *Check,
ASTContext *Context) {
-  Check->diag(Use.DeclRef->getExprLoc(), "'%0' used after it was moved")
-  << MovedVariable->getName();
-  Check->diag(MovingCall->getExprLoc(), "move occurred here",
-  DiagnosticIDs::Note);
+  SourceLocation UseLoc = Use.DeclRef->getExprLoc();
+  SourceLocation MoveLoc = MovingCall->getExprLoc();
+
+  Check->diag(UseLoc, "'%0' used after it was moved")
+  << MoveArg->getDecl()->getName();
+  Check->diag(MoveLoc, "move occurred here", DiagnosticIDs::Note);

[PATCH] D23543: Adapt to TraverseLambdaCapture interface change from D23204

2016-08-15 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: alexfh.
mboehme added a subscriber: cfe-commits.
mboehme added a dependency: D23204: Visit lambda capture inits from 
RecursiveASTVisitor::TraverseLambdaCapture()..

Depends on D23204.

This is intended to be submitted immediately after D23204 lands.

https://reviews.llvm.org/D23543

Files:
  clang-tidy/modernize/LoopConvertUtils.cpp
  clang-tidy/modernize/LoopConvertUtils.h
  modularize/Modularize.cpp

Index: modularize/Modularize.cpp
===
--- modularize/Modularize.cpp
+++ modularize/Modularize.cpp
@@ -571,7 +571,10 @@
 return true;
   }
   bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; 
}
-  bool TraverseLambdaCapture(LambdaCapture C) { return true; }
+  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init) {
+return true;
+  }
 
   // Check 'extern "*" {}' block for #include directives.
   bool VisitLinkageSpecDecl(LinkageSpecDecl *D) {
@@ -756,7 +759,10 @@
 return true;
   }
   bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; 
}
-  bool TraverseLambdaCapture(LambdaCapture C) { return true; }
+  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init) {
+return true;
+  }
 
   // Check 'extern "*" {}' block for #include directives.
   bool VisitLinkageSpecDecl(LinkageSpecDecl *D) {
Index: clang-tidy/modernize/LoopConvertUtils.h
===
--- clang-tidy/modernize/LoopConvertUtils.h
+++ clang-tidy/modernize/LoopConvertUtils.h
@@ -337,7 +337,8 @@
   bool TraverseArraySubscriptExpr(ArraySubscriptExpr *E);
   bool TraverseCXXMemberCallExpr(CXXMemberCallExpr *MemberCall);
   bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *OpCall);
-  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C);
+  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init);
   bool TraverseMemberExpr(MemberExpr *Member);
   bool TraverseUnaryDeref(UnaryOperator *Uop);
   bool VisitDeclRefExpr(DeclRefExpr *E);
Index: clang-tidy/modernize/LoopConvertUtils.cpp
===
--- clang-tidy/modernize/LoopConvertUtils.cpp
+++ clang-tidy/modernize/LoopConvertUtils.cpp
@@ -763,7 +763,8 @@
 ///   }
 /// \endcode
 bool ForLoopIndexUseVisitor::TraverseLambdaCapture(LambdaExpr *LE,
-   const LambdaCapture *C) {
+   const LambdaCapture *C,
+   Expr *Init) {
   if (C->capturesVariable()) {
 const VarDecl *VDecl = C->getCapturedVar();
 if (areSameVariable(IndexVar, cast(VDecl))) {
@@ -776,7 +777,7 @@
  C->getLocation()));
 }
   }
-  return VisitorBase::TraverseLambdaCapture(LE, C);
+  return VisitorBase::TraverseLambdaCapture(LE, C, Init);
 }
 
 /// \brief If we find that another variable is created just to refer to the 
loop


Index: modularize/Modularize.cpp
===
--- modularize/Modularize.cpp
+++ modularize/Modularize.cpp
@@ -571,7 +571,10 @@
 return true;
   }
   bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; }
-  bool TraverseLambdaCapture(LambdaCapture C) { return true; }
+  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init) {
+return true;
+  }
 
   // Check 'extern "*" {}' block for #include directives.
   bool VisitLinkageSpecDecl(LinkageSpecDecl *D) {
@@ -756,7 +759,10 @@
 return true;
   }
   bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; }
-  bool TraverseLambdaCapture(LambdaCapture C) { return true; }
+  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init) {
+return true;
+  }
 
   // Check 'extern "*" {}' block for #include directives.
   bool VisitLinkageSpecDecl(LinkageSpecDecl *D) {
Index: clang-tidy/modernize/LoopConvertUtils.h
===
--- clang-tidy/modernize/LoopConvertUtils.h
+++ clang-tidy/modernize/LoopConvertUtils.h
@@ -337,7 +337,8 @@
   bool TraverseArraySubscriptExpr(ArraySubscriptExpr *E);
   bool TraverseCXXMemberCallExpr(CXXMemberCallExpr *MemberCall);
   bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *OpCall);
-  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C);
+  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init);
   bool TraverseMemberExpr(MemberExpr *Member);
   bool TraverseUnaryDeref(UnaryOperator *Uop);
   bool VisitDeclRefExpr(DeclRefExpr *E);
Index: clang-tidy/modernize/LoopCon

Re: [PATCH] D23204: Visit lambda capture inits from RecursiveASTVisitor::TraverseLambdaCapture().

2016-08-15 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 68139.
mboehme added a comment.

Update to a clean diff.

(Sorry, the last diff included a large number of extraneous changes by others.)


https://reviews.llvm.org/D23204

Files:
  include/clang/AST/RecursiveASTVisitor.h
  lib/Index/IndexBody.cpp
  unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
  unittests/Tooling/TestVisitor.h

Index: unittests/Tooling/TestVisitor.h
===
--- unittests/Tooling/TestVisitor.h
+++ unittests/Tooling/TestVisitor.h
@@ -43,6 +43,7 @@
 Lang_C,
 Lang_CXX98,
 Lang_CXX11,
+Lang_CXX14,
 Lang_OBJC,
 Lang_OBJCXX11,
 Lang_CXX = Lang_CXX98
@@ -55,6 +56,7 @@
   case Lang_C: Args.push_back("-std=c99"); break;
   case Lang_CXX98: Args.push_back("-std=c++98"); break;
   case Lang_CXX11: Args.push_back("-std=c++11"); break;
+  case Lang_CXX14: Args.push_back("-std=c++14"); break;
   case Lang_OBJC: Args.push_back("-ObjC"); break;
   case Lang_OBJCXX11:
 Args.push_back("-ObjC++");
@@ -127,9 +129,12 @@
   /// \brief Expect 'Match' to occur at the given 'Line' and 'Column'.
   ///
   /// Any number of expected matches can be set by calling this repeatedly.
-  /// Each is expected to be matched exactly once.
-  void ExpectMatch(Twine Match, unsigned Line, unsigned Column) {
-ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column));
+  /// Each is expected to be matched 'Times' number of times. (This is useful in
+  /// cases in which different AST nodes can match at the same source code
+  /// location.)
+  void ExpectMatch(Twine Match, unsigned Line, unsigned Column,
+   unsigned Times = 1) {
+ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column, Times));
   }
 
   /// \brief Checks that all expected matches have been found.
@@ -200,30 +205,34 @@
   };
 
   struct ExpectedMatch {
-ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber)
-  : Candidate(Name, LineNumber, ColumnNumber), Found(false) {}
+ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber,
+  unsigned Times)
+: Candidate(Name, LineNumber, ColumnNumber), TimesExpected(Times),
+  TimesSeen(0) {}
 
 void UpdateFor(StringRef Name, FullSourceLoc Location, SourceManager &SM) {
   if (Candidate.Matches(Name, Location)) {
-EXPECT_TRUE(!Found);
-Found = true;
-  } else if (!Found && Candidate.PartiallyMatches(Name, Location)) {
+EXPECT_LT(TimesSeen, TimesExpected);
+++TimesSeen;
+  } else if (TimesSeen < TimesExpected &&
+ Candidate.PartiallyMatches(Name, Location)) {
 llvm::raw_string_ostream Stream(PartialMatches);
 Stream << ", partial match: \"" << Name << "\" at ";
 Location.print(Stream, SM);
   }
 }
 
 void ExpectFound() const {
-  EXPECT_TRUE(Found)
+  EXPECT_EQ(TimesExpected, TimesSeen)
   << "Expected \"" << Candidate.ExpectedName
   << "\" at " << Candidate.LineNumber
   << ":" << Candidate.ColumnNumber << PartialMatches;
 }
 
 MatchCandidate Candidate;
 std::string PartialMatches;
-bool Found;
+unsigned TimesExpected;
+unsigned TimesSeen;
   };
 
   std::vector DisallowedMatches;
Index: unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
===
--- unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
+++ unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
@@ -161,10 +161,21 @@
 
 class DeclRefExprVisitor : public ExpectedLocationVisitor {
 public:
+  DeclRefExprVisitor() : ShouldVisitImplicitCode(false) {}
+
+  bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
+
+  void setShouldVisitImplicitCode(bool NewValue) {
+ShouldVisitImplicitCode = NewValue;
+  }
+
   bool VisitDeclRefExpr(DeclRefExpr *Reference) {
 Match(Reference->getNameInfo().getAsString(), Reference->getLocation());
 return true;
   }
+
+private:
+  bool ShouldVisitImplicitCode;
 };
 
 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
@@ -191,14 +202,44 @@
 "void x(); void y() { x(); }"));
 }
 
-TEST(RecursiveASTVisitor, VisitsLambdaCaptureInit) {
+TEST(RecursiveASTVisitor, VisitsExplicitLambdaCaptureInit) {
   DeclRefExprVisitor Visitor;
   Visitor.ExpectMatch("i", 1, 20);
   EXPECT_TRUE(Visitor.runOver(
-"void f() { int i; [i]{}; };",
+"void f() { int i; [i]{}; }",
 DeclRefExprVisitor::Lang_CXX11));
 }
 
+TEST(RecursiveASTVisitor, VisitsImplicitLambdaCaptureInit) {
+  {
+DeclRefExprVisitor Visitor;
+Visitor.ExpectMatch("i", 1, 24);
+EXPECT_TRUE(Visitor.runOver(
+  "void f() { int i; [=]{ i; }; }",
+  DeclRefExprVisitor::Lang_CXX11));
+  }
+  {
+DeclRefExprVisitor Visitor;
+Visitor.setShouldVisitImplicitCode(true);
+// We're expecting the "i" in the lambda to be visited 

Re: [PATCH] D23204: Visit lambda capture inits from RecursiveASTVisitor::TraverseLambdaCapture().

2016-08-15 Thread Martin Böhme via cfe-commits
mboehme marked 2 inline comments as done.


Comment at: include/clang/AST/RecursiveASTVisitor.h:892
@@ -891,1 +891,3 @@
+  else
+TRY_TO(TraverseStmt(LE->capture_init_begin()[C - LE->capture_begin()]));
   return true;

klimek wrote:
> I'd rather pass in the offset than doing math with what's semantically a 
> pointer vs an iterator.
I think the cleanest way to do this would be to pass in both the LambdaCapture 
and the Expr for the corresponding initialization (and handle the offsets in 
TraverseLambdaExpr).

This will first require transitioning all users of TraverseLambdaCapture to the 
new interface, which I'll do in a separate patch.


Comment at: include/clang/AST/RecursiveASTVisitor.h:895
@@ -891,1 +894,3 @@
+  else
+TRY_TO(TraverseStmt(Init));
   return true;

I've now decided to do the interface change for TraverseLambdaCapture in this 
same patch.

There are a few users of TraverseLambdaCapture in clang-tools-extra; the 
required changes are in D23543. The intent is to wait until the reviews for 
both patches are complete, then submit them at the same time.


https://reviews.llvm.org/D23204



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D23353: [clang-tidy] Add check 'misc-use-after-move'

2016-08-16 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 68147.
mboehme added a comment.

Responses to reviewer comments.


https://reviews.llvm.org/D23353

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/UseAfterMoveCheck.cpp
  clang-tidy/misc/UseAfterMoveCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-use-after-move.rst
  test/clang-tidy/misc-use-after-move.cpp

Index: test/clang-tidy/misc-use-after-move.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-use-after-move.cpp
@@ -0,0 +1,1039 @@
+// RUN: %check_clang_tidy %s misc-use-after-move %t
+
+typedef decltype(nullptr) nullptr_t;
+
+namespace std {
+typedef unsigned size_t;
+
+template 
+struct unique_ptr {
+  unique_ptr();
+  T *get() const;
+};
+
+template 
+struct shared_ptr {
+  shared_ptr();
+  T *get() const;
+};
+
+#define DECLARE_STANDARD_CONTAINER(name) \
+  template   \
+  struct name {  \
+name();  \
+void clear();\
+bool empty();\
+  }
+
+#define DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(name) \
+  template   \
+  struct name {  \
+name();  \
+void clear();\
+bool empty();\
+void assign(size_t, const T &);  \
+  }
+
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(basic_string);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(vector);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(deque);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(forward_list);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(list);
+DECLARE_STANDARD_CONTAINER(set);
+DECLARE_STANDARD_CONTAINER(map);
+DECLARE_STANDARD_CONTAINER(multiset);
+DECLARE_STANDARD_CONTAINER(multimap);
+DECLARE_STANDARD_CONTAINER(unordered_set);
+DECLARE_STANDARD_CONTAINER(unordered_map);
+DECLARE_STANDARD_CONTAINER(unordered_multiset);
+DECLARE_STANDARD_CONTAINER(unordered_multimap);
+
+typedef basic_string string;
+
+template 
+struct remove_reference;
+
+template 
+struct remove_reference {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &> {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &&> {
+  typedef _Tp type;
+};
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) noexcept {
+  return static_cast::type &&>(__t);
+}
+
+} // namespace std
+
+class A {
+public:
+  A();
+  A(const A &);
+  A(A &&);
+
+  A &operator=(const A &);
+  A &operator=(A &&);
+
+  void foo() const;
+  int getInt() const;
+
+  operator bool() const;
+
+  int i;
+};
+
+
+// General tests.
+
+// Simple case.
+void simple() {
+  A a;
+  a.foo();
+  A other_a = std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:15: note: move occurred here
+}
+
+// A warning should only be emitted for one use-after-move.
+void onlyFlagOneUseAfterMove() {
+  A a;
+  a.foo();
+  A other_a = std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:15: note: move occurred here
+  a.foo();
+}
+
+void moveAfterMove() {
+  // Move-after-move also counts as a use.
+  {
+A a;
+std::move(a);
+std::move(a);
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: 'a' used after it was moved
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  // This is also true if the move itself turns into the use on the second loop
+  // iteration.
+  {
+A a;
+for (int i = 0; i < 10; ++i) {
+  std::move(a);
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-2]]:7: note: move occurred here
+}
+  }
+}
+
+// Checks also works on function parameters that have a use-after move.
+void parameters(A a) {
+  std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:3: note: move occurred here
+}
+
+void uniquePtrAndSharedPtr() {
+  // Use-after-moves on std::unique_ptr<> or std::shared_ptr<> aren't flagged.
+  {
+std::unique_ptr ptr;
+std::move(ptr);
+ptr.get();
+  }
+  {
+std::shared_ptr ptr;
+std::move(ptr);
+ptr.get();
+  }
+  // This is also true if the std::unique_ptr<> or std::shared_ptr<> is wrapped
+  // in a typedef.
+  {
+typedef std::unique_ptr PtrToA;
+PtrToA ptr;
+std::move(ptr);
+ptr.get();
+  }
+  {
+typedef std::shared_ptr PtrToA;
+PtrToA ptr;
+std::move(ptr);
+ptr.get();
+  }
+  // And it's also true if the template argument is a little more involved.
+  {
+struct B {
+  typedef A AnotherNa

Re: [PATCH] D23353: [clang-tidy] Add check 'misc-use-after-move'

2016-08-16 Thread Martin Böhme via cfe-commits
mboehme marked 9 inline comments as done.


Comment at: clang-tidy/misc/UseAfterMoveCheck.cpp:493
@@ +492,3 @@
+if (!S)
+  continue;
+

For some reason, I thought I had read that they weren't compatible with CFG / 
CFGBlock -- but obviously I must have been imagining things. ;)

Also changed the other occurrences.


Comment at: docs/clang-tidy/checks/misc-use-after-move.rst:16
@@ +15,3 @@
+The last line will trigger a warning that ``str`` is used after it has been
+moved.
+

There doesn't seem to be a clear preference here (see alexfh's comments on 
similar cases), so I'll leave this open until it's resolved one way or the 
other.


Comment at: docs/clang-tidy/checks/misc-use-after-move.rst:182
@@ +181,3 @@
+
+struct S {
+  std::string str;

Sorry -- forgot to check that the documentation compiles (it does now).


Comment at: test/clang-tidy/misc-use-after-move.cpp:159
@@ +158,3 @@
+ptr.get();
+  }
+  // This is also true if the std::unique_ptr<> or std::shared_ptr<> is wrapped

No, it doesn't. At the moment, the check intentionally disregards all uses of 
unique_ptr and shared_ptr (see also the documentation).

I agree that it definitely makes sense to check for scenarios like the one you 
mention. They're a bit of a different beast though because unique_ptr and 
shared_ptr have a well-defined state after they've been moved from. This means 
they would require some special logic -- we'd want to disallow ptr->Foo() after 
a std::move, but not ptr.get(). For this reason, I've left them out of this 
initial version.

Also, I'm not sure whether this check is the best place for these unique_ptr 
and shared_ptr checks to live. Because the after-move state of unique_ptr and 
shared_ptr is well defined, the "use, then dereference" case is really just a 
subset of what could be a more general "dereference null pointer" check.


Comment at: test/clang-tidy/misc-use-after-move.cpp:280
@@ +279,3 @@
+A a;
+std::move(a);
+auto lambda = [&]() { a.foo(); };

> can you add tests with reference capture?

Done.

> also what about: [snip]

The check won't warn about this. More generally, it doesn't do any kind of 
inter-procedural analysis.

Inter-procedural analysis would certainly help in a number of ways. For 
example, it could be used to answer the following:

- If a function takes a non-const reference to an object, does it reinitialize 
that object? (Currently, we optimistically assume that it always does.)
- If a function (that isn't a move constructor or move assignment operator) 
takes an rvalue reference to an object, does it actually move from that object, 
and does it do so unconditionally?

However, this would take significant additional implementation effort and would 
also run more slowly.


https://reviews.llvm.org/D23353



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D23353: [clang-tidy] Add check 'misc-use-after-move'

2016-08-16 Thread Martin Böhme via cfe-commits
mboehme marked 4 inline comments as done.
mboehme added a comment.

In https://reviews.llvm.org/D23353#511362, @Prazek wrote:

> I will review it later, but my first thoughts:
>
> 1. I think we should make some other group, because misc seems to be 
> overloaded. I discussed it with Alex months ago - something like bugprone 
> would be good.


Agree that "misc" seems pretty overcrowded. I'll defer to those who have been 
working on clang-tidy longer than me to make this call.

> 2. Also it would be good to make link in cppcoreguidelines.


How exactly would I create such a "link"? Are you just thinking of a link in 
the documentation, or is there a way to have one clang-tidy check activate 
another (and is this what you're thinking of)?


https://reviews.llvm.org/D23353



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-17 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 68322.
mboehme added a comment.

Reponses to reviewer comments


https://reviews.llvm.org/D0

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-move-forwarding-reference.rst
  test/clang-tidy/misc-move-forwarding-reference.cpp

Index: test/clang-tidy/misc-move-forwarding-reference.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-move-forwarding-reference.cpp
@@ -0,0 +1,125 @@
+// RUN: %check_clang_tidy %s misc-move-forwarding-reference %t -- -- -std=c++14
+
+namespace std {
+template  struct remove_reference;
+
+template  struct remove_reference { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &> { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
+
+} // namespace std
+
+// Standard case.
+template  void f1(U &&SomeU) {
+  T SomeT(std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Ignore parentheses around the argument to std::move().
+template  void f2(U &&SomeU) {
+  T SomeT(std::move((SomeU)));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward((SomeU)));
+}
+
+// Handle the case correctly where std::move() is being used through a using
+// declaration.
+template  void f3(U &&SomeU) {
+  using std::move;
+  T SomeT(move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Handle the case correctly where a global specifier is prepended to
+// std::move().
+template  void f4(U &&SomeU) {
+  T SomeT(::std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(::std::forward(SomeU));
+}
+
+// Create a correct fix if there are spaces around the scope resolution
+// operator.
+template  void f5(U &&SomeU) {
+  {
+T SomeT(::  std  ::  move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(::std::forward(SomeU));
+  }
+  {
+T SomeT(std  ::  move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(std::forward(SomeU));
+  }
+}
+
+// Ignore const rvalue reference parameters.
+template  void f6(const U &&SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the argument to std::move() is a lambda parameter (and
+// thus not actually a parameter of the function template).
+template  void f7() {
+  [](U &&SomeU) { T SomeT(std::move(SomeU)); };
+}
+
+// Ignore the case where the argument is a lvalue reference.
+template  void f8(U &SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the template parameter is a class template parameter
+// (i.e. no template argument deduction is taking place).
+template  class SomeClass {
+  void f(U &&SomeU) { T SomeT(std::move(SomeU)); }
+};
+
+// Ignore the case where the function parameter in the template isn't an rvalue
+// reference but the template argument is explicitly set to be an rvalue
+// reference.
+class A {};
+template  void foo(T);
+void f8() {
+  A a;
+  foo(std::move(a));
+}
+
+// A warning is output, but no fix is suggested, if a macro is used to rename
+// std::move.
+#define MOVE(x) std::move((x))
+template  void f9(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the argument is passed outside of the macro.
+#undef MOVE
+#define MOVE std::move
+template  void f10(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the macro does not include the "std" namespace.
+#undef MOVE
+#define MOVE move
+template  void f11(U &&SomeU) {
+  T SomeT(std::MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Handle the case correctly where the forwarding reference is a parameter of a
+// generic lambda.
+template  void f12() {
+  [] (auto&& x) { T SomeT(std::move(x)); };
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: forwarding reference passed to
+  // CHECK-FIXES: [] (auto&& x) { T SomeT(std::forward(x)); }
+}
Index: docs/clang-tidy/checks/misc-move-forwarding-reference.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-move-forwarding-reference.rst
@@ -0,0 +1,60 @@
+.. title:: clang-tidy - misc-move-forwarding-reference
+
+misc-move

Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-17 Thread Martin Böhme via cfe-commits
mboehme marked 2 inline comments as done.


Comment at: clang-tidy/misc/MoveForwardingReferenceCheck.cpp:46-56
@@ +45,13 @@
+// std::move(). This will hopefully prevent erroneous replacements if the
+// code does unusual things (e.g. create an alias for std::move() in
+// another namespace).
+NestedNameSpecifier *NNS = Callee->getQualifier();
+if (!NNS) {
+  // Called as "move" (i.e. presumably the code had a "using std::move;").
+  // We still conservatively put a "std::" in front of the forward because
+  // we don't know whether the code also had a "using std::forward;".
+  Diag << FixItHint::CreateReplacement(CallRange, "std::" + ForwardName);
+} else if (const NamespaceDecl *Namespace = NNS->getAsNamespace()) {
+  if (Namespace->getName() == "std") {
+if (!NNS->getPrefix()) {
+  // Called as "std::move".

aaron.ballman wrote:
> This code can be combined with the Global check below with something like:
> ```
> Diag << ..., Twine(NNS->getPrefix()->getKind() == NestedNameSpecifier::Global 
> ? "::" : "") + "std::" + ForwardName);
> ```
It could -- but note that there is a third case that also needs to be handled 
here, namely that NNS has a prefix, but it's something other than "::". In 
other words, the code would need to go something like this:

```
if (!NNS->getPrefix() || NNS->getPrefix()->getKind() == 
NestedNameSpecifier::Global) {
  Diag << ..., Twine(NNS->getPrefix() ? "::" : "") + "std::" + ForwardName);
}
```

This repeats part of the check, and I feel it's more opaque than explicitly 
spelling out the two cases I'm interested in, at the cost of a little 
duplication.


Comment at: clang-tidy/misc/MoveForwardingReferenceCheck.cpp:124-125
@@ +123,4 @@
+  auto Diag = diag(CallMove->getExprLoc(),
+   "forwarding reference passed to std::move(); did you mean "
+   "to use std::forward() instead?");
+

aaron.ballman wrote:
> Given that the user is possibly in a confused state when they wrote 
> `std::move()` rather than `std::forward()`, I wonder if it makes more sense 
> to word the diagnostic as an imperative rather than a question? The 
> diagnostic as it is doesn't really explain why `std::forward()` would be 
> right while `std::move()` could be wrong.
> 
> Perhaps: "forwarding reference passed to `std::move()` may unexpectedly leave 
> lvalue references in an indeterminate state; use `std::forward()` instead for 
> perfect forwarding"
> I wonder if it makes more sense to word the diagnostic as an imperative 
> rather than a question?

Good point -- done.

I've reworded your suggestion a bit:

- I've phrased this simply as "may unexpectedly cause lvalues to be moved". 
That's shorter and, I'm hoping, more accessible than talking about 
"indeterminate state".

- I've left out the reference to "perfect forwarding". If someone triggers this 
warning, chances are they won't know what it is anyway. They still have 
everything they need to find out about perfect forwarding; if they do a search 
for std::forward(), they should find relevant material.

What do you think?


Comment at: docs/ReleaseNotes.rst:78
@@ -77,1 +77,3 @@
 
+- New `misc-move-forwarding-reference
+  
`_
 check

aaron.ballman wrote:
> Uncertain whether we're doing this or not, but should we keep this list 
> alphabetized?
I think it's a good idea -- done!


https://reviews.llvm.org/D0



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D23204: Visit lambda capture inits from RecursiveASTVisitor::TraverseLambdaCapture().

2016-08-17 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 68352.
mboehme marked an inline comment as done.
mboehme added a comment.

Changes in response to reviewer comments


https://reviews.llvm.org/D23204

Files:
  include/clang/AST/RecursiveASTVisitor.h
  lib/Index/IndexBody.cpp
  unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
  unittests/Tooling/TestVisitor.h

Index: unittests/Tooling/TestVisitor.h
===
--- unittests/Tooling/TestVisitor.h
+++ unittests/Tooling/TestVisitor.h
@@ -43,6 +43,7 @@
 Lang_C,
 Lang_CXX98,
 Lang_CXX11,
+Lang_CXX14,
 Lang_OBJC,
 Lang_OBJCXX11,
 Lang_CXX = Lang_CXX98
@@ -55,6 +56,7 @@
   case Lang_C: Args.push_back("-std=c99"); break;
   case Lang_CXX98: Args.push_back("-std=c++98"); break;
   case Lang_CXX11: Args.push_back("-std=c++11"); break;
+  case Lang_CXX14: Args.push_back("-std=c++14"); break;
   case Lang_OBJC: Args.push_back("-ObjC"); break;
   case Lang_OBJCXX11:
 Args.push_back("-ObjC++");
@@ -127,9 +129,12 @@
   /// \brief Expect 'Match' to occur at the given 'Line' and 'Column'.
   ///
   /// Any number of expected matches can be set by calling this repeatedly.
-  /// Each is expected to be matched exactly once.
-  void ExpectMatch(Twine Match, unsigned Line, unsigned Column) {
-ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column));
+  /// Each is expected to be matched 'Times' number of times. (This is useful in
+  /// cases in which different AST nodes can match at the same source code
+  /// location.)
+  void ExpectMatch(Twine Match, unsigned Line, unsigned Column,
+   unsigned Times = 1) {
+ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column, Times));
   }
 
   /// \brief Checks that all expected matches have been found.
@@ -200,30 +205,34 @@
   };
 
   struct ExpectedMatch {
-ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber)
-  : Candidate(Name, LineNumber, ColumnNumber), Found(false) {}
+ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber,
+  unsigned Times)
+: Candidate(Name, LineNumber, ColumnNumber), TimesExpected(Times),
+  TimesSeen(0) {}
 
 void UpdateFor(StringRef Name, FullSourceLoc Location, SourceManager &SM) {
   if (Candidate.Matches(Name, Location)) {
-EXPECT_TRUE(!Found);
-Found = true;
-  } else if (!Found && Candidate.PartiallyMatches(Name, Location)) {
+EXPECT_LT(TimesSeen, TimesExpected);
+++TimesSeen;
+  } else if (TimesSeen < TimesExpected &&
+ Candidate.PartiallyMatches(Name, Location)) {
 llvm::raw_string_ostream Stream(PartialMatches);
 Stream << ", partial match: \"" << Name << "\" at ";
 Location.print(Stream, SM);
   }
 }
 
 void ExpectFound() const {
-  EXPECT_TRUE(Found)
+  EXPECT_EQ(TimesExpected, TimesSeen)
   << "Expected \"" << Candidate.ExpectedName
   << "\" at " << Candidate.LineNumber
   << ":" << Candidate.ColumnNumber << PartialMatches;
 }
 
 MatchCandidate Candidate;
 std::string PartialMatches;
-bool Found;
+unsigned TimesExpected;
+unsigned TimesSeen;
   };
 
   std::vector DisallowedMatches;
Index: unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
===
--- unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
+++ unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
@@ -161,10 +161,21 @@
 
 class DeclRefExprVisitor : public ExpectedLocationVisitor {
 public:
+  DeclRefExprVisitor() : ShouldVisitImplicitCode(false) {}
+
+  bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
+
+  void setShouldVisitImplicitCode(bool NewValue) {
+ShouldVisitImplicitCode = NewValue;
+  }
+
   bool VisitDeclRefExpr(DeclRefExpr *Reference) {
 Match(Reference->getNameInfo().getAsString(), Reference->getLocation());
 return true;
   }
+
+private:
+  bool ShouldVisitImplicitCode;
 };
 
 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
@@ -191,14 +202,43 @@
 "void x(); void y() { x(); }"));
 }
 
-TEST(RecursiveASTVisitor, VisitsLambdaCaptureInit) {
+TEST(RecursiveASTVisitor, VisitsExplicitLambdaCaptureInit) {
   DeclRefExprVisitor Visitor;
   Visitor.ExpectMatch("i", 1, 20);
   EXPECT_TRUE(Visitor.runOver(
-"void f() { int i; [i]{}; };",
+"void f() { int i; [i]{}; }",
+DeclRefExprVisitor::Lang_CXX11));
+}
+
+TEST(RecursiveASTVisitor, VisitsUseOfImplicitLambdaCapture) {
+  DeclRefExprVisitor Visitor;
+  Visitor.ExpectMatch("i", 1, 24);
+  EXPECT_TRUE(Visitor.runOver(
+"void f() { int i; [=]{ i; }; }",
+DeclRefExprVisitor::Lang_CXX11));
+}
+
+TEST(RecursiveASTVisitor, VisitsImplicitLambdaCaptureInit) {
+  DeclRefExprVisitor Visitor;
+  Visitor.setShouldVisitImplicitCode(true);
+  // We're expecting the "i" in the lambda

Re: [PATCH] D23204: Visit lambda capture inits from RecursiveASTVisitor::TraverseLambdaCapture().

2016-08-17 Thread Martin Böhme via cfe-commits
mboehme marked 3 inline comments as done.


Comment at: unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp:239
@@ +238,3 @@
+  EXPECT_TRUE(Visitor.runOver(
+"void f() { int i; [a = i + 1]{}; }",
+DeclRefExprVisitor::Lang_CXX14));

alexfh wrote:
> So, C++14 allows you do that? Wow, TIL something new about C++ ;)
;)


https://reviews.llvm.org/D23204



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D23204: Visit lambda capture inits from RecursiveASTVisitor::TraverseLambdaCapture().

2016-08-17 Thread Martin Böhme via cfe-commits
This revision was automatically updated to reflect the committed changes.
mboehme marked an inline comment as done.
Closed by commit rL278933: Visit lambda capture inits from 
RecursiveASTVisitor::TraverseLambdaCapture(). (authored by mboehme).

Changed prior to commit:
  https://reviews.llvm.org/D23204?vs=68352&id=68357#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D23204

Files:
  cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
  cfe/trunk/lib/Index/IndexBody.cpp
  cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
  cfe/trunk/unittests/Tooling/TestVisitor.h

Index: cfe/trunk/lib/Index/IndexBody.cpp
===
--- cfe/trunk/lib/Index/IndexBody.cpp
+++ cfe/trunk/lib/Index/IndexBody.cpp
@@ -276,7 +276,8 @@
 return true;
   }
 
-  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C) {
+  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init) {
 if (C->capturesThis() || C->capturesVLAType())
   return true;
 
Index: cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
===
--- cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
+++ cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
@@ -161,10 +161,21 @@
 
 class DeclRefExprVisitor : public ExpectedLocationVisitor {
 public:
+  DeclRefExprVisitor() : ShouldVisitImplicitCode(false) {}
+
+  bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
+
+  void setShouldVisitImplicitCode(bool NewValue) {
+ShouldVisitImplicitCode = NewValue;
+  }
+
   bool VisitDeclRefExpr(DeclRefExpr *Reference) {
 Match(Reference->getNameInfo().getAsString(), Reference->getLocation());
 return true;
   }
+
+private:
+  bool ShouldVisitImplicitCode;
 };
 
 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
@@ -191,14 +202,43 @@
 "void x(); void y() { x(); }"));
 }
 
-TEST(RecursiveASTVisitor, VisitsLambdaCaptureInit) {
+TEST(RecursiveASTVisitor, VisitsExplicitLambdaCaptureInit) {
   DeclRefExprVisitor Visitor;
   Visitor.ExpectMatch("i", 1, 20);
   EXPECT_TRUE(Visitor.runOver(
-"void f() { int i; [i]{}; };",
+"void f() { int i; [i]{}; }",
+DeclRefExprVisitor::Lang_CXX11));
+}
+
+TEST(RecursiveASTVisitor, VisitsUseOfImplicitLambdaCapture) {
+  DeclRefExprVisitor Visitor;
+  Visitor.ExpectMatch("i", 1, 24);
+  EXPECT_TRUE(Visitor.runOver(
+"void f() { int i; [=]{ i; }; }",
+DeclRefExprVisitor::Lang_CXX11));
+}
+
+TEST(RecursiveASTVisitor, VisitsImplicitLambdaCaptureInit) {
+  DeclRefExprVisitor Visitor;
+  Visitor.setShouldVisitImplicitCode(true);
+  // We're expecting the "i" in the lambda to be visited twice:
+  // - Once for the DeclRefExpr in the lambda capture initialization (whose
+  //   source code location is set to the first use of the variable).
+  // - Once for the DeclRefExpr for the use of "i" inside the lambda.
+  Visitor.ExpectMatch("i", 1, 24, /*Times=*/2);
+  EXPECT_TRUE(Visitor.runOver(
+"void f() { int i; [=]{ i; }; }",
 DeclRefExprVisitor::Lang_CXX11));
 }
 
+TEST(RecursiveASTVisitor, VisitsLambdaInitCaptureInit) {
+  DeclRefExprVisitor Visitor;
+  Visitor.ExpectMatch("i", 1, 24);
+  EXPECT_TRUE(Visitor.runOver(
+"void f() { int i; [a = i + 1]{}; }",
+DeclRefExprVisitor::Lang_CXX14));
+}
+
 /* FIXME: According to Richard Smith this is a bug in the AST.
 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
   DeclRefExprVisitor Visitor;
Index: cfe/trunk/unittests/Tooling/TestVisitor.h
===
--- cfe/trunk/unittests/Tooling/TestVisitor.h
+++ cfe/trunk/unittests/Tooling/TestVisitor.h
@@ -43,6 +43,7 @@
 Lang_C,
 Lang_CXX98,
 Lang_CXX11,
+Lang_CXX14,
 Lang_OBJC,
 Lang_OBJCXX11,
 Lang_CXX = Lang_CXX98
@@ -55,6 +56,7 @@
   case Lang_C: Args.push_back("-std=c99"); break;
   case Lang_CXX98: Args.push_back("-std=c++98"); break;
   case Lang_CXX11: Args.push_back("-std=c++11"); break;
+  case Lang_CXX14: Args.push_back("-std=c++14"); break;
   case Lang_OBJC: Args.push_back("-ObjC"); break;
   case Lang_OBJCXX11:
 Args.push_back("-ObjC++");
@@ -127,9 +129,12 @@
   /// \brief Expect 'Match' to occur at the given 'Line' and 'Column'.
   ///
   /// Any number of expected matches can be set by calling this repeatedly.
-  /// Each is expected to be matched exactly once.
-  void ExpectMatch(Twine Match, unsigned Line, unsigned Column) {
-ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column));
+  /// Each is expected to be matched 'Times' number of times. (This is useful in
+  /// cases in which different AST nodes can match at the same source code
+  /// location.)
+  void ExpectMatch(Twine Match, unsigned Line, unsigned Column,
+   unsigned Times = 1) {
+ExpectedM

Re: [PATCH] D23543: Adapt to TraverseLambdaCapture interface change from D23204

2016-08-17 Thread Martin Böhme via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL278934: Adapt to TraverseLambdaCapture interface change from 
D23204 (authored by mboehme).

Changed prior to commit:
  https://reviews.llvm.org/D23543?vs=68138&id=68358#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D23543

Files:
  clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.cpp
  clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.h
  clang-tools-extra/trunk/modularize/Modularize.cpp

Index: clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.h
===
--- clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.h
+++ clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.h
@@ -337,7 +337,8 @@
   bool TraverseArraySubscriptExpr(ArraySubscriptExpr *E);
   bool TraverseCXXMemberCallExpr(CXXMemberCallExpr *MemberCall);
   bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *OpCall);
-  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C);
+  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init);
   bool TraverseMemberExpr(MemberExpr *Member);
   bool TraverseUnaryDeref(UnaryOperator *Uop);
   bool VisitDeclRefExpr(DeclRefExpr *E);
Index: clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.cpp
===
--- clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.cpp
+++ clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.cpp
@@ -763,7 +763,8 @@
 ///   }
 /// \endcode
 bool ForLoopIndexUseVisitor::TraverseLambdaCapture(LambdaExpr *LE,
-   const LambdaCapture *C) {
+   const LambdaCapture *C,
+   Expr *Init) {
   if (C->capturesVariable()) {
 const VarDecl *VDecl = C->getCapturedVar();
 if (areSameVariable(IndexVar, cast(VDecl))) {
@@ -776,7 +777,7 @@
  C->getLocation()));
 }
   }
-  return VisitorBase::TraverseLambdaCapture(LE, C);
+  return VisitorBase::TraverseLambdaCapture(LE, C, Init);
 }
 
 /// \brief If we find that another variable is created just to refer to the 
loop
Index: clang-tools-extra/trunk/modularize/Modularize.cpp
===
--- clang-tools-extra/trunk/modularize/Modularize.cpp
+++ clang-tools-extra/trunk/modularize/Modularize.cpp
@@ -571,7 +571,10 @@
 return true;
   }
   bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; 
}
-  bool TraverseLambdaCapture(LambdaCapture C) { return true; }
+  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init) {
+return true;
+  }
 
   // Check 'extern "*" {}' block for #include directives.
   bool VisitLinkageSpecDecl(LinkageSpecDecl *D) {
@@ -756,7 +759,10 @@
 return true;
   }
   bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; 
}
-  bool TraverseLambdaCapture(LambdaCapture C) { return true; }
+  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init) {
+return true;
+  }
 
   // Check 'extern "*" {}' block for #include directives.
   bool VisitLinkageSpecDecl(LinkageSpecDecl *D) {


Index: clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.h
===
--- clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.h
+++ clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.h
@@ -337,7 +337,8 @@
   bool TraverseArraySubscriptExpr(ArraySubscriptExpr *E);
   bool TraverseCXXMemberCallExpr(CXXMemberCallExpr *MemberCall);
   bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *OpCall);
-  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C);
+  bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init);
   bool TraverseMemberExpr(MemberExpr *Member);
   bool TraverseUnaryDeref(UnaryOperator *Uop);
   bool VisitDeclRefExpr(DeclRefExpr *E);
Index: clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.cpp
===
--- clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.cpp
+++ clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.cpp
@@ -763,7 +763,8 @@
 ///   }
 /// \endcode
 bool ForLoopIndexUseVisitor::TraverseLambdaCapture(LambdaExpr *LE,
-   const LambdaCapture *C) {
+   const LambdaCapture *C,
+   Expr *Init) {
   if (C->capturesVariable()) {
 const VarDecl *VDecl = C->getCapturedVar();
 if (areSameVariable(IndexVar, cast

Re: [PATCH] D23353: [clang-tidy] Add check 'misc-use-after-move'

2016-08-17 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 68365.
mboehme added a comment.

Remove braces around single-line bodies of if statements


https://reviews.llvm.org/D23353

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/UseAfterMoveCheck.cpp
  clang-tidy/misc/UseAfterMoveCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-use-after-move.rst
  test/clang-tidy/misc-use-after-move.cpp

Index: test/clang-tidy/misc-use-after-move.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-use-after-move.cpp
@@ -0,0 +1,1039 @@
+// RUN: %check_clang_tidy %s misc-use-after-move %t
+
+typedef decltype(nullptr) nullptr_t;
+
+namespace std {
+typedef unsigned size_t;
+
+template 
+struct unique_ptr {
+  unique_ptr();
+  T *get() const;
+};
+
+template 
+struct shared_ptr {
+  shared_ptr();
+  T *get() const;
+};
+
+#define DECLARE_STANDARD_CONTAINER(name) \
+  template   \
+  struct name {  \
+name();  \
+void clear();\
+bool empty();\
+  }
+
+#define DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(name) \
+  template   \
+  struct name {  \
+name();  \
+void clear();\
+bool empty();\
+void assign(size_t, const T &);  \
+  }
+
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(basic_string);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(vector);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(deque);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(forward_list);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(list);
+DECLARE_STANDARD_CONTAINER(set);
+DECLARE_STANDARD_CONTAINER(map);
+DECLARE_STANDARD_CONTAINER(multiset);
+DECLARE_STANDARD_CONTAINER(multimap);
+DECLARE_STANDARD_CONTAINER(unordered_set);
+DECLARE_STANDARD_CONTAINER(unordered_map);
+DECLARE_STANDARD_CONTAINER(unordered_multiset);
+DECLARE_STANDARD_CONTAINER(unordered_multimap);
+
+typedef basic_string string;
+
+template 
+struct remove_reference;
+
+template 
+struct remove_reference {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &> {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &&> {
+  typedef _Tp type;
+};
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) noexcept {
+  return static_cast::type &&>(__t);
+}
+
+} // namespace std
+
+class A {
+public:
+  A();
+  A(const A &);
+  A(A &&);
+
+  A &operator=(const A &);
+  A &operator=(A &&);
+
+  void foo() const;
+  int getInt() const;
+
+  operator bool() const;
+
+  int i;
+};
+
+
+// General tests.
+
+// Simple case.
+void simple() {
+  A a;
+  a.foo();
+  A other_a = std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:15: note: move occurred here
+}
+
+// A warning should only be emitted for one use-after-move.
+void onlyFlagOneUseAfterMove() {
+  A a;
+  a.foo();
+  A other_a = std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:15: note: move occurred here
+  a.foo();
+}
+
+void moveAfterMove() {
+  // Move-after-move also counts as a use.
+  {
+A a;
+std::move(a);
+std::move(a);
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: 'a' used after it was moved
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  // This is also true if the move itself turns into the use on the second loop
+  // iteration.
+  {
+A a;
+for (int i = 0; i < 10; ++i) {
+  std::move(a);
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-2]]:7: note: move occurred here
+}
+  }
+}
+
+// Checks also works on function parameters that have a use-after move.
+void parameters(A a) {
+  std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:3: note: move occurred here
+}
+
+void uniquePtrAndSharedPtr() {
+  // Use-after-moves on std::unique_ptr<> or std::shared_ptr<> aren't flagged.
+  {
+std::unique_ptr ptr;
+std::move(ptr);
+ptr.get();
+  }
+  {
+std::shared_ptr ptr;
+std::move(ptr);
+ptr.get();
+  }
+  // This is also true if the std::unique_ptr<> or std::shared_ptr<> is wrapped
+  // in a typedef.
+  {
+typedef std::unique_ptr PtrToA;
+PtrToA ptr;
+std::move(ptr);
+ptr.get();
+  }
+  {
+typedef std::shared_ptr PtrToA;
+PtrToA ptr;
+std::move(ptr);
+ptr.get();
+  }
+  // And it's also true if the template argument is a little more involved.
+  {
+struct B {
+

Re: [PATCH] D23353: [clang-tidy] Add check 'misc-use-after-move'

2016-08-17 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 68366.
mboehme added a comment.

Remove braces around another single-line if statement block


https://reviews.llvm.org/D23353

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/UseAfterMoveCheck.cpp
  clang-tidy/misc/UseAfterMoveCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-use-after-move.rst
  test/clang-tidy/misc-use-after-move.cpp

Index: test/clang-tidy/misc-use-after-move.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-use-after-move.cpp
@@ -0,0 +1,1039 @@
+// RUN: %check_clang_tidy %s misc-use-after-move %t
+
+typedef decltype(nullptr) nullptr_t;
+
+namespace std {
+typedef unsigned size_t;
+
+template 
+struct unique_ptr {
+  unique_ptr();
+  T *get() const;
+};
+
+template 
+struct shared_ptr {
+  shared_ptr();
+  T *get() const;
+};
+
+#define DECLARE_STANDARD_CONTAINER(name) \
+  template   \
+  struct name {  \
+name();  \
+void clear();\
+bool empty();\
+  }
+
+#define DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(name) \
+  template   \
+  struct name {  \
+name();  \
+void clear();\
+bool empty();\
+void assign(size_t, const T &);  \
+  }
+
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(basic_string);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(vector);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(deque);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(forward_list);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(list);
+DECLARE_STANDARD_CONTAINER(set);
+DECLARE_STANDARD_CONTAINER(map);
+DECLARE_STANDARD_CONTAINER(multiset);
+DECLARE_STANDARD_CONTAINER(multimap);
+DECLARE_STANDARD_CONTAINER(unordered_set);
+DECLARE_STANDARD_CONTAINER(unordered_map);
+DECLARE_STANDARD_CONTAINER(unordered_multiset);
+DECLARE_STANDARD_CONTAINER(unordered_multimap);
+
+typedef basic_string string;
+
+template 
+struct remove_reference;
+
+template 
+struct remove_reference {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &> {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &&> {
+  typedef _Tp type;
+};
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) noexcept {
+  return static_cast::type &&>(__t);
+}
+
+} // namespace std
+
+class A {
+public:
+  A();
+  A(const A &);
+  A(A &&);
+
+  A &operator=(const A &);
+  A &operator=(A &&);
+
+  void foo() const;
+  int getInt() const;
+
+  operator bool() const;
+
+  int i;
+};
+
+
+// General tests.
+
+// Simple case.
+void simple() {
+  A a;
+  a.foo();
+  A other_a = std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:15: note: move occurred here
+}
+
+// A warning should only be emitted for one use-after-move.
+void onlyFlagOneUseAfterMove() {
+  A a;
+  a.foo();
+  A other_a = std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:15: note: move occurred here
+  a.foo();
+}
+
+void moveAfterMove() {
+  // Move-after-move also counts as a use.
+  {
+A a;
+std::move(a);
+std::move(a);
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: 'a' used after it was moved
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  // This is also true if the move itself turns into the use on the second loop
+  // iteration.
+  {
+A a;
+for (int i = 0; i < 10; ++i) {
+  std::move(a);
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-2]]:7: note: move occurred here
+}
+  }
+}
+
+// Checks also works on function parameters that have a use-after move.
+void parameters(A a) {
+  std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:3: note: move occurred here
+}
+
+void uniquePtrAndSharedPtr() {
+  // Use-after-moves on std::unique_ptr<> or std::shared_ptr<> aren't flagged.
+  {
+std::unique_ptr ptr;
+std::move(ptr);
+ptr.get();
+  }
+  {
+std::shared_ptr ptr;
+std::move(ptr);
+ptr.get();
+  }
+  // This is also true if the std::unique_ptr<> or std::shared_ptr<> is wrapped
+  // in a typedef.
+  {
+typedef std::unique_ptr PtrToA;
+PtrToA ptr;
+std::move(ptr);
+ptr.get();
+  }
+  {
+typedef std::shared_ptr PtrToA;
+PtrToA ptr;
+std::move(ptr);
+ptr.get();
+  }
+  // And it's also true if the template argument is a little more involved.
+  {
+struct B 

Re: [PATCH] D23353: [clang-tidy] Add check 'misc-use-after-move'

2016-08-17 Thread Martin Böhme via cfe-commits
mboehme marked 2 inline comments as done.


Comment at: clang-tidy/misc/UseAfterMoveCheck.cpp:659
@@ +658,3 @@
+  UseAfterMove Use;
+  if (finder.find(FunctionBody, MovingCall, MovedVariable, &Use)) {
+emitDiagnostic(MovingCall, MovedVariable, Use, this, Result.Context);

alexfh wrote:
> omtcyfz wrote:
> > Nit: As I discussed with Alex, it is better to omit `{}` in conditional 
> > statements if the body only contains one statement. Even if it wasn't so, 
> > it'd be better to use one "style" (i.e. either always omit `{}` or always 
> > have `{}`) at least inside a single check and you have no `{}` in many 
> > places inside this file (L637, L647, L577, ...).
> > 
> > Just a stylistic thing, doesn't matter too much, though.
> I always say "single-line", not "single statement", which is a bit different 
> ;) 
Agree -- I'm just used to putting the braces in there. ;)

I went through and cleaned up a bunch of these -- hope I found them all.


https://reviews.llvm.org/D23353



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D23842: [CFG] Add iterator_ranges to CFG and CFGBlock.

2016-08-24 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: alexfh.
mboehme added a subscriber: cfe-commits.

(Needed for D23353.)

https://reviews.llvm.org/D23842

Files:
  include/clang/Analysis/CFG.h

Index: include/clang/Analysis/CFG.h
===
--- include/clang/Analysis/CFG.h
+++ include/clang/Analysis/CFG.h
@@ -22,6 +22,7 @@
 #include "llvm/ADT/GraphTraits.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/iterator_range.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/raw_ostream.h"
@@ -522,11 +523,15 @@
   typedef AdjacentBlocks::const_iterator  const_pred_iterator;
   typedef AdjacentBlocks::reverse_iterator  pred_reverse_iterator;
   typedef AdjacentBlocks::const_reverse_iterator  const_pred_reverse_iterator;
+  typedef llvm::iterator_range  pred_range;
+  typedef llvm::iterator_range  pred_const_range;
 
   typedef AdjacentBlocks::iterator  succ_iterator;
   typedef AdjacentBlocks::const_iterator  const_succ_iterator;
   typedef AdjacentBlocks::reverse_iterator  succ_reverse_iterator;
   typedef AdjacentBlocks::const_reverse_iterator  const_succ_reverse_iterator;
+  typedef llvm::iterator_range  succ_range;
+  typedef llvm::iterator_range  succ_const_range;
 
   pred_iteratorpred_begin(){ return Preds.begin();   }
   pred_iteratorpred_end()  { return Preds.end(); }
@@ -538,6 +543,13 @@
   const_pred_reverse_iterator  pred_rbegin() const { return Preds.rbegin();  }
   const_pred_reverse_iterator  pred_rend()   const { return Preds.rend();}
 
+  pred_range   preds() {
+return pred_range(pred_begin(), pred_end());
+  }
+  pred_const_range preds() const {
+return pred_const_range(pred_begin(), pred_end());
+  }
+
   succ_iteratorsucc_begin(){ return Succs.begin();   }
   succ_iteratorsucc_end()  { return Succs.end(); }
   const_succ_iterator  succ_begin()  const { return Succs.begin();   }
@@ -548,13 +560,19 @@
   const_succ_reverse_iterator  succ_rbegin() const { return Succs.rbegin();  }
   const_succ_reverse_iterator  succ_rend()   const { return Succs.rend();}
 
+  succ_range   succs() {
+return succ_range(succ_begin(), succ_end());
+  }
+  succ_const_range succs() const {
+return succ_const_range(succ_begin(), succ_end());
+  }
+
   unsigned succ_size()   const { return Succs.size();}
   bool succ_empty()  const { return Succs.empty();   }
 
   unsigned pred_size()   const { return Preds.size();}
   bool pred_empty()  const { return Preds.empty();   }
 
-
   class FilterOptions {
   public:
 FilterOptions() {
@@ -840,6 +858,7 @@
 
   typedef llvm::DenseMap::const_iterator
 synthetic_stmt_iterator;
+  typedef llvm::iterator_range synthetic_stmt_range;
 
   /// Iterates over synthetic DeclStmts in the CFG.
   ///
@@ -855,6 +874,11 @@
 return SyntheticDeclStmts.end();
   }
 
+  /// \sa synthetic_stmt_begin
+  synthetic_stmt_range synthetic_stmts() const {
+return synthetic_stmt_range(synthetic_stmt_begin(), synthetic_stmt_end());
+  }
+
   
//======//
   // Member templates useful for various batch operations over CFGs.
   
//======//


Index: include/clang/Analysis/CFG.h
===
--- include/clang/Analysis/CFG.h
+++ include/clang/Analysis/CFG.h
@@ -22,6 +22,7 @@
 #include "llvm/ADT/GraphTraits.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/iterator_range.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/raw_ostream.h"
@@ -522,11 +523,15 @@
   typedef AdjacentBlocks::const_iterator  const_pred_iterator;
   typedef AdjacentBlocks::reverse_iterator  pred_reverse_iterator;
   typedef AdjacentBlocks::const_reverse_iterator  const_pred_reverse_iterator;
+  typedef llvm::iterator_range  pred_range;
+  typedef llvm::iterator_range  pred_const_range;
 
   typedef AdjacentBlocks::iterator  succ_iterator;
   typedef AdjacentBlocks::const_iterator  const_succ_iterator;
   typedef AdjacentBlocks::reverse_iterator  succ_reverse_iterator;
   typedef AdjacentBlocks::const_reverse_iterator  const_succ_reverse_iterator;
+  typedef llvm::iterator_range  succ_range;
+  typedef llvm::iterator_range  succ_const_rang

Re: [PATCH] D23842: [CFG] Add iterator_ranges to CFG and CFGBlock.

2016-08-24 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 69129.
mboehme added a comment.

Re-add inadvertently deleted blank line


https://reviews.llvm.org/D23842

Files:
  include/clang/Analysis/CFG.h

Index: include/clang/Analysis/CFG.h
===
--- include/clang/Analysis/CFG.h
+++ include/clang/Analysis/CFG.h
@@ -22,6 +22,7 @@
 #include "llvm/ADT/GraphTraits.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/iterator_range.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/raw_ostream.h"
@@ -522,11 +523,15 @@
   typedef AdjacentBlocks::const_iterator  const_pred_iterator;
   typedef AdjacentBlocks::reverse_iterator  pred_reverse_iterator;
   typedef AdjacentBlocks::const_reverse_iterator  const_pred_reverse_iterator;
+  typedef llvm::iterator_range  pred_range;
+  typedef llvm::iterator_range  pred_const_range;
 
   typedef AdjacentBlocks::iterator  succ_iterator;
   typedef AdjacentBlocks::const_iterator  const_succ_iterator;
   typedef AdjacentBlocks::reverse_iterator  succ_reverse_iterator;
   typedef AdjacentBlocks::const_reverse_iterator  const_succ_reverse_iterator;
+  typedef llvm::iterator_range  succ_range;
+  typedef llvm::iterator_range  succ_const_range;
 
   pred_iteratorpred_begin(){ return Preds.begin();   }
   pred_iteratorpred_end()  { return Preds.end(); }
@@ -538,6 +543,13 @@
   const_pred_reverse_iterator  pred_rbegin() const { return Preds.rbegin();  }
   const_pred_reverse_iterator  pred_rend()   const { return Preds.rend();}
 
+  pred_range   preds() {
+return pred_range(pred_begin(), pred_end());
+  }
+  pred_const_range preds() const {
+return pred_const_range(pred_begin(), pred_end());
+  }
+
   succ_iteratorsucc_begin(){ return Succs.begin();   }
   succ_iteratorsucc_end()  { return Succs.end(); }
   const_succ_iterator  succ_begin()  const { return Succs.begin();   }
@@ -548,6 +560,13 @@
   const_succ_reverse_iterator  succ_rbegin() const { return Succs.rbegin();  }
   const_succ_reverse_iterator  succ_rend()   const { return Succs.rend();}
 
+  succ_range   succs() {
+return succ_range(succ_begin(), succ_end());
+  }
+  succ_const_range succs() const {
+return succ_const_range(succ_begin(), succ_end());
+  }
+
   unsigned succ_size()   const { return Succs.size();}
   bool succ_empty()  const { return Succs.empty();   }
 
@@ -840,6 +859,7 @@
 
   typedef llvm::DenseMap::const_iterator
 synthetic_stmt_iterator;
+  typedef llvm::iterator_range synthetic_stmt_range;
 
   /// Iterates over synthetic DeclStmts in the CFG.
   ///
@@ -855,6 +875,11 @@
 return SyntheticDeclStmts.end();
   }
 
+  /// \sa synthetic_stmt_begin
+  synthetic_stmt_range synthetic_stmts() const {
+return synthetic_stmt_range(synthetic_stmt_begin(), synthetic_stmt_end());
+  }
+
   
//======//
   // Member templates useful for various batch operations over CFGs.
   
//======//


Index: include/clang/Analysis/CFG.h
===
--- include/clang/Analysis/CFG.h
+++ include/clang/Analysis/CFG.h
@@ -22,6 +22,7 @@
 #include "llvm/ADT/GraphTraits.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/iterator_range.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/raw_ostream.h"
@@ -522,11 +523,15 @@
   typedef AdjacentBlocks::const_iterator  const_pred_iterator;
   typedef AdjacentBlocks::reverse_iterator  pred_reverse_iterator;
   typedef AdjacentBlocks::const_reverse_iterator  const_pred_reverse_iterator;
+  typedef llvm::iterator_range  pred_range;
+  typedef llvm::iterator_range  pred_const_range;
 
   typedef AdjacentBlocks::iterator  succ_iterator;
   typedef AdjacentBlocks::const_iterator  const_succ_iterator;
   typedef AdjacentBlocks::reverse_iterator  succ_reverse_iterator;
   typedef AdjacentBlocks::const_reverse_iterator  const_succ_reverse_iterator;
+  typedef llvm::iterator_range  succ_range;
+  typedef llvm::iterator_range  succ_const_range;
 
   pred_iteratorpred_begin(){ return Preds.begin();   }
   pred_iteratorpred_end()  { return Preds.end(); }
@@ -538,6 +543,13 @@
   const_pred_reverse_iterator  pred_rbegin() const { 

Re: [PATCH] D23353: [clang-tidy] Add check 'misc-use-after-move'

2016-08-25 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 69206.
mboehme added a comment.

Responses to reviewer comments.


https://reviews.llvm.org/D23353

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/UseAfterMoveCheck.cpp
  clang-tidy/misc/UseAfterMoveCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-use-after-move.rst
  test/clang-tidy/misc-use-after-move.cpp

Index: test/clang-tidy/misc-use-after-move.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-use-after-move.cpp
@@ -0,0 +1,1039 @@
+// RUN: %check_clang_tidy %s misc-use-after-move %t
+
+typedef decltype(nullptr) nullptr_t;
+
+namespace std {
+typedef unsigned size_t;
+
+template 
+struct unique_ptr {
+  unique_ptr();
+  T *get() const;
+};
+
+template 
+struct shared_ptr {
+  shared_ptr();
+  T *get() const;
+};
+
+#define DECLARE_STANDARD_CONTAINER(name) \
+  template   \
+  struct name {  \
+name();  \
+void clear();\
+bool empty();\
+  }
+
+#define DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(name) \
+  template   \
+  struct name {  \
+name();  \
+void clear();\
+bool empty();\
+void assign(size_t, const T &);  \
+  }
+
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(basic_string);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(vector);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(deque);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(forward_list);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(list);
+DECLARE_STANDARD_CONTAINER(set);
+DECLARE_STANDARD_CONTAINER(map);
+DECLARE_STANDARD_CONTAINER(multiset);
+DECLARE_STANDARD_CONTAINER(multimap);
+DECLARE_STANDARD_CONTAINER(unordered_set);
+DECLARE_STANDARD_CONTAINER(unordered_map);
+DECLARE_STANDARD_CONTAINER(unordered_multiset);
+DECLARE_STANDARD_CONTAINER(unordered_multimap);
+
+typedef basic_string string;
+
+template 
+struct remove_reference;
+
+template 
+struct remove_reference {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &> {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &&> {
+  typedef _Tp type;
+};
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) noexcept {
+  return static_cast::type &&>(__t);
+}
+
+} // namespace std
+
+class A {
+public:
+  A();
+  A(const A &);
+  A(A &&);
+
+  A &operator=(const A &);
+  A &operator=(A &&);
+
+  void foo() const;
+  int getInt() const;
+
+  operator bool() const;
+
+  int i;
+};
+
+
+// General tests.
+
+// Simple case.
+void simple() {
+  A a;
+  a.foo();
+  A other_a = std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:15: note: move occurred here
+}
+
+// A warning should only be emitted for one use-after-move.
+void onlyFlagOneUseAfterMove() {
+  A a;
+  a.foo();
+  A other_a = std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:15: note: move occurred here
+  a.foo();
+}
+
+void moveAfterMove() {
+  // Move-after-move also counts as a use.
+  {
+A a;
+std::move(a);
+std::move(a);
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: 'a' used after it was moved
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  // This is also true if the move itself turns into the use on the second loop
+  // iteration.
+  {
+A a;
+for (int i = 0; i < 10; ++i) {
+  std::move(a);
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-2]]:7: note: move occurred here
+}
+  }
+}
+
+// Checks also works on function parameters that have a use-after move.
+void parameters(A a) {
+  std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:3: note: move occurred here
+}
+
+void uniquePtrAndSharedPtr() {
+  // Use-after-moves on std::unique_ptr<> or std::shared_ptr<> aren't flagged.
+  {
+std::unique_ptr ptr;
+std::move(ptr);
+ptr.get();
+  }
+  {
+std::shared_ptr ptr;
+std::move(ptr);
+ptr.get();
+  }
+  // This is also true if the std::unique_ptr<> or std::shared_ptr<> is wrapped
+  // in a typedef.
+  {
+typedef std::unique_ptr PtrToA;
+PtrToA ptr;
+std::move(ptr);
+ptr.get();
+  }
+  {
+typedef std::shared_ptr PtrToA;
+PtrToA ptr;
+std::move(ptr);
+ptr.get();
+  }
+  // And it's also true if the template argument is a little more involved.
+  {
+struct B {
+  typedef A AnotherNa

Re: [PATCH] D23353: [clang-tidy] Add check 'misc-use-after-move'

2016-08-25 Thread Martin Böhme via cfe-commits
mboehme marked 9 inline comments as done.
mboehme added a comment.

> > > 2. Also it would be good to make link in cppcoreguidelines.

> 

> > 

> 

> > 

> 

> > How exactly would I create such a "link"? Are you just thinking of a link 
> > in the documentation, or is there a way to have one clang-tidy check 
> > activate another (and is this what you're thinking of)?

> 

> 

> I am not sure if there is any other mechanism than just links in 
> documentation.


I've taken a look, but I'm not sure where I would put this link. I could add 
another file that starts with "cppcoreguidelines-", but that would make it look 
as if an actual check with that name exists, and I'm not sure that's what we 
want. Do you have a suggestion?

> In the perfect word it would be nice to invoke this check using 
> cppcoreguidelines-use-after-move also with some special options like 
> Pedantic=1 (That would warn about any use after move, even after 
> reinitialization - this is what cppcoreguidelines says)


Do you have a pointer to something in CppCoreGuidelines that says this 
explicitly?

The closest I've been able to find is in F.18: "Flag access to moved-from 
objects." It's not entirely clear here whether "access" is meant to include 
reinitialization.

However, other parts of CppCoreGuidelines seem to imply that it _is_ OK to 
reinitialize an object:

From ES.56:
"Usually, a std::move() is used as an argument to a && parameter. And after you 
do that, assume the object has been moved from (see C.64) and don't read its 
state again until you first set it to a new value."

And from C.64:
"Unless there is an exceptionally strong reason not to, make x = std::move(y); 
y = z; work with the conventional semantics."



Comment at: clang-tidy/misc/UseAfterMoveCheck.cpp:29
@@ +28,3 @@
+/// Provides information about the evaluation order of (sub-)expressions within
+/// a CFGBlock.
+///

alexfh wrote:
> Please enclose inline code snippets in double backquotes (doxygen supports 
> markdown to a certain degree).
Shouldn't those be single backquotes? (See 
https://www.stack.nl/~dimitri/doxygen/manual/markdown.html)

Done with single backquotes.


Comment at: clang-tidy/misc/UseAfterMoveCheck.cpp:46
@@ +45,3 @@
+///   API),
+/// - Removing the dependency of SequenceChecker on Sema, and
+/// - (Probably) modifying SequenceChecker to make it suitable to be used in

alexfh wrote:
> Does it look feasible?
At least it's not something that I feel I would be able to do without breaking 
things -- I'm not familiar enough with SequenceChecker for that.


Comment at: clang-tidy/misc/UseAfterMoveCheck.cpp:135
@@ +134,3 @@
+class UseAfterMoveFinder {
+public:
+  UseAfterMoveFinder(ASTContext *TheContext);

alexfh wrote:
> It's definitely subjective, but I don't think it's scary. And the size of the 
> file doesn't seem to be an issue yet. IMO, a reason to move this to a header 
> would appear once this class is needed elsewhere. 
Leaving it here for now.


Comment at: clang-tidy/misc/UseAfterMoveCheck.cpp:217
@@ +216,3 @@
+  for (const auto &SyntheticStmt : TheCFG->synthetic_stmts()) {
+SyntheticStmtSourceMap[SyntheticStmt.first] = SyntheticStmt.second;
+  }

I've added CFG::synthetic_stmts() in D23842.


Comment at: clang-tidy/misc/UseAfterMoveCheck.cpp:436
@@ +435,3 @@
+return true;
+}
+  }

Added CFGBlock::succs() in D23842. This looks much nicer now!


Comment at: test/clang-tidy/misc-use-after-move.cpp:505-506
@@ +504,4 @@
+void noreturnDestructor() {
+  A a;
+  // The while loop in the ASSERT() would ordinarily have the potential to 
cause
+  // a use-after-move because the second iteration of the loop would be using a

Noted for a future addition. I'd like to get this patch in though without 
further expanding the functionality (it's already pretty big...).


https://reviews.llvm.org/D23353



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D23842: [CFG] Add iterator_ranges to CFG and CFGBlock.

2016-08-25 Thread Martin Böhme via cfe-commits
mboehme marked an inline comment as done.


Comment at: include/clang/Analysis/CFG.h:526
@@ -524,1 +525,3 @@
   typedef AdjacentBlocks::const_reverse_iterator  const_pred_reverse_iterator;
+  typedef llvm::iterator_range  pred_range;
+  typedef llvm::iterator_range  pred_const_range;

alexfh wrote:
> Most of the time the new functions will be used in a range-based for loop. I 
> don't think the type returned by the functions will need to be explicitly 
> specified anywhere. I'd remove the typedefs.
I agree the typedefs will probably never be used outside this class, but 
typedefs for iterator_ranges seem to be a common pattern in the Clang codebase. 
(EnumDecl::enumerator_range and CallExpr::arg_range are two random examples.) I 
assume the intent is to make the definition of the functions that return these 
ranges less verbose.

Are you OK with me submitting this patch as-is (with the typedefs)?


https://reviews.llvm.org/D23842



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-26 Thread Martin Böhme via cfe-commits
mboehme marked an inline comment as done.
mboehme added a comment.

Any more comments here?


https://reviews.llvm.org/D0



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-30 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 69662.
mboehme added a comment.

Fix typo


https://reviews.llvm.org/D0

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-move-forwarding-reference.rst
  test/clang-tidy/misc-move-forwarding-reference.cpp

Index: test/clang-tidy/misc-move-forwarding-reference.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-move-forwarding-reference.cpp
@@ -0,0 +1,125 @@
+// RUN: %check_clang_tidy %s misc-move-forwarding-reference %t -- -- -std=c++14
+
+namespace std {
+template  struct remove_reference;
+
+template  struct remove_reference { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &> { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
+
+} // namespace std
+
+// Standard case.
+template  void f1(U &&SomeU) {
+  T SomeT(std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Ignore parentheses around the argument to std::move().
+template  void f2(U &&SomeU) {
+  T SomeT(std::move((SomeU)));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward((SomeU)));
+}
+
+// Handle the case correctly where std::move() is being used through a using
+// declaration.
+template  void f3(U &&SomeU) {
+  using std::move;
+  T SomeT(move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Handle the case correctly where a global specifier is prepended to
+// std::move().
+template  void f4(U &&SomeU) {
+  T SomeT(::std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(::std::forward(SomeU));
+}
+
+// Create a correct fix if there are spaces around the scope resolution
+// operator.
+template  void f5(U &&SomeU) {
+  {
+T SomeT(::  std  ::  move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(::std::forward(SomeU));
+  }
+  {
+T SomeT(std  ::  move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(std::forward(SomeU));
+  }
+}
+
+// Ignore const rvalue reference parameters.
+template  void f6(const U &&SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the argument to std::move() is a lambda parameter (and
+// thus not actually a parameter of the function template).
+template  void f7() {
+  [](U &&SomeU) { T SomeT(std::move(SomeU)); };
+}
+
+// Ignore the case where the argument is a lvalue reference.
+template  void f8(U &SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the template parameter is a class template parameter
+// (i.e. no template argument deduction is taking place).
+template  class SomeClass {
+  void f(U &&SomeU) { T SomeT(std::move(SomeU)); }
+};
+
+// Ignore the case where the function parameter in the template isn't an rvalue
+// reference but the template argument is explicitly set to be an rvalue
+// reference.
+class A {};
+template  void foo(T);
+void f8() {
+  A a;
+  foo(std::move(a));
+}
+
+// A warning is output, but no fix is suggested, if a macro is used to rename
+// std::move.
+#define MOVE(x) std::move((x))
+template  void f9(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the argument is passed outside of the macro.
+#undef MOVE
+#define MOVE std::move
+template  void f10(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the macro does not include the "std" namespace.
+#undef MOVE
+#define MOVE move
+template  void f11(U &&SomeU) {
+  T SomeT(std::MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Handle the case correctly where the forwarding reference is a parameter of a
+// generic lambda.
+template  void f12() {
+  [] (auto&& x) { T SomeT(std::move(x)); };
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: forwarding reference passed to
+  // CHECK-FIXES: [] (auto&& x) { T SomeT(std::forward(x)); }
+}
Index: docs/clang-tidy/checks/misc-move-forwarding-reference.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-move-forwarding-reference.rst
@@ -0,0 +1,60 @@
+.. title:: clang-tidy - misc-move-forwarding-reference
+
+misc-move-forwarding-reference

Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-30 Thread Martin Böhme via cfe-commits
mboehme marked an inline comment as done.
mboehme added a comment.

https://reviews.llvm.org/D0



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-30 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 69665.
mboehme added a comment.

Update to current head


https://reviews.llvm.org/D0

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-move-forwarding-reference.rst
  test/clang-tidy/misc-move-forwarding-reference.cpp

Index: test/clang-tidy/misc-move-forwarding-reference.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-move-forwarding-reference.cpp
@@ -0,0 +1,125 @@
+// RUN: %check_clang_tidy %s misc-move-forwarding-reference %t -- -- -std=c++14
+
+namespace std {
+template  struct remove_reference;
+
+template  struct remove_reference { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &> { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
+
+} // namespace std
+
+// Standard case.
+template  void f1(U &&SomeU) {
+  T SomeT(std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Ignore parentheses around the argument to std::move().
+template  void f2(U &&SomeU) {
+  T SomeT(std::move((SomeU)));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward((SomeU)));
+}
+
+// Handle the case correctly where std::move() is being used through a using
+// declaration.
+template  void f3(U &&SomeU) {
+  using std::move;
+  T SomeT(move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Handle the case correctly where a global specifier is prepended to
+// std::move().
+template  void f4(U &&SomeU) {
+  T SomeT(::std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(::std::forward(SomeU));
+}
+
+// Create a correct fix if there are spaces around the scope resolution
+// operator.
+template  void f5(U &&SomeU) {
+  {
+T SomeT(::  std  ::  move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(::std::forward(SomeU));
+  }
+  {
+T SomeT(std  ::  move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(std::forward(SomeU));
+  }
+}
+
+// Ignore const rvalue reference parameters.
+template  void f6(const U &&SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the argument to std::move() is a lambda parameter (and
+// thus not actually a parameter of the function template).
+template  void f7() {
+  [](U &&SomeU) { T SomeT(std::move(SomeU)); };
+}
+
+// Ignore the case where the argument is a lvalue reference.
+template  void f8(U &SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the template parameter is a class template parameter
+// (i.e. no template argument deduction is taking place).
+template  class SomeClass {
+  void f(U &&SomeU) { T SomeT(std::move(SomeU)); }
+};
+
+// Ignore the case where the function parameter in the template isn't an rvalue
+// reference but the template argument is explicitly set to be an rvalue
+// reference.
+class A {};
+template  void foo(T);
+void f8() {
+  A a;
+  foo(std::move(a));
+}
+
+// A warning is output, but no fix is suggested, if a macro is used to rename
+// std::move.
+#define MOVE(x) std::move((x))
+template  void f9(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the argument is passed outside of the macro.
+#undef MOVE
+#define MOVE std::move
+template  void f10(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the macro does not include the "std" namespace.
+#undef MOVE
+#define MOVE move
+template  void f11(U &&SomeU) {
+  T SomeT(std::MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Handle the case correctly where the forwarding reference is a parameter of a
+// generic lambda.
+template  void f12() {
+  [] (auto&& x) { T SomeT(std::move(x)); };
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: forwarding reference passed to
+  // CHECK-FIXES: [] (auto&& x) { T SomeT(std::forward(x)); }
+}
Index: docs/clang-tidy/checks/misc-move-forwarding-reference.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-move-forwarding-reference.rst
@@ -0,0 +1,60 @@
+.. title:: clang-tidy - misc-move-forwarding-reference
+
+misc-move-forwar

Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-30 Thread Martin Böhme via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL280077: [clang-tidy] Add check 
'misc-move-forwarding-reference' (authored by mboehme).

Changed prior to commit:
  https://reviews.llvm.org/D0?vs=69665&id=69666#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D0

Files:
  clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
  clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp
  clang-tools-extra/trunk/clang-tidy/misc/MoveForwardingReferenceCheck.cpp
  clang-tools-extra/trunk/clang-tidy/misc/MoveForwardingReferenceCheck.h
  clang-tools-extra/trunk/docs/ReleaseNotes.rst
  clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/trunk/docs/clang-tidy/checks/misc-move-forwarding-reference.rst
  clang-tools-extra/trunk/test/clang-tidy/misc-move-forwarding-reference.cpp

Index: clang-tools-extra/trunk/clang-tidy/misc/MoveForwardingReferenceCheck.h
===
--- clang-tools-extra/trunk/clang-tidy/misc/MoveForwardingReferenceCheck.h
+++ clang-tools-extra/trunk/clang-tidy/misc/MoveForwardingReferenceCheck.h
@@ -0,0 +1,49 @@
+//===--- MoveForwardingReferenceCheck.h - clang-tidy --===//
+//
+// 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_MISC_MOVEFORWARDINGREFERENCECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVEFORWARDINGREFERENCECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// The check warns if std::move is applied to a forwarding reference (i.e. an
+/// rvalue reference of a function template argument type).
+///
+/// If a developer is unaware of the special rules for template argument
+/// deduction on forwarding references, it will seem reasonable to apply
+/// std::move to the forwarding reference, in the same way that this would be
+/// done for a "normal" rvalue reference.
+///
+/// This has a consequence that is usually unwanted and possibly surprising: if
+/// the function that takes the forwarding reference as its parameter is called
+/// with an lvalue, that lvalue will be moved from (and hence placed into an
+/// indeterminate state) even though no std::move was applied to the lvalue at
+/// the call site.
+//
+/// The check suggests replacing the std::move with a std::forward.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-move-forwarding-reference.html
+class MoveForwardingReferenceCheck : public ClangTidyCheck {
+public:
+  MoveForwardingReferenceCheck(StringRef Name, ClangTidyContext *Context)
+  : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVEFORWARDINGREFERENCECHECK_H
Index: clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
===
--- clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
+++ clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
@@ -19,6 +19,7 @@
   MisplacedWideningCastCheck.cpp
   MoveConstantArgumentCheck.cpp
   MoveConstructorInitCheck.cpp
+  MoveForwardingReferenceCheck.cpp
   MultipleStatementMacroCheck.cpp
   NewDeleteOverloadsCheck.cpp
   NoexceptMoveConstructorCheck.cpp
Index: clang-tools-extra/trunk/clang-tidy/misc/MoveForwardingReferenceCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/misc/MoveForwardingReferenceCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/misc/MoveForwardingReferenceCheck.cpp
@@ -0,0 +1,134 @@
+//===--- MoveForwardingReferenceCheck.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 "MoveForwardingReferenceCheck.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+static void replaceMoveWithForward(const UnresolvedLookupExpr *Callee,
+   const ParmVarDecl *ParmVar,
+   const TemplateTypeParmDecl *TypeParmDecl,
+   DiagnosticBuilder &Diag,
+   const ASTContext &Context) {
+  const SourceManager &SM = C

Re: [PATCH] D23842: [CFG] Add iterator_ranges to CFG and CFGBlock.

2016-09-12 Thread Martin Böhme via cfe-commits
This revision was automatically updated to reflect the committed changes.
mboehme marked an inline comment as done.
Closed by commit rL281200: [CFG] Add iterator_ranges to CFG and CFGBlock. 
(authored by mboehme).

Changed prior to commit:
  https://reviews.llvm.org/D23842?vs=69129&id=70981#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D23842

Files:
  cfe/trunk/include/clang/Analysis/CFG.h

Index: cfe/trunk/include/clang/Analysis/CFG.h
===
--- cfe/trunk/include/clang/Analysis/CFG.h
+++ cfe/trunk/include/clang/Analysis/CFG.h
@@ -22,6 +22,7 @@
 #include "llvm/ADT/GraphTraits.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/iterator_range.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/raw_ostream.h"
@@ -522,11 +523,15 @@
   typedef AdjacentBlocks::const_iterator  const_pred_iterator;
   typedef AdjacentBlocks::reverse_iterator  pred_reverse_iterator;
   typedef AdjacentBlocks::const_reverse_iterator  const_pred_reverse_iterator;
+  typedef llvm::iterator_range  pred_range;
+  typedef llvm::iterator_range  pred_const_range;
 
   typedef AdjacentBlocks::iterator  succ_iterator;
   typedef AdjacentBlocks::const_iterator  const_succ_iterator;
   typedef AdjacentBlocks::reverse_iterator  succ_reverse_iterator;
   typedef AdjacentBlocks::const_reverse_iterator  const_succ_reverse_iterator;
+  typedef llvm::iterator_range  succ_range;
+  typedef llvm::iterator_range  succ_const_range;
 
   pred_iteratorpred_begin(){ return Preds.begin();   }
   pred_iteratorpred_end()  { return Preds.end(); }
@@ -538,6 +543,13 @@
   const_pred_reverse_iterator  pred_rbegin() const { return Preds.rbegin();  }
   const_pred_reverse_iterator  pred_rend()   const { return Preds.rend();}
 
+  pred_range   preds() {
+return pred_range(pred_begin(), pred_end());
+  }
+  pred_const_range preds() const {
+return pred_const_range(pred_begin(), pred_end());
+  }
+
   succ_iteratorsucc_begin(){ return Succs.begin();   }
   succ_iteratorsucc_end()  { return Succs.end(); }
   const_succ_iterator  succ_begin()  const { return Succs.begin();   }
@@ -548,6 +560,13 @@
   const_succ_reverse_iterator  succ_rbegin() const { return Succs.rbegin();  }
   const_succ_reverse_iterator  succ_rend()   const { return Succs.rend();}
 
+  succ_range   succs() {
+return succ_range(succ_begin(), succ_end());
+  }
+  succ_const_range succs() const {
+return succ_const_range(succ_begin(), succ_end());
+  }
+
   unsigned succ_size()   const { return Succs.size();}
   bool succ_empty()  const { return Succs.empty();   }
 
@@ -840,6 +859,7 @@
 
   typedef llvm::DenseMap::const_iterator
 synthetic_stmt_iterator;
+  typedef llvm::iterator_range synthetic_stmt_range;
 
   /// Iterates over synthetic DeclStmts in the CFG.
   ///
@@ -855,6 +875,11 @@
 return SyntheticDeclStmts.end();
   }
 
+  /// \sa synthetic_stmt_begin
+  synthetic_stmt_range synthetic_stmts() const {
+return synthetic_stmt_range(synthetic_stmt_begin(), synthetic_stmt_end());
+  }
+
   
//======//
   // Member templates useful for various batch operations over CFGs.
   
//======//


Index: cfe/trunk/include/clang/Analysis/CFG.h
===
--- cfe/trunk/include/clang/Analysis/CFG.h
+++ cfe/trunk/include/clang/Analysis/CFG.h
@@ -22,6 +22,7 @@
 #include "llvm/ADT/GraphTraits.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/iterator_range.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/raw_ostream.h"
@@ -522,11 +523,15 @@
   typedef AdjacentBlocks::const_iterator  const_pred_iterator;
   typedef AdjacentBlocks::reverse_iterator  pred_reverse_iterator;
   typedef AdjacentBlocks::const_reverse_iterator  const_pred_reverse_iterator;
+  typedef llvm::iterator_range  pred_range;
+  typedef llvm::iterator_range  pred_const_range;
 
   typedef AdjacentBlocks::iterator  succ_iterator;
   typedef AdjacentBlocks::const_iterator  const_succ_iterator;
   typedef AdjacentBlocks::reverse_iterator  succ_reverse_iterator;
   typedef AdjacentBlocks::const_reverse_iterator  const_succ_reverse_iterator;
+  typedef llvm::iterator_range  succ_range;
+  typedef llvm::it

Re: [PATCH] D23353: [clang-tidy] Add check 'misc-use-after-move'

2016-09-14 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 71312.
mboehme marked 6 inline comments as done.
mboehme added a comment.
Herald added subscribers: mgorny, beanz.

Responses to reviewer comments.


https://reviews.llvm.org/D23353

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/UseAfterMoveCheck.cpp
  clang-tidy/misc/UseAfterMoveCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-use-after-move.rst
  test/clang-tidy/misc-use-after-move.cpp

Index: test/clang-tidy/misc-use-after-move.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-use-after-move.cpp
@@ -0,0 +1,1039 @@
+// RUN: %check_clang_tidy %s misc-use-after-move %t
+
+typedef decltype(nullptr) nullptr_t;
+
+namespace std {
+typedef unsigned size_t;
+
+template 
+struct unique_ptr {
+  unique_ptr();
+  T *get() const;
+};
+
+template 
+struct shared_ptr {
+  shared_ptr();
+  T *get() const;
+};
+
+#define DECLARE_STANDARD_CONTAINER(name) \
+  template   \
+  struct name {  \
+name();  \
+void clear();\
+bool empty();\
+  }
+
+#define DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(name) \
+  template   \
+  struct name {  \
+name();  \
+void clear();\
+bool empty();\
+void assign(size_t, const T &);  \
+  }
+
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(basic_string);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(vector);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(deque);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(forward_list);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(list);
+DECLARE_STANDARD_CONTAINER(set);
+DECLARE_STANDARD_CONTAINER(map);
+DECLARE_STANDARD_CONTAINER(multiset);
+DECLARE_STANDARD_CONTAINER(multimap);
+DECLARE_STANDARD_CONTAINER(unordered_set);
+DECLARE_STANDARD_CONTAINER(unordered_map);
+DECLARE_STANDARD_CONTAINER(unordered_multiset);
+DECLARE_STANDARD_CONTAINER(unordered_multimap);
+
+typedef basic_string string;
+
+template 
+struct remove_reference;
+
+template 
+struct remove_reference {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &> {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &&> {
+  typedef _Tp type;
+};
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) noexcept {
+  return static_cast::type &&>(__t);
+}
+
+} // namespace std
+
+class A {
+public:
+  A();
+  A(const A &);
+  A(A &&);
+
+  A &operator=(const A &);
+  A &operator=(A &&);
+
+  void foo() const;
+  int getInt() const;
+
+  operator bool() const;
+
+  int i;
+};
+
+
+// General tests.
+
+// Simple case.
+void simple() {
+  A a;
+  a.foo();
+  A other_a = std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:15: note: move occurred here
+}
+
+// A warning should only be emitted for one use-after-move.
+void onlyFlagOneUseAfterMove() {
+  A a;
+  a.foo();
+  A other_a = std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:15: note: move occurred here
+  a.foo();
+}
+
+void moveAfterMove() {
+  // Move-after-move also counts as a use.
+  {
+A a;
+std::move(a);
+std::move(a);
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: 'a' used after it was moved
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  // This is also true if the move itself turns into the use on the second loop
+  // iteration.
+  {
+A a;
+for (int i = 0; i < 10; ++i) {
+  std::move(a);
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-2]]:7: note: move occurred here
+}
+  }
+}
+
+// Checks also works on function parameters that have a use-after move.
+void parameters(A a) {
+  std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:3: note: move occurred here
+}
+
+void uniquePtrAndSharedPtr() {
+  // Use-after-moves on std::unique_ptr<> or std::shared_ptr<> aren't flagged.
+  {
+std::unique_ptr ptr;
+std::move(ptr);
+ptr.get();
+  }
+  {
+std::shared_ptr ptr;
+std::move(ptr);
+ptr.get();
+  }
+  // This is also true if the std::unique_ptr<> or std::shared_ptr<> is wrapped
+  // in a typedef.
+  {
+typedef std::unique_ptr PtrToA;
+PtrToA ptr;
+std::move(ptr);
+ptr.get();
+  }
+  {
+typedef std::shared_ptr PtrToA;
+PtrToA ptr;
+std::move(ptr);
+ptr.get();
+  }
+  // And it's also true if the template 

Re: [PATCH] D23353: [clang-tidy] Add check 'misc-use-after-move'

2016-09-14 Thread Martin Böhme via cfe-commits
mboehme marked an inline comment as done.
mboehme added a comment.

https://reviews.llvm.org/D23353



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D23353: [clang-tidy] Add check 'misc-use-after-move'

2016-09-14 Thread Martin Böhme via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL281453: [clang-tidy] Add check 'misc-use-after-move' 
(authored by mboehme).

Changed prior to commit:
  https://reviews.llvm.org/D23353?vs=71312&id=71313#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D23353

Files:
  clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
  clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp
  clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
  clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.h
  clang-tools-extra/trunk/docs/ReleaseNotes.rst
  clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
  clang-tools-extra/trunk/docs/clang-tidy/checks/misc-use-after-move.rst
  clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp

Index: clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.h
===
--- clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.h
+++ clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.h
@@ -0,0 +1,36 @@
+//===--- UseAfterMoveCheck.h - clang-tidy -===//
+//
+// 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_MISC_USEAFTERMOVECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEAFTERMOVECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// The check warns if an object is used after it has been moved, without an
+/// intervening reinitialization.
+///
+/// For details, see the user-facing documentation:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-use-after-move.html
+class UseAfterMoveCheck : public ClangTidyCheck {
+public:
+  UseAfterMoveCheck(StringRef Name, ClangTidyContext *Context)
+  : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEAFTERMOVECHECK_H
Index: clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
===
--- clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
+++ clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
@@ -43,6 +43,7 @@
   UnusedParametersCheck.cpp
   UnusedRAIICheck.cpp
   UnusedUsingDeclsCheck.cpp
+  UseAfterMoveCheck.cpp
   VirtualNearMissCheck.cpp
 
   LINK_LIBS
Index: clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
@@ -0,0 +1,643 @@
+//===--- UseAfterMoveCheck.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 "UseAfterMoveCheck.h"
+
+#include "clang/Analysis/CFG.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+namespace {
+
+/// Provides information about the evaluation order of (sub-)expressions within
+/// a `CFGBlock`.
+///
+/// While a `CFGBlock` does contain individual `CFGElement`s for some
+/// sub-expressions, the order in which those `CFGElement`s appear reflects
+/// only one possible order in which the sub-expressions may be evaluated.
+/// However, we want to warn if any of the potential evaluation orders can lead
+/// to a use-after-move, not just the one contained in the `CFGBlock`.
+///
+/// This class implements only a simplified version of the C++ sequencing rules
+/// that is, however, sufficient for the purposes of this check. The main
+/// limitation is that we do not distinguish between value computation and side
+/// effect -- see the "Implementation" section for more details.
+///
+/// Note: `SequenceChecker` from SemaChecking.cpp does a similar job (and much
+/// more thoroughly), but using it would require
+/// - Pulling `SequenceChecker` out into a header file (i.e. making it part of
+///   the API),
+/// - Removing the dependency of `SequenceChecker` on `Sema`, and
+/// - (Probably) modifying `SequenceChecker` to make it suitable to be used in
+///   this context.
+/// For the moment, it seems preferable to re-implement our own v

[PATCH] D24550: [clang-tidy] Make test for misc-use-after-move pass under Windows

2016-09-14 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: alexfh.
mboehme added a subscriber: cfe-commits.

Adds -fno-delayed-template-parsing

https://reviews.llvm.org/D24550

Files:
  test/clang-tidy/misc-use-after-move.cpp

Index: test/clang-tidy/misc-use-after-move.cpp
===
--- test/clang-tidy/misc-use-after-move.cpp
+++ test/clang-tidy/misc-use-after-move.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s misc-use-after-move %t
+// RUN: %check_clang_tidy %s misc-use-after-move %t -- -- -std=c++11 
-fno-delayed-template-parsing
 
 typedef decltype(nullptr) nullptr_t;
 


Index: test/clang-tidy/misc-use-after-move.cpp
===
--- test/clang-tidy/misc-use-after-move.cpp
+++ test/clang-tidy/misc-use-after-move.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s misc-use-after-move %t
+// RUN: %check_clang_tidy %s misc-use-after-move %t -- -- -std=c++11 -fno-delayed-template-parsing
 
 typedef decltype(nullptr) nullptr_t;
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D24550: [clang-tidy] Make test for misc-use-after-move pass under Windows

2016-09-14 Thread Martin Böhme via cfe-commits
mboehme added a comment.

Single-line trivial change, will submit without review. Please let me know if 
you have any objections.


https://reviews.llvm.org/D24550



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D24550: [clang-tidy] Make test for misc-use-after-move pass under Windows

2016-09-14 Thread Martin Böhme via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL281455: [clang-tidy] Make test for misc-use-after-move pass 
under Windows (authored by mboehme).

Changed prior to commit:
  https://reviews.llvm.org/D24550?vs=71318&id=71319#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D24550

Files:
  clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp

Index: clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s misc-use-after-move %t
+// RUN: %check_clang_tidy %s misc-use-after-move %t -- -- -std=c++11 
-fno-delayed-template-parsing
 
 typedef decltype(nullptr) nullptr_t;
 


Index: clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s misc-use-after-move %t
+// RUN: %check_clang_tidy %s misc-use-after-move %t -- -- -std=c++11 -fno-delayed-template-parsing
 
 typedef decltype(nullptr) nullptr_t;
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [clang-tools-extra] r281453 - [clang-tidy] Add check 'misc-use-after-move'

2016-09-14 Thread Martin Böhme via cfe-commits
>
> While I'm excited to see this go in anywhere, I have to say I'm a bit sad
> it isn't going in as a warning and instead inside clang-tidy. This has been
> a much requested warning from Clang for many years.
>
> Is there a concise description of why this design was chosen? Are there
> specific problems that make it infeasible to be a warnings? Is there maybe
> a plan to move it to a warning after some set of issues are addressed?
>

Yes, my hope is that this can be moved to a warning, and others have
expressed the same thought to me.

There are two main issues that need to be addressed before this can be made
a warning:

   - I suspect (though I haven't measured) that the implementation isn't
   currently efficient enough to be made a Clang warning.
   - There are a number of scenarios in which the check warns when arguably
   it should not. These are:
  - User-defined types that make guarantees about the state of a
  moved-from object (in the way that std::unique_ptr and
std::shared_ptr do).
  Some form of annotation could be used to indicate that this is the case.
  - User-defined types that provide a member function to reinitialize
  the entire object (the way that clear() does on the standard container
  classes). These could either again be annotated in some way, or we could
  simply assume that any non-const member function reinitializes the object.
  - Tests for move constructors / move assignment operators. Often,
  these tests check that a moved-from object is left in a certain
state, even
  if the class in question does not provide such a guarantee to
clients (the
  intent being to check that the move constructor / move
assignment operator
  do not simply perform a copy).

All of these scenarios are probably somewhat controversial, but I don't
think there's a broad consensus that any of them should be prohibited, so
there needs to be a way to silence the warning in these cases.


I do hope to resolve these issues and make this check into a warning, but
in the meantime, having it available as a clang-tidy check seems like a
good way to gather feedback and gain experience with it.

Since you say this is a much-requested warning: Any pointers to previous
discussions that I should be aware of?


See user-facing documentation for details.
>>
>
> In general, I suspect at least some more context should be provided in
> change descriptions. =]
>

Thanks -- still new to this.

The intent was not to repeat myself, but I evidently went a bit far with
that. ;) Is it of value if I provide a short summary on this thread, or is
this just something I should keep in mind for future patches?
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D24561: [clang-tidy] Add dependency on clangAnalysis to clangTidyMiscModule

2016-09-14 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a subscriber: cfe-commits.
Herald added subscribers: mgorny, beanz.

This is needed for the recently submitted misc-use-after-move check (rL281453).
For some reason, this still built under Linux, but it caused the PPC build bot
to fail.

https://reviews.llvm.org/D24561

Files:
  clang-tidy/misc/CMakeLists.txt

Index: clang-tidy/misc/CMakeLists.txt
===
--- clang-tidy/misc/CMakeLists.txt
+++ clang-tidy/misc/CMakeLists.txt
@@ -47,6 +47,7 @@
   VirtualNearMissCheck.cpp
 
   LINK_LIBS
+  clangAnalysis
   clangAST
   clangASTMatchers
   clangBasic


Index: clang-tidy/misc/CMakeLists.txt
===
--- clang-tidy/misc/CMakeLists.txt
+++ clang-tidy/misc/CMakeLists.txt
@@ -47,6 +47,7 @@
   VirtualNearMissCheck.cpp
 
   LINK_LIBS
+  clangAnalysis
   clangAST
   clangASTMatchers
   clangBasic
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D24561: [clang-tidy] Add dependency on clangAnalysis to clangTidyMiscModule

2016-09-14 Thread Martin Böhme via cfe-commits
mboehme added a comment.

Trivial build fix, will submit without review.


https://reviews.llvm.org/D24561



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D24561: [clang-tidy] Add dependency on clangAnalysis to clangTidyMiscModule

2016-09-14 Thread Martin Böhme via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL281460: [clang-tidy] Add dependency on clangAnalysis to 
clangTidyMiscModule (authored by mboehme).

Changed prior to commit:
  https://reviews.llvm.org/D24561?vs=71345&id=71346#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D24561

Files:
  clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt

Index: clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
===
--- clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
+++ clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
@@ -47,6 +47,7 @@
   VirtualNearMissCheck.cpp
 
   LINK_LIBS
+  clangAnalysis
   clangAST
   clangASTMatchers
   clangBasic


Index: clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
===
--- clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
+++ clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
@@ -47,6 +47,7 @@
   VirtualNearMissCheck.cpp
 
   LINK_LIBS
+  clangAnalysis
   clangAST
   clangASTMatchers
   clangBasic
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D24561: [clang-tidy] Add dependency on clangAnalysis to clangTidyMiscModule

2016-09-14 Thread Martin Böhme via cfe-commits
mboehme added a comment.

Thanks!


Repository:
  rL LLVM

https://reviews.llvm.org/D24561



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D26041: [clang-tidy] Extend misc-use-after-move to support unique_ptr and shared_ptr.

2016-10-27 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: alexfh.
mboehme added a subscriber: cfe-commits.

As a unique_ptr or shared_ptr that has been moved from is guaranteed to be null,
we only warn if the pointer is dereferenced.


https://reviews.llvm.org/D26041

Files:
  clang-tidy/misc/UseAfterMoveCheck.cpp
  docs/clang-tidy/checks/misc-use-after-move.rst
  test/clang-tidy/misc-use-after-move.cpp

Index: test/clang-tidy/misc-use-after-move.cpp
===
--- test/clang-tidy/misc-use-after-move.cpp
+++ test/clang-tidy/misc-use-after-move.cpp
@@ -9,12 +9,21 @@
 struct unique_ptr {
   unique_ptr();
   T *get() const;
+  explicit operator bool() const;
+  void reset(T *ptr);
+  T &operator*() const;
+  T *operator->() const;
+  T& operator[](size_t i) const;
 };
 
 template 
 struct shared_ptr {
   shared_ptr();
   T *get() const;
+  explicit operator bool() const;
+  void reset(T *ptr);
+  T &operator*() const;
+  T *operator->() const;
 };
 
 #define DECLARE_STANDARD_CONTAINER(name) \
@@ -147,19 +156,50 @@
 }
 
 void uniquePtrAndSharedPtr() {
-  // Use-after-moves on std::unique_ptr<> or std::shared_ptr<> aren't flagged.
+  // std::unique_ptr<> and std::shared_ptr<> are guaranteed to be null after
+  // a std::move. So the check only flags accesses that would dereference the
+  // pointer.
   {
 std::unique_ptr ptr;
 std::move(ptr);
 ptr.get();
+static_cast(ptr);
+*ptr;
+// CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'ptr' used after it was moved
+// CHECK-MESSAGES: [[@LINE-5]]:5: note: move occurred here
+  }
+  {
+std::unique_ptr ptr;
+std::move(ptr);
+ptr->foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  {
+std::unique_ptr ptr;
+std::move(ptr);
+ptr[0];
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
   }
   {
 std::shared_ptr ptr;
 std::move(ptr);
 ptr.get();
+static_cast(ptr);
+*ptr;
+// CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'ptr' used after it was moved
+// CHECK-MESSAGES: [[@LINE-5]]:5: note: move occurred here
+  }
+  {
+std::shared_ptr ptr;
+std::move(ptr);
+ptr->foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
   }
-  // This is also true if the std::unique_ptr<> or std::shared_ptr<> is wrapped
-  // in a typedef.
+  // Make sure we recognize std::unique_ptr<> or std::shared_ptr<> if they're
+  // wrapped in a typedef.
   {
 typedef std::unique_ptr PtrToA;
 PtrToA ptr;
@@ -172,15 +212,27 @@
 std::move(ptr);
 ptr.get();
   }
-  // And it's also true if the template argument is a little more involved.
+  // And we don't get confused if the template argument is a little more
+  // involved.
   {
 struct B {
   typedef A AnotherNameForA;
 };
 std::unique_ptr ptr;
 std::move(ptr);
 ptr.get();
   }
+  // We don't give any special treatment to types that are called "unique_ptr"
+  // or "shared_ptr" but are not in the "::std" namespace.
+  {
+struct unique_ptr {
+  void get();
+} ptr;
+std::move(ptr);
+ptr.get();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
 }
 
 // The check also works in member functions.
@@ -795,6 +847,23 @@
   }
 }
 
+// Resetting the standard smart pointer types using reset() is treated as a
+// re-initialization.
+void standardSmartPointerResetIsReinit() {
+  {
+std::unique_ptr ptr;
+std::move(ptr);
+ptr.reset(new A);
+*ptr;
+  }
+  {
+std::shared_ptr ptr;
+std::move(ptr);
+ptr.reset(new A);
+*ptr;
+  }
+}
+
 
 // Tests related to order of evaluation within expressions
 
Index: docs/clang-tidy/checks/misc-use-after-move.rst
===
--- docs/clang-tidy/checks/misc-use-after-move.rst
+++ docs/clang-tidy/checks/misc-use-after-move.rst
@@ -75,10 +75,6 @@
   std::cout << str;
 }
 
-No warnings are emitted for objects of type ``std::unique_ptr`` and
-``std::shared_ptr``, as they have defined move behavior. (Objects of these
-classes are guaranteed to be empty after they have been moved from.)
-
 Subsections below explain more precisely what exactly the check considers to be
 a move, use, and reinitialization.
 
@@ -153,6 +149,13 @@
 Any occurrence of the moved variable that is not a reinitialization (see below)
 is considered to be a use.
 
+An exception to this are objects of type ``std::unique_ptr`` and
+``std::shared_ptr``, which have defined move behavior (objects of these
+classes are guaranteed to be 

[PATCH] D26041: [clang-tidy] Extend misc-use-after-move to support unique_ptr and shared_ptr.

2016-11-01 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 76655.
mboehme added a comment.

- Responses to reviewer comments


https://reviews.llvm.org/D26041

Files:
  clang-tidy/misc/UseAfterMoveCheck.cpp
  docs/clang-tidy/checks/misc-use-after-move.rst
  test/clang-tidy/misc-use-after-move.cpp

Index: test/clang-tidy/misc-use-after-move.cpp
===
--- test/clang-tidy/misc-use-after-move.cpp
+++ test/clang-tidy/misc-use-after-move.cpp
@@ -9,12 +9,27 @@
 struct unique_ptr {
   unique_ptr();
   T *get() const;
+  explicit operator bool() const;
+  void reset(T *ptr);
+  T &operator*() const;
+  T *operator->() const;
+  T& operator[](size_t i) const;
 };
 
 template 
 struct shared_ptr {
   shared_ptr();
   T *get() const;
+  explicit operator bool() const;
+  void reset(T *ptr);
+  T &operator*() const;
+  T *operator->() const;
+};
+
+template 
+struct weak_ptr {
+  weak_ptr();
+  bool expired() const;
 };
 
 #define DECLARE_STANDARD_CONTAINER(name) \
@@ -146,20 +161,58 @@
   // CHECK-MESSAGES: [[@LINE-3]]:3: note: move occurred here
 }
 
-void uniquePtrAndSharedPtr() {
-  // Use-after-moves on std::unique_ptr<> or std::shared_ptr<> aren't flagged.
+void standardSmartPtr() {
+  // std::unique_ptr<>, std::shared_ptr<> and std::weak_ptr<> are guaranteed to
+  // be null after a std::move. So the check only flags accesses that would
+  // dereference the pointer.
   {
 std::unique_ptr ptr;
 std::move(ptr);
 ptr.get();
+static_cast(ptr);
+*ptr;
+// CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'ptr' used after it was moved
+// CHECK-MESSAGES: [[@LINE-5]]:5: note: move occurred here
+  }
+  {
+std::unique_ptr ptr;
+std::move(ptr);
+ptr->foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  {
+std::unique_ptr ptr;
+std::move(ptr);
+ptr[0];
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
   }
   {
 std::shared_ptr ptr;
 std::move(ptr);
 ptr.get();
+static_cast(ptr);
+*ptr;
+// CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'ptr' used after it was moved
+// CHECK-MESSAGES: [[@LINE-5]]:5: note: move occurred here
+  }
+  {
+std::shared_ptr ptr;
+std::move(ptr);
+ptr->foo();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
   }
-  // This is also true if the std::unique_ptr<> or std::shared_ptr<> is wrapped
-  // in a typedef.
+  {
+// std::weak_ptr<> cannot be dereferenced directly, so we only check that
+// member functions may be called on it after a move.
+std::weak_ptr ptr;
+std::move(ptr);
+ptr.expired();
+  }
+  // Make sure we recognize std::unique_ptr<> or std::shared_ptr<> if they're
+  // wrapped in a typedef.
   {
 typedef std::unique_ptr PtrToA;
 PtrToA ptr;
@@ -172,15 +225,27 @@
 std::move(ptr);
 ptr.get();
   }
-  // And it's also true if the template argument is a little more involved.
+  // And we don't get confused if the template argument is a little more
+  // involved.
   {
 struct B {
   typedef A AnotherNameForA;
 };
 std::unique_ptr ptr;
 std::move(ptr);
 ptr.get();
   }
+  // We don't give any special treatment to types that are called "unique_ptr"
+  // or "shared_ptr" but are not in the "::std" namespace.
+  {
+struct unique_ptr {
+  void get();
+} ptr;
+std::move(ptr);
+ptr.get();
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
 }
 
 // The check also works in member functions.
@@ -795,6 +860,24 @@
   }
 }
 
+// Resetting the standard smart pointer types using reset() is treated as a
+// re-initialization. (We don't test std::weak_ptr<> because it can't be
+// dereferenced directly.)
+void standardSmartPointerResetIsReinit() {
+  {
+std::unique_ptr ptr;
+std::move(ptr);
+ptr.reset(new A);
+*ptr;
+  }
+  {
+std::shared_ptr ptr;
+std::move(ptr);
+ptr.reset(new A);
+*ptr;
+  }
+}
+
 
 // Tests related to order of evaluation within expressions
 
Index: docs/clang-tidy/checks/misc-use-after-move.rst
===
--- docs/clang-tidy/checks/misc-use-after-move.rst
+++ docs/clang-tidy/checks/misc-use-after-move.rst
@@ -75,10 +75,6 @@
   std::cout << str;
 }
 
-No warnings are emitted for objects of type ``std::unique_ptr`` and
-``std::shared_ptr``, as they have defined move behavior. (Objects of these
-classes are guaranteed to be empty after they have been moved from.)
-
 Subsections below explain more precisely what exactly the check considers 

[PATCH] D26041: [clang-tidy] Extend misc-use-after-move to support unique_ptr and shared_ptr.

2016-11-01 Thread Martin Böhme via cfe-commits
mboehme marked 4 inline comments as done.
mboehme added a comment.

Please take another look.




Comment at: clang-tidy/misc/UseAfterMoveCheck.cpp:467
+StringRef getName(const NamedDecl *ND) {
+  if (!ND->getIdentifier())
+return StringRef();

aaron.ballman wrote:
> This logic could be improved as:
> ```
> if (const auto *ID = ND->getIdentifier())
>   return ID->getName();
> return "";
> ```
> However, I'm not certain that this function is needed at all -- it's pretty 
> simple and is only used from `isStandardSmartPointer()`.
> However, I'm not certain that this function is needed at all -- it's pretty 
> simple and is only used from isStandardSmartPointer().

Good point -- I've inlined it there.



Comment at: clang-tidy/misc/UseAfterMoveCheck.cpp:482
+  StringRef Name = getName(RecordDecl);
+  if (Name != "unique_ptr" && Name != "shared_ptr")
+return false;

aaron.ballman wrote:
> Shouldn't this improvement also include `weak_ptr`?
Good point -- done.


https://reviews.llvm.org/D26041



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D26041: [clang-tidy] Extend misc-use-after-move to support unique_ptr and shared_ptr.

2016-11-02 Thread Martin Böhme via cfe-commits
This revision was automatically updated to reflect the committed changes.
mboehme marked 2 inline comments as done.
Closed by commit rL285842: [clang-tidy] Extend misc-use-after-move to support 
unique_ptr and shared_ptr. (authored by mboehme).

Changed prior to commit:
  https://reviews.llvm.org/D26041?vs=76655&id=76740#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D26041

Files:
  clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
  clang-tools-extra/trunk/docs/clang-tidy/checks/misc-use-after-move.rst
  clang-tools-extra/trunk/test/clang-tidy/misc-use-after-move.cpp

Index: clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
@@ -463,6 +463,26 @@
 });
 }
 
+bool isStandardSmartPointer(const ValueDecl *VD) {
+  const Type *TheType = VD->getType().getTypePtrOrNull();
+  if (!TheType)
+return false;
+
+  const CXXRecordDecl *RecordDecl = TheType->getAsCXXRecordDecl();
+  if (!RecordDecl)
+return false;
+
+  const IdentifierInfo *ID = RecordDecl->getIdentifier();
+  if (!ID)
+return false;
+
+  StringRef Name = ID->getName();
+  if (Name != "unique_ptr" && Name != "shared_ptr" && Name != "weak_ptr")
+return false;
+
+  return RecordDecl->getDeclContext()->isStdNamespace();
+}
+
 void UseAfterMoveFinder::getDeclRefs(
 const CFGBlock *Block, const Decl *MovedVariable,
 llvm::SmallPtrSetImpl *DeclRefs) {
@@ -472,17 +492,33 @@
 if (!S)
   continue;
 
-SmallVector Matches =
-match(findAll(declRefExpr(hasDeclaration(equalsNode(MovedVariable)),
-  unless(inDecltypeOrTemplateArg()))
-  .bind("declref")),
-  *S->getStmt(), *Context);
+auto addDeclRefs = [this, Block,
+DeclRefs](const ArrayRef Matches) {
+  for (const auto &Match : Matches) {
+const auto *DeclRef = Match.getNodeAs("declref");
+const auto *Operator = Match.getNodeAs("operator");
+if (DeclRef && BlockMap->blockContainingStmt(DeclRef) == Block) {
+  // Ignore uses of a standard smart pointer that don't dereference the
+  // pointer.
+  if (Operator || !isStandardSmartPointer(DeclRef->getDecl())) {
+DeclRefs->insert(DeclRef);
+  }
+}
+  }
+};
 
-for (const auto &Match : Matches) {
-  const auto *DeclRef = Match.getNodeAs("declref");
-  if (DeclRef && BlockMap->blockContainingStmt(DeclRef) == Block)
-DeclRefs->insert(DeclRef);
-}
+auto DeclRefMatcher = declRefExpr(hasDeclaration(equalsNode(MovedVariable)),
+  unless(inDecltypeOrTemplateArg()))
+  .bind("declref");
+
+addDeclRefs(match(findAll(DeclRefMatcher), *S->getStmt(), *Context));
+addDeclRefs(match(
+findAll(cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("*"),
+  hasOverloadedOperatorName("->"),
+  hasOverloadedOperatorName("[]")),
+hasArgument(0, DeclRefMatcher))
+.bind("operator")),
+*S->getStmt(), *Context));
   }
 }
 
@@ -500,6 +536,9 @@
  "::std::unordered_set", "::std::unordered_map",
  "::std::unordered_multiset", "::std::unordered_multimap")));
 
+  auto StandardSmartPointerTypeMatcher = hasType(cxxRecordDecl(
+  hasAnyName("::std::unique_ptr", "::std::shared_ptr", "::std::weak_ptr")));
+
   // Matches different types of reinitialization.
   auto ReinitMatcher =
   stmt(anyOf(
@@ -521,6 +560,10 @@
// is called on any of the other containers, this will be
// flagged by a compile error anyway.
callee(cxxMethodDecl(hasAnyName("clear", "assign",
+   // reset() on standard smart pointers.
+   cxxMemberCallExpr(
+   on(allOf(DeclRefMatcher, StandardSmartPointerTypeMatcher)),
+   callee(cxxMethodDecl(hasName("reset",
// Passing variable to a function as a non-const pointer.
callExpr(forEachArgumentWithParam(
unaryOperator(hasOperatorName("&"),
@@ -587,15 +630,10 @@
   if (!getLangOpts().CPlusPlus11)
 return;
 
-  auto StandardSmartPointerTypeMatcher = hasType(
-  cxxRecordDecl(hasAnyName("::std::unique_ptr", "::std::shared_ptr")));
-
   auto CallMoveMatcher =
   callExpr(
   callee(functionDecl(hasName("::std::move"))), argumentCountIs(1),
-  hasArgument(
-  0,
-  declRefExpr(unless(StandardSmartPointerTypeMatcher)).bind("arg")),
+  hasArgument(0, declRefExpr().bind("arg")),
   anyOf(hasAncestor(lambdaExpr().b

[PATCH] D22566: Make RecursiveASTVisitor visit lambda capture initialization expressions

2016-07-20 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: klimek.
mboehme added a subscriber: cfe-commits.
Herald added a subscriber: klimek.

Lambda capture initializations are part of the explicit source code and 
therefore should be visited by default but, so far, RecursiveASTVisitor does 
not visit them.

This appears to be an oversight. Because the lambda body needs custom handling 
(calling TraverseLambdaBody()), the DEF_TRAVERSE_STMT for LambdaExpr sets 
ShouldVisitChildren to false but then neglects to visit the lambda capture 
initializations. This patch adds code to visit the expressions associated with 
lambda capture initializations.

https://reviews.llvm.org/D22566

Files:
  include/clang/AST/RecursiveASTVisitor.h
  unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp

Index: unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
===
--- unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
+++ unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
@@ -191,6 +191,14 @@
 "void x(); void y() { x(); }"));
 }
 
+TEST(RecursiveASTVisitor, VisitsLambdaCaptureInit) {
+  DeclRefExprVisitor Visitor;
+  Visitor.ExpectMatch("i", 1, 20);
+  EXPECT_TRUE(Visitor.runOver(
+"void f() { int i; [i]{}; };",
+DeclRefExprVisitor::Lang_CXX11));
+}
+
 /* FIXME: According to Richard Smith this is a bug in the AST.
 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
   DeclRefExprVisitor Visitor;
Index: include/clang/AST/RecursiveASTVisitor.h
===
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -2254,6 +2254,9 @@
C != CEnd; ++C) {
 TRY_TO(TraverseLambdaCapture(S, C));
   }
+  for (Expr *Init : S->capture_inits()) {
+TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(Init);
+  }
 
   TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
   FunctionProtoTypeLoc Proto = TL.castAs();


Index: unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
===
--- unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
+++ unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
@@ -191,6 +191,14 @@
 "void x(); void y() { x(); }"));
 }
 
+TEST(RecursiveASTVisitor, VisitsLambdaCaptureInit) {
+  DeclRefExprVisitor Visitor;
+  Visitor.ExpectMatch("i", 1, 20);
+  EXPECT_TRUE(Visitor.runOver(
+"void f() { int i; [i]{}; };",
+DeclRefExprVisitor::Lang_CXX11));
+}
+
 /* FIXME: According to Richard Smith this is a bug in the AST.
 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
   DeclRefExprVisitor Visitor;
Index: include/clang/AST/RecursiveASTVisitor.h
===
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -2254,6 +2254,9 @@
C != CEnd; ++C) {
 TRY_TO(TraverseLambdaCapture(S, C));
   }
+  for (Expr *Init : S->capture_inits()) {
+TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(Init);
+  }
 
   TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
   FunctionProtoTypeLoc Proto = TL.castAs();
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-07-26 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 65484.
mboehme marked an inline comment as done.
mboehme added a comment.

Changes in response to reviewer comments


https://reviews.llvm.org/D0

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-move-forwarding-reference.rst
  test/clang-tidy/misc-move-forwarding-reference.cpp

Index: test/clang-tidy/misc-move-forwarding-reference.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-move-forwarding-reference.cpp
@@ -0,0 +1,102 @@
+// RUN: %check_clang_tidy %s misc-move-forwarding-reference %t
+
+namespace std {
+template  struct remove_reference;
+
+template  struct remove_reference { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &> { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
+
+} // namespace std
+
+// Standard case.
+template  void f1(U &&SomeU) {
+  T SomeT(std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Ignore parentheses around the argument to std::move().
+template  void f2(U &&SomeU) {
+  T SomeT(std::move((SomeU)));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward((SomeU)));
+}
+
+// Handle the case correctly where std::move() is being used through a using
+// declaration.
+template  void f3(U &&SomeU) {
+  using std::move;
+  T SomeT(move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Handle the case correctly where a global specifier is prepended to
+// std::move().
+template  void f4(U &&SomeU) {
+  T SomeT(::std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(::std::forward(SomeU));
+}
+
+// Ignore const rvalue reference parameters.
+template  void f5(const U &&SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the argument to std::move() is a lambda parameter (and
+// thus not actually a parameter of the function template).
+template  void f6() {
+  [](U &&SomeU) { T SomeT(std::move(SomeU)); };
+}
+
+// Ignore the case where the argument is a lvalue reference.
+template  void f7(U &SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the template parameter is a class template parameter
+// (i.e. no template argument deduction is taking place).
+template  class SomeClass {
+  void f(U &&SomeU) { T SomeT(std::move(SomeU)); }
+};
+
+// Ignore the case where the function parameter in the template isn't an rvalue
+// reference but the template argument is explicitly set to be an rvalue
+// reference.
+class A {};
+template  void foo(T);
+void f8() {
+  A a;
+  foo(std::move(a));
+}
+
+// A warning is output, but no fix is suggested, if a macro is used to rename
+// std::move.
+#define MOVE(x) std::move((x))
+template  void f9(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the argument is passed outside of the macro.
+#undef MOVE
+#define MOVE std::move
+template  void f10(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the macro does not include the "std" namespace.
+#undef MOVE
+#define MOVE move
+template  void f11(U &&SomeU) {
+  T SomeT(std::MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
Index: docs/clang-tidy/checks/misc-move-forwarding-reference.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-move-forwarding-reference.rst
@@ -0,0 +1,60 @@
+.. title:: clang-tidy - misc-move-forwarding-reference
+
+misc-move-forwarding-reference
+==
+
+Warns if ``std::move`` is called on a forwarding reference, for example:
+
+  .. code-block:: c++
+
+template 
+void foo(T&& t) {
+  bar(std::move(t));
+}
+
+`Forwarding references
+`_ should
+typically be passed to ``std::forward`` instead of ``std::move``, and this is
+the fix that will be suggested.
+
+(A forwarding reference is an rvalue reference of a type that is a deduced
+function template argument.)
+
+In this example, the suggested fix would be
+
+  .. code-block:: c++
+
+bar(std::forward(t));
+
+Background
+--
+
+Code like the example above is often written in the expectation that ``T&&``
+will al

Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-07-26 Thread Martin Böhme via cfe-commits
mboehme marked 13 inline comments as done.


Comment at: clang-tidy/misc/MoveForwardingReferenceCheck.cpp:20
@@ +19,3 @@
+
+static void ReplaceMoveWithForward(const UnresolvedLookupExpr *Callee,
+   const TemplateTypeParmType *TypeParmType,

sbenza wrote:
> aaron.ballman wrote:
> > Might as well pass `Context` by const reference rather than pointer.
> Function names start in lower case.
Sorry -- still getting used to LLVM naming conventions.


Comment at: clang-tidy/misc/MoveForwardingReferenceCheck.cpp:30
@@ +29,3 @@
+  Callee->getLocStart(),
+  Lexer::getLocForEndOfToken(Callee->getLocEnd(), 0, SM, LangOpts)),
+  SM, LangOpts);

sbenza wrote:
> Isn't this just 
> `CharSourceRange::getTokenRange(Callee->getLocStart(),Callee->getLocEnd())` ?
Thanks -- done.


Comment at: clang-tidy/misc/MoveForwardingReferenceCheck.cpp:43-53
@@ +42,13 @@
+// another namespace).
+const StringRef OriginalText =
+Lexer::getSourceText(CallRange, SM, LangOpts);
+if (OriginalText == "::std::move") {
+  Diag << FixItHint::CreateReplacement(CallRange, "::std::" + ForwardName);
+  // If the original text was simply "move", we conservatively still put a
+  // "std::" in front of the "forward". Rationale: Even if the code
+  // apparently had a "using std::move;", that doesn't tell us whether it
+  // also had a "using std::forward;".
+} else if (OriginalText == "std::move" || OriginalText == "move") {
+  Diag << FixItHint::CreateReplacement(CallRange, "std::" + ForwardName);
+}
+  }

etienneb wrote:
> alexfh wrote:
> > aaron.ballman wrote:
> > > I'm not certain I understand the benefit to this. We know it's a call to 
> > > std::move() from the standard namespace already, so why do we care about 
> > > the original text? I think it's reasonable to replace any call to move() 
> > > from the standard namespace with `::std::forward()`, so we should be able 
> > > to remove the if statements and not have to go read the original source 
> > > text from the source manager (which could involve, for instance, a query 
> > > for that text over a slow network).
> > I think, the value of this is to maintain consistency with the existing 
> > code in terms of whether the `std` namespace should be globally qualified 
> > or not. Changing `std::move` to `::std::forward` would sometimes be 
> > unwelcome, if the code doesn't use `::std` otherwise.
> I agree with alex, it's better to keep code consistency (programmer intend).
> But, at the same time, the check should be bomb proof for ugly cases like:
> ```
>   "std:: move"
>":: std::move",
> ```
> 
> For the moment, the code seems to propose a fix only when it's a known case,
> and a warning is emitted in every cases.
> why do we care about the original text?

See alexfh's comment -- my intent is to perserve the existing style in terms of 
whether "std" is globally qualified or not.


Comment at: clang-tidy/misc/MoveForwardingReferenceCheck.cpp:83
@@ +82,3 @@
+  // same function...
+  references(templateTypeParmType(hasDeclaration(hasDeclContext(
+  functionDecl().bind("context"

sbenza wrote:
> Will this trigger on code like this:
> 
> 
> ```
> template 
> void F(T);
> 
> void G() { F(std::move(str)); }
> ```
No, it won't -- I've added a test for this.

The reason it doesn't trigger is because the check only looks at the template 
itself, but not any instantiations (this is because the main matcher below 
matches for UnresolvedLookupExpr, which only exists in the template).


Comment at: clang-tidy/misc/MoveForwardingReferenceCheck.cpp:92
@@ +91,3 @@
+  Finder->addMatcher(
+  callExpr(callee(unresolvedLookupExpr().bind("lookup")),
+   argumentCountIs(1),

etienneb wrote:
> aaron.ballman wrote:
> > It might be a bit more clear if you made `isStdMove()` into a local AST 
> > matcher and called it from here.
> +1 I agree with Aaron here.
> 
> The match will also be more precise.
That was my original plan, but there doesn't seem to be a way to do this with 
an AST matcher, and I'm not sure whether it's desired that this should change 
or what would be the best way to change it.

The main issue is that the decls() contained in a UnresolvedLookupExpr aren't 
children of the UnresolvedLookupExpr, and RecursiveASTVisitor doesn't contain 
any special-case logic to visit them either. (A consequence of this is that 
they don't show up when dumping the AST.) This means that it isn't possible to 
match for them using unresolvedLookupExpr(has(...)), for example.

This is the reason I went with an explicit test inside the check(). But if you 
have a suggestion on how this could be changed into an AST matcher in a way 
that's consistent with the overall design of

Re: [PATCH] D22566: Make RecursiveASTVisitor visit lambda capture initialization expressions

2016-07-26 Thread Martin Böhme via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL276755: Make RecursiveASTVisitor visit lambda capture 
initialization expressions (authored by mboehme).

Changed prior to commit:
  https://reviews.llvm.org/D22566?vs=64665&id=65526#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D22566

Files:
  cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
  cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp

Index: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
===
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
@@ -2266,6 +2266,9 @@
C != CEnd; ++C) {
 TRY_TO(TraverseLambdaCapture(S, C));
   }
+  for (Expr *Init : S->capture_inits()) {
+TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(Init);
+  }
 
   TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
   FunctionProtoTypeLoc Proto = TL.castAs();
Index: cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
===
--- cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
+++ cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
@@ -191,6 +191,14 @@
 "void x(); void y() { x(); }"));
 }
 
+TEST(RecursiveASTVisitor, VisitsLambdaCaptureInit) {
+  DeclRefExprVisitor Visitor;
+  Visitor.ExpectMatch("i", 1, 20);
+  EXPECT_TRUE(Visitor.runOver(
+"void f() { int i; [i]{}; };",
+DeclRefExprVisitor::Lang_CXX11));
+}
+
 /* FIXME: According to Richard Smith this is a bug in the AST.
 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
   DeclRefExprVisitor Visitor;


Index: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
===
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
@@ -2266,6 +2266,9 @@
C != CEnd; ++C) {
 TRY_TO(TraverseLambdaCapture(S, C));
   }
+  for (Expr *Init : S->capture_inits()) {
+TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(Init);
+  }
 
   TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
   FunctionProtoTypeLoc Proto = TL.castAs();
Index: cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
===
--- cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
+++ cfe/trunk/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
@@ -191,6 +191,14 @@
 "void x(); void y() { x(); }"));
 }
 
+TEST(RecursiveASTVisitor, VisitsLambdaCaptureInit) {
+  DeclRefExprVisitor Visitor;
+  Visitor.ExpectMatch("i", 1, 20);
+  EXPECT_TRUE(Visitor.runOver(
+"void f() { int i; [i]{}; };",
+DeclRefExprVisitor::Lang_CXX11));
+}
+
 /* FIXME: According to Richard Smith this is a bug in the AST.
 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
   DeclRefExprVisitor Visitor;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D22903: [clang-tidy] Prepare modernize-loop-convert for upcoming changes in D22566

2016-07-27 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: klimek.
mboehme added a subscriber: cfe-commits.

D22566 will change RecursiveASTVisitor so that it descends into the 
initialization expressions for lambda captures.

modernize-loop-convert needs to be prepared for this so that it does not 
interpret these initialization expressions as invalid uses of the loop 
variable. The change has no ill effects without D22566 in place, i.e. the 
change does not depend on D22566.

https://reviews.llvm.org/D22903

Files:
  clang-tidy/modernize/LoopConvertUtils.cpp

Index: clang-tidy/modernize/LoopConvertUtils.cpp
===
--- clang-tidy/modernize/LoopConvertUtils.cpp
+++ clang-tidy/modernize/LoopConvertUtils.cpp
@@ -805,6 +805,18 @@
 }
 
 bool ForLoopIndexUseVisitor::TraverseStmt(Stmt *S) {
+  // If this is an initialization expression for a lambda capture, prune the
+  // traversal so that we don't end up diagnosing the contained DeclRefExpr as
+  // inconsistent usage. No need to record the usage here -- this is done in
+  // TraverseLambdaCapture().
+  if (const auto *LE = dyn_cast_or_null(NextStmtParent)) {
+// Any child of a LambdaExpr that isn't the body is an initialization
+// expression.
+if (S != LE->getBody()) {
+  return true;
+}
+  }
+
   // All this pointer swapping is a mechanism for tracking immediate parentage
   // of Stmts.
   const Stmt *OldNextParent = NextStmtParent;


Index: clang-tidy/modernize/LoopConvertUtils.cpp
===
--- clang-tidy/modernize/LoopConvertUtils.cpp
+++ clang-tidy/modernize/LoopConvertUtils.cpp
@@ -805,6 +805,18 @@
 }
 
 bool ForLoopIndexUseVisitor::TraverseStmt(Stmt *S) {
+  // If this is an initialization expression for a lambda capture, prune the
+  // traversal so that we don't end up diagnosing the contained DeclRefExpr as
+  // inconsistent usage. No need to record the usage here -- this is done in
+  // TraverseLambdaCapture().
+  if (const auto *LE = dyn_cast_or_null(NextStmtParent)) {
+// Any child of a LambdaExpr that isn't the body is an initialization
+// expression.
+if (S != LE->getBody()) {
+  return true;
+}
+  }
+
   // All this pointer swapping is a mechanism for tracking immediate parentage
   // of Stmts.
   const Stmt *OldNextParent = NextStmtParent;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22566: Make RecursiveASTVisitor visit lambda capture initialization expressions

2016-07-27 Thread Martin Böhme via cfe-commits
mboehme added a comment.

This was reverted in https://reviews.llvm.org/rL276759 because it broke 
modernize-loop-convert.

https://reviews.llvm.org/D22903 contains a fix for the modernize-loop-convert 
issue. Will re-submit this patch once https://reviews.llvm.org/D22903 has 
landed.


Repository:
  rL LLVM

https://reviews.llvm.org/D22566



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D23004: [ASTMatchers] Add matchers canReferToDecl() and hasUnderlyingDecl()

2016-08-01 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added reviewers: aaron.ballman, sbenza.
mboehme added a subscriber: cfe-commits.
Herald added a subscriber: klimek.

Required for D0

https://reviews.llvm.org/D23004

Files:
  docs/LibASTMatchersReference.html
  include/clang/ASTMatchers/ASTMatchers.h
  lib/ASTMatchers/Dynamic/Registry.cpp
  unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -241,6 +241,17 @@
 hasDeclaration(namedDecl(hasName("A";
 }
 
+TEST(HasUnderlyingDecl, Matches) {
+  EXPECT_TRUE(matches("class A{};"),
+  cxxRecordDecl(hasName("A"), hasUnderlyingDecl(hasName("A";
+  EXPECT_TRUE(matches("class A{}; typedef A B;"),
+  typedefDecl(hasName("B"), hasUnderlyingDecl(hasName("A";
+  EXPECT_TRUE(matches("class A{}; typedef A B; typedef B C;"),
+  typedefDecl(hasName("C"), hasUnderlyingDecl(hasName("A";
+  EXPECT_TRUE(notMatches("class A{}; class B{}; typedef B C;"),
+  typedefDecl(hasName("C"), hasUnderlyingDecl(hasName("A";
+}
+
 TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
   TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X")));
   EXPECT_TRUE(
@@ -2051,5 +2062,24 @@
   EXPECT_TRUE(notMatches(Code2, ForEachOverriddenInClass("A1")));
 }
 
+TEST(Matcher, CanReferToDecl) {
+  std::string Fragment = "void foo(int p1);"
+ "void foo(int *p2);"
+ "void bar(int p3);"
+ "template  void baz(T t) { foo(t); }";
+
+  EXPECT_TRUE(
+  matches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl(
+hasParameter(0, parmVarDecl(hasName("p1";
+  EXPECT_TRUE(
+  matches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl(
+hasParameter(0, parmVarDecl(hasName("p2";
+  EXPECT_TRUE(
+  notMatches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl(
+   hasParameter(0, parmVarDecl(hasName("p3";
+  EXPECT_TRUE(notMatches(Fragment, unresolvedLookupExpr(canReferToDecl(
+   functionDecl(hasName("bar"));
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -115,6 +115,7 @@
   REGISTER_MATCHER(breakStmt);
   REGISTER_MATCHER(builtinType);
   REGISTER_MATCHER(callExpr);
+  REGISTER_MATCHER(canReferToDecl);
   REGISTER_MATCHER(caseStmt);
   REGISTER_MATCHER(castExpr);
   REGISTER_MATCHER(characterLiteral);
@@ -265,6 +266,7 @@
   REGISTER_MATCHER(hasTypeLoc);
   REGISTER_MATCHER(hasUnaryOperand);
   REGISTER_MATCHER(hasUnarySelector);
+  REGISTER_MATCHER(hasUnderlyingDecl);
   REGISTER_MATCHER(hasValueType);
   REGISTER_MATCHER(ifStmt);
   REGISTER_MATCHER(ignoringImplicit);
Index: include/clang/ASTMatchers/ASTMatchers.h
===
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -2422,6 +2422,24 @@
   void(internal::HasDeclarationSupportedTypes)>(InnerMatcher);
 }
 
+/// \brief Matches a \c NamedDecl whose underlying declaration matches the given
+/// matcher.
+///
+/// Given
+/// \code
+///   class X {};
+///   typedef X Y;
+/// \endcode
+/// \c namedDecl(hasUnderlyingDecl(hasName("X")))
+///   matches both \c X and \c Y .
+AST_MATCHER_P(NamedDecl, hasUnderlyingDecl, internal::Matcher,
+  InnerMatcher) {
+  const NamedDecl *UnderlyingDecl = Node.getUnderlyingDecl();
+
+  return (UnderlyingDecl != nullptr &&
+  InnerMatcher.matches(*UnderlyingDecl, Finder, Builder));
+}
+
 /// \brief Matches on the implicit object argument of a member call expression.
 ///
 /// Example matches y.x()
@@ -2777,6 +2795,22 @@
   return false;
 }
 
+/// \brief Matches any \c Decl of an \c OverloadExpr that matches the given
+/// matcher.
+///
+/// Given
+/// \code
+///   void foo(int);
+///   template  void bar(T t) { foo(t); }
+/// \endcode
+/// unresolvedLookupExpr(canReferToDecl(functionDecl()))
+///   matches \c foo in \c foo(t);
+AST_MATCHER_P(OverloadExpr, canReferToDecl, internal::Matcher,
+  InnerMatcher) {
+  return matchesFirstInPointerRange(InnerMatcher, Node.decls_begin(),
+Node.decls_end(), Finder, Builder);
+}
+
 /// \brief Matches the Decl of a DeclStmt which has a single declaration.
 ///
 /// Given
Index: docs/LibASTMatchersReference.html
===
--- docs/LibASTMatchersReference.html
+++ docs/LibASTMatchersReference.html

Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-01 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 66284.
mboehme marked 3 inline comments as done.

https://reviews.llvm.org/D0

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-move-forwarding-reference.rst
  test/clang-tidy/misc-move-forwarding-reference.cpp

Index: test/clang-tidy/misc-move-forwarding-reference.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-move-forwarding-reference.cpp
@@ -0,0 +1,117 @@
+// RUN: %check_clang_tidy %s misc-move-forwarding-reference %t
+
+namespace std {
+template  struct remove_reference;
+
+template  struct remove_reference { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &> { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
+
+} // namespace std
+
+// Standard case.
+template  void f1(U &&SomeU) {
+  T SomeT(std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Ignore parentheses around the argument to std::move().
+template  void f2(U &&SomeU) {
+  T SomeT(std::move((SomeU)));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward((SomeU)));
+}
+
+// Handle the case correctly where std::move() is being used through a using
+// declaration.
+template  void f3(U &&SomeU) {
+  using std::move;
+  T SomeT(move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Handle the case correctly where a global specifier is prepended to
+// std::move().
+template  void f4(U &&SomeU) {
+  T SomeT(::std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(::std::forward(SomeU));
+}
+
+// Create a correct fix if there are spaces around the overload resolution
+// operator.
+template  void f5(U &&SomeU) {
+  {
+T SomeT(::std::move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(::std::forward(SomeU));
+  }
+  {
+T SomeT(std::move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(std::forward(SomeU));
+  }
+}
+
+// Ignore const rvalue reference parameters.
+template  void f6(const U &&SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the argument to std::move() is a lambda parameter (and
+// thus not actually a parameter of the function template).
+template  void f7() {
+  [](U &&SomeU) { T SomeT(std::move(SomeU)); };
+}
+
+// Ignore the case where the argument is a lvalue reference.
+template  void f8(U &SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the template parameter is a class template parameter
+// (i.e. no template argument deduction is taking place).
+template  class SomeClass {
+  void f(U &&SomeU) { T SomeT(std::move(SomeU)); }
+};
+
+// Ignore the case where the function parameter in the template isn't an rvalue
+// reference but the template argument is explicitly set to be an rvalue
+// reference.
+class A {};
+template  void foo(T);
+void f8() {
+  A a;
+  foo(std::move(a));
+}
+
+// A warning is output, but no fix is suggested, if a macro is used to rename
+// std::move.
+#define MOVE(x) std::move((x))
+template  void f9(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the argument is passed outside of the macro.
+#undef MOVE
+#define MOVE std::move
+template  void f10(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the macro does not include the "std" namespace.
+#undef MOVE
+#define MOVE move
+template  void f11(U &&SomeU) {
+  T SomeT(std::MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
Index: docs/clang-tidy/checks/misc-move-forwarding-reference.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-move-forwarding-reference.rst
@@ -0,0 +1,60 @@
+.. title:: clang-tidy - misc-move-forwarding-reference
+
+misc-move-forwarding-reference
+==
+
+Warns if ``std::move`` is called on a forwarding reference, for example:
+
+  .. code-block:: c++
+
+template 
+void foo(T&& t) {
+  bar(std::move(t));
+}
+
+`Forwarding references
+`_ should
+typically be passed to 

Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-01 Thread Martin Böhme via cfe-commits
mboehme marked 7 inline comments as done.


Comment at: clang-tidy/misc/MoveForwardingReferenceCheck.cpp:93
@@ +92,3 @@
+   hasArgument(0, ignoringParenImpCasts(declRefExpr(
+  to(ForwardingReferenceParmMatcher)
+  .bind("call-move"),

sbenza wrote:
> aaron.ballman wrote:
> > I wonder if there's a reason for this behavior, or if it's simple a matter 
> > of not being needed previously and so it was never implemented. @sbenza or 
> > @klimek may know. I think we should be fixing the RecursiveASTVisitor, 
> > unless there is a valid reason not to (which there may be), though that 
> > would be a separate patch (and can happen after we land this one).
> Even if the nodes are not visited through the recursive visitor, you can 
> always have a matcher for it.
> Eg: `hasAnyConstructorInitializer` / `cxxCtorInitializer`.
> 
> But what node are you trying to visit here?
> The only node I see is `NamingClass`, which is not really a child node.
> Like the referred `Decl` in a `DeclRefExpr` is not a child either. You can't 
> use `has()` there, you have to use `to()`.
I've now reworked this to use new matchers (in review in D23004). Thanks for 
the comments, which finally got me on the right track!

> But what node are you trying to visit here?

I'm trying to visit the decls() in an OverloadExpr (this happened in 
isStdMove(), which is now deleted).

As you note, these intentionally aren't children of the OverloadExpr (so it 
doesn't make sense for the RecursiveASTMatcher to visit them), but it still 
makes sense to have a matchers for them -- which I've now added.


Comment at: clang-tidy/misc/MoveForwardingReferenceCheck.cpp:45-55
@@ +44,13 @@
+  // We still conservatively put a "std::" in front of the forward because
+  // we don't know whether the code also had a "using std::forward;".
+  Diag << FixItHint::CreateReplacement(CallRange, "std::" + ForwardName);
+} else if (const NamespaceDecl *Namespace = NNS->getAsNamespace()) {
+  if (Namespace->getName() == "std") {
+if (!NNS->getPrefix()) {
+  // Called as "std::move".
+  Diag << FixItHint::CreateReplacement(CallRange,
+   "std::" + ForwardName);
+} else if (NNS->getPrefix()->getKind() == NestedNameSpecifier::Global) 
{
+  // Called as "::std::move".
+  Diag << FixItHint::CreateReplacement(CallRange,
+   "::std::" + ForwardName);

I've changed the code to look at the NestedNameSpecifiers instead of looking at 
the original source text.

> But, at the same time, the check should be bomb proof for ugly cases like 
> [snip]

Apologies, I misunderstood -- I thought you were saying it should be bomb proof 
in the sense that it shouldn't suggest any replacement (and that's why I marked 
your comment done). Having read aaron.ballman's comment, I now realize what you 
meant is that the check should be bomb proof in the sense that it should create 
a correct fix even for such "ugly" cases.


https://reviews.llvm.org/D0



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D23004: [ASTMatchers] Add matchers canReferToDecl() and hasUnderlyingDecl()

2016-08-01 Thread Martin Böhme via cfe-commits
mboehme added a comment.

Retracting from review for the moment. Tests fail to compile (embarrasingly 
enough, I ran the wrong test suite -- apologies).


https://reviews.llvm.org/D23004



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D23004: [ASTMatchers] Add matchers canReferToDecl() and hasUnderlyingDecl()

2016-08-01 Thread Martin Böhme via cfe-commits
mboehme added reviewers: sbenza, aaron.ballman.
mboehme updated this revision to Diff 66291.
mboehme added a comment.

Updated test and documentation for hasUnderlyingDecl() to use using 
declarations instead of typedefs. (I made the mistaken assumption that 
getUnderlyingDecl() would also work on a typdef and didn't catch the mistake 
because I ran the wrong tests.)


https://reviews.llvm.org/D23004

Files:
  docs/LibASTMatchersReference.html
  include/clang/ASTMatchers/ASTMatchers.h
  lib/ASTMatchers/Dynamic/Registry.cpp
  unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -241,6 +241,21 @@
 hasDeclaration(namedDecl(hasName("A";
 }
 
+TEST(HasUnderlyingDecl, Matches) {
+  EXPECT_TRUE(matches("namespace N { template  void f(T t); }"
+  "template  void g() { using N::f; f(T()); }",
+  unresolvedLookupExpr(canReferToDecl(
+  namedDecl(hasUnderlyingDecl(hasName("::N::f")));
+  EXPECT_TRUE(matches(
+  "namespace N { template  void f(T t); }"
+  "template  void g() { N::f(T()); }",
+  unresolvedLookupExpr(canReferToDecl(namedDecl(hasName("::N::f"));
+  EXPECT_TRUE(notMatches(
+  "namespace N { template  void f(T t); }"
+  "template  void g() { using N::f; f(T()); }",
+  unresolvedLookupExpr(canReferToDecl(namedDecl(hasName("::N::f"));
+}
+
 TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
   TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X")));
   EXPECT_TRUE(
@@ -2051,5 +2066,24 @@
   EXPECT_TRUE(notMatches(Code2, ForEachOverriddenInClass("A1")));
 }
 
+TEST(Matcher, CanReferToDecl) {
+  std::string Fragment = "void foo(int p1);"
+ "void foo(int *p2);"
+ "void bar(int p3);"
+ "template  void baz(T t) { foo(t); }";
+
+  EXPECT_TRUE(
+  matches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl(
+hasParameter(0, parmVarDecl(hasName("p1";
+  EXPECT_TRUE(
+  matches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl(
+hasParameter(0, parmVarDecl(hasName("p2";
+  EXPECT_TRUE(
+  notMatches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl(
+   hasParameter(0, parmVarDecl(hasName("p3";
+  EXPECT_TRUE(notMatches(Fragment, unresolvedLookupExpr(canReferToDecl(
+   functionDecl(hasName("bar"));
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -115,6 +115,7 @@
   REGISTER_MATCHER(breakStmt);
   REGISTER_MATCHER(builtinType);
   REGISTER_MATCHER(callExpr);
+  REGISTER_MATCHER(canReferToDecl);
   REGISTER_MATCHER(caseStmt);
   REGISTER_MATCHER(castExpr);
   REGISTER_MATCHER(characterLiteral);
@@ -265,6 +266,7 @@
   REGISTER_MATCHER(hasTypeLoc);
   REGISTER_MATCHER(hasUnaryOperand);
   REGISTER_MATCHER(hasUnarySelector);
+  REGISTER_MATCHER(hasUnderlyingDecl);
   REGISTER_MATCHER(hasValueType);
   REGISTER_MATCHER(ifStmt);
   REGISTER_MATCHER(ignoringImplicit);
Index: include/clang/ASTMatchers/ASTMatchers.h
===
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -2422,6 +2422,25 @@
   void(internal::HasDeclarationSupportedTypes)>(InnerMatcher);
 }
 
+/// \brief Matches a \c NamedDecl whose underlying declaration matches the given
+/// matcher.
+///
+/// Given
+/// \code
+///   namespace N { template void f(T t); }
+///   template  void g() { using N::f; f(T()); }
+/// \endcode
+/// \c unresolvedLookupExpr(canReferToDecl(
+/// namedDecl(hasUnderlyingDecl(hasName("::N::f")
+///   matches the use of \c f in \c g() .
+AST_MATCHER_P(NamedDecl, hasUnderlyingDecl, internal::Matcher,
+  InnerMatcher) {
+  const NamedDecl *UnderlyingDecl = Node.getUnderlyingDecl();
+
+  return (UnderlyingDecl != nullptr &&
+  InnerMatcher.matches(*UnderlyingDecl, Finder, Builder));
+}
+
 /// \brief Matches on the implicit object argument of a member call expression.
 ///
 /// Example matches y.x()
@@ -2777,6 +2796,22 @@
   return false;
 }
 
+/// \brief Matches any \c Decl of an \c OverloadExpr that matches the given
+/// matcher.
+///
+/// Given
+/// \code
+///   void foo(int);
+///   template  void bar(T t) { foo(t); }
+/// \endcode
+/// unresolvedLookupExpr(canReferToDecl(functionDecl()))
+///   matches \c foo in \c foo(t);
+AST_MATCHER_P(OverloadExpr, canReferToDecl, internal::Matche

Re: [PATCH] D22903: [clang-tidy] Prepare modernize-loop-convert for upcoming changes in D22566

2016-08-01 Thread Martin Böhme via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL277339: [clang-tidy] Prepare modernize-loop-convert for 
upcoming changes in D22566 (authored by mboehme).

Changed prior to commit:
  https://reviews.llvm.org/D22903?vs=65877&id=66303#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D22903

Files:
  clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.cpp

Index: clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.cpp
===
--- clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.cpp
+++ clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.cpp
@@ -805,6 +805,18 @@
 }
 
 bool ForLoopIndexUseVisitor::TraverseStmt(Stmt *S) {
+  // If this is an initialization expression for a lambda capture, prune the
+  // traversal so that we don't end up diagnosing the contained DeclRefExpr as
+  // inconsistent usage. No need to record the usage here -- this is done in
+  // TraverseLambdaCapture().
+  if (const auto *LE = dyn_cast_or_null(NextStmtParent)) {
+// Any child of a LambdaExpr that isn't the body is an initialization
+// expression.
+if (S != LE->getBody()) {
+  return true;
+}
+  }
+
   // All this pointer swapping is a mechanism for tracking immediate parentage
   // of Stmts.
   const Stmt *OldNextParent = NextStmtParent;


Index: clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.cpp
===
--- clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.cpp
+++ clang-tools-extra/trunk/clang-tidy/modernize/LoopConvertUtils.cpp
@@ -805,6 +805,18 @@
 }
 
 bool ForLoopIndexUseVisitor::TraverseStmt(Stmt *S) {
+  // If this is an initialization expression for a lambda capture, prune the
+  // traversal so that we don't end up diagnosing the contained DeclRefExpr as
+  // inconsistent usage. No need to record the usage here -- this is done in
+  // TraverseLambdaCapture().
+  if (const auto *LE = dyn_cast_or_null(NextStmtParent)) {
+// Any child of a LambdaExpr that isn't the body is an initialization
+// expression.
+if (S != LE->getBody()) {
+  return true;
+}
+  }
+
   // All this pointer swapping is a mechanism for tracking immediate parentage
   // of Stmts.
   const Stmt *OldNextParent = NextStmtParent;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D23004: [ASTMatchers] Add matchers canReferToDecl() and hasUnderlyingDecl()

2016-08-04 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 66808.

https://reviews.llvm.org/D23004

Files:
  docs/LibASTMatchersReference.html
  include/clang/ASTMatchers/ASTMatchers.h
  lib/ASTMatchers/Dynamic/Registry.cpp
  unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -241,6 +241,21 @@
 hasDeclaration(namedDecl(hasName("A";
 }
 
+TEST(HasUnderlyingDecl, Matches) {
+  EXPECT_TRUE(matches("namespace N { template  void f(T t); }"
+  "template  void g() { using N::f; f(T()); }",
+  unresolvedLookupExpr(canReferToDecl(
+  namedDecl(hasUnderlyingDecl(hasName("::N::f")));
+  EXPECT_TRUE(matches(
+  "namespace N { template  void f(T t); }"
+  "template  void g() { N::f(T()); }",
+  unresolvedLookupExpr(canReferToDecl(namedDecl(hasName("::N::f"));
+  EXPECT_TRUE(notMatches(
+  "namespace N { template  void f(T t); }"
+  "template  void g() { using N::f; f(T()); }",
+  unresolvedLookupExpr(canReferToDecl(namedDecl(hasName("::N::f"));
+}
+
 TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
   TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X")));
   EXPECT_TRUE(
@@ -2072,5 +2087,24 @@
   EXPECT_TRUE(notMatches(Code2, ForEachOverriddenInClass("A1")));
 }
 
+TEST(Matcher, CanReferToDecl) {
+  std::string Fragment = "void foo(int p1);"
+ "void foo(int *p2);"
+ "void bar(int p3);"
+ "template  void baz(T t) { foo(t); }";
+
+  EXPECT_TRUE(
+  matches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl(
+hasParameter(0, parmVarDecl(hasName("p1";
+  EXPECT_TRUE(
+  matches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl(
+hasParameter(0, parmVarDecl(hasName("p2";
+  EXPECT_TRUE(
+  notMatches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl(
+   hasParameter(0, parmVarDecl(hasName("p3";
+  EXPECT_TRUE(notMatches(Fragment, unresolvedLookupExpr(canReferToDecl(
+   functionDecl(hasName("bar"));
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -115,6 +115,7 @@
   REGISTER_MATCHER(breakStmt);
   REGISTER_MATCHER(builtinType);
   REGISTER_MATCHER(callExpr);
+  REGISTER_MATCHER(canReferToDecl);
   REGISTER_MATCHER(caseStmt);
   REGISTER_MATCHER(castExpr);
   REGISTER_MATCHER(characterLiteral);
@@ -265,6 +266,7 @@
   REGISTER_MATCHER(hasTypeLoc);
   REGISTER_MATCHER(hasUnaryOperand);
   REGISTER_MATCHER(hasUnarySelector);
+  REGISTER_MATCHER(hasUnderlyingDecl);
   REGISTER_MATCHER(hasValueType);
   REGISTER_MATCHER(ifStmt);
   REGISTER_MATCHER(ignoringImplicit);
Index: include/clang/ASTMatchers/ASTMatchers.h
===
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -2468,6 +2468,25 @@
   void(internal::HasDeclarationSupportedTypes)>(InnerMatcher);
 }
 
+/// \brief Matches a \c NamedDecl whose underlying declaration matches the given
+/// matcher.
+///
+/// Given
+/// \code
+///   namespace N { template void f(T t); }
+///   template  void g() { using N::f; f(T()); }
+/// \endcode
+/// \c unresolvedLookupExpr(canReferToDecl(
+/// namedDecl(hasUnderlyingDecl(hasName("::N::f")
+///   matches the use of \c f in \c g() .
+AST_MATCHER_P(NamedDecl, hasUnderlyingDecl, internal::Matcher,
+  InnerMatcher) {
+  const NamedDecl *UnderlyingDecl = Node.getUnderlyingDecl();
+
+  return (UnderlyingDecl != nullptr &&
+  InnerMatcher.matches(*UnderlyingDecl, Finder, Builder));
+}
+
 /// \brief Matches on the implicit object argument of a member call expression.
 ///
 /// Example matches y.x()
@@ -2823,6 +2842,26 @@
   return false;
 }
 
+/// \brief Matches an \c OverloadExpr if any of the declarations in the set of
+/// overloads matches the given matcher.
+///
+/// Given
+/// \code
+///   template  void foo(T);
+///   template  void bar(T);
+///   template  void baz(T t) {
+/// foo(t);
+/// bar(t);
+///   }
+/// \endcode
+/// unresolvedLookupExpr(canReferToDecl(functionTemplateDecl(hasName("foo"
+///   matches \c foo in \c foo(t); but not \c bar in \c bar(t);
+AST_MATCHER_P(OverloadExpr, canReferToDecl, internal::Matcher,
+  InnerMatcher) {
+  return matchesFirstInPointerRange(InnerMatcher, Node.decls_begin(),
+Node.decls_end(), Finder, Build

Re: [PATCH] D23004: [ASTMatchers] Add matchers canReferToDecl() and hasUnderlyingDecl()

2016-08-04 Thread Martin Böhme via cfe-commits
mboehme added a comment.

I've rebased the patch to a newer head revision, which seems to confuse 
Phabricator when diffing against earlier versions of the patch. Apologies. I 
assume this means I should avoid doing this (rebasing to a newer revision)?


https://reviews.llvm.org/D23004



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D23004: [ASTMatchers] Add matchers canReferToDecl() and hasUnderlyingDecl()

2016-08-04 Thread Martin Böhme via cfe-commits
mboehme marked an inline comment as done.


Comment at: include/clang/ASTMatchers/ASTMatchers.h:2486
@@ +2485,3 @@
+
+  return (UnderlyingDecl != nullptr &&
+  InnerMatcher.matches(*UnderlyingDecl, Finder, Builder));

I was trying to match the style of the next matcher below -- or do you think I 
should establish a precedent / preference for emitting the superfluous 
parentheses?


Comment at: include/clang/ASTMatchers/ASTMatchers.h:2855
@@ +2854,3 @@
+/// bar(t);
+///   }
+/// \endcode

> The documentation doesn't describe what the matcher does (can you please 
> clarify the docs?).

I've rephrased the description of the matcher -- is it clearer now?

> The implementation suggests that this is looking to see if the given decl 
> exists in the overload expression set, which makes me wonder why this isn't 
> implemented on the hasDeclaration() traversal matcher rather than adding a 
> new matcher name?

As klimek notes, the difference is that hasDeclaration() is currently used only 
for nodes that have exactly one associated declaration.

My proposal would be to stay with canReferToDecl -- thoughts?


https://reviews.llvm.org/D23004



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D23004: [ASTMatchers] Add matchers canReferToDecl() and hasUnderlyingDecl()

2016-08-04 Thread Martin Böhme via cfe-commits
mboehme marked 3 inline comments as done.
mboehme added a comment.

https://reviews.llvm.org/D23004



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D23004: [ASTMatchers] Add matchers canReferToDecl() and hasUnderlyingDecl()

2016-08-04 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 66815.
mboehme added a comment.

Removed superfluous parentheses


https://reviews.llvm.org/D23004

Files:
  docs/LibASTMatchersReference.html
  include/clang/ASTMatchers/ASTMatchers.h
  lib/ASTMatchers/Dynamic/Registry.cpp
  unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -241,6 +241,21 @@
 hasDeclaration(namedDecl(hasName("A";
 }
 
+TEST(HasUnderlyingDecl, Matches) {
+  EXPECT_TRUE(matches("namespace N { template  void f(T t); }"
+  "template  void g() { using N::f; f(T()); }",
+  unresolvedLookupExpr(canReferToDecl(
+  namedDecl(hasUnderlyingDecl(hasName("::N::f")));
+  EXPECT_TRUE(matches(
+  "namespace N { template  void f(T t); }"
+  "template  void g() { N::f(T()); }",
+  unresolvedLookupExpr(canReferToDecl(namedDecl(hasName("::N::f"));
+  EXPECT_TRUE(notMatches(
+  "namespace N { template  void f(T t); }"
+  "template  void g() { using N::f; f(T()); }",
+  unresolvedLookupExpr(canReferToDecl(namedDecl(hasName("::N::f"));
+}
+
 TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
   TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X")));
   EXPECT_TRUE(
@@ -2072,5 +2087,24 @@
   EXPECT_TRUE(notMatches(Code2, ForEachOverriddenInClass("A1")));
 }
 
+TEST(Matcher, CanReferToDecl) {
+  std::string Fragment = "void foo(int p1);"
+ "void foo(int *p2);"
+ "void bar(int p3);"
+ "template  void baz(T t) { foo(t); }";
+
+  EXPECT_TRUE(
+  matches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl(
+hasParameter(0, parmVarDecl(hasName("p1";
+  EXPECT_TRUE(
+  matches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl(
+hasParameter(0, parmVarDecl(hasName("p2";
+  EXPECT_TRUE(
+  notMatches(Fragment, unresolvedLookupExpr(canReferToDecl(functionDecl(
+   hasParameter(0, parmVarDecl(hasName("p3";
+  EXPECT_TRUE(notMatches(Fragment, unresolvedLookupExpr(canReferToDecl(
+   functionDecl(hasName("bar"));
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -115,6 +115,7 @@
   REGISTER_MATCHER(breakStmt);
   REGISTER_MATCHER(builtinType);
   REGISTER_MATCHER(callExpr);
+  REGISTER_MATCHER(canReferToDecl);
   REGISTER_MATCHER(caseStmt);
   REGISTER_MATCHER(castExpr);
   REGISTER_MATCHER(characterLiteral);
@@ -265,6 +266,7 @@
   REGISTER_MATCHER(hasTypeLoc);
   REGISTER_MATCHER(hasUnaryOperand);
   REGISTER_MATCHER(hasUnarySelector);
+  REGISTER_MATCHER(hasUnderlyingDecl);
   REGISTER_MATCHER(hasValueType);
   REGISTER_MATCHER(ifStmt);
   REGISTER_MATCHER(ignoringImplicit);
Index: include/clang/ASTMatchers/ASTMatchers.h
===
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -2468,6 +2468,25 @@
   void(internal::HasDeclarationSupportedTypes)>(InnerMatcher);
 }
 
+/// \brief Matches a \c NamedDecl whose underlying declaration matches the given
+/// matcher.
+///
+/// Given
+/// \code
+///   namespace N { template void f(T t); }
+///   template  void g() { using N::f; f(T()); }
+/// \endcode
+/// \c unresolvedLookupExpr(canReferToDecl(
+/// namedDecl(hasUnderlyingDecl(hasName("::N::f")
+///   matches the use of \c f in \c g() .
+AST_MATCHER_P(NamedDecl, hasUnderlyingDecl, internal::Matcher,
+  InnerMatcher) {
+  const NamedDecl *UnderlyingDecl = Node.getUnderlyingDecl();
+
+  return UnderlyingDecl != nullptr &&
+ InnerMatcher.matches(*UnderlyingDecl, Finder, Builder);
+}
+
 /// \brief Matches on the implicit object argument of a member call expression.
 ///
 /// Example matches y.x()
@@ -2823,6 +2842,26 @@
   return false;
 }
 
+/// \brief Matches an \c OverloadExpr if any of the declarations in the set of
+/// overloads matches the given matcher.
+///
+/// Given
+/// \code
+///   template  void foo(T);
+///   template  void bar(T);
+///   template  void baz(T t) {
+/// foo(t);
+/// bar(t);
+///   }
+/// \endcode
+/// unresolvedLookupExpr(canReferToDecl(functionTemplateDecl(hasName("foo"
+///   matches \c foo in \c foo(t); but not \c bar in \c bar(t);
+AST_MATCHER_P(OverloadExpr, canReferToDecl, internal::Matcher,
+  InnerMatcher) {
+  return matchesFirstInPointerRange(InnerMatcher, Node.decls_begin(),
+   

Re: [PATCH] D23004: [ASTMatchers] Add matchers canReferToDecl() and hasUnderlyingDecl()

2016-08-05 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 66912.
mboehme added a comment.

- Rename canReferToDecl to hasAnyDeclaration


https://reviews.llvm.org/D23004

Files:
  docs/LibASTMatchersReference.html
  include/clang/ASTMatchers/ASTMatchers.h
  lib/ASTMatchers/Dynamic/Registry.cpp
  unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -241,6 +241,21 @@
 hasDeclaration(namedDecl(hasName("A";
 }
 
+TEST(HasUnderlyingDecl, Matches) {
+  EXPECT_TRUE(matches("namespace N { template  void f(T t); }"
+  "template  void g() { using N::f; f(T()); }",
+  unresolvedLookupExpr(hasAnyDeclaration(
+  namedDecl(hasUnderlyingDecl(hasName("::N::f")));
+  EXPECT_TRUE(matches(
+  "namespace N { template  void f(T t); }"
+  "template  void g() { N::f(T()); }",
+  unresolvedLookupExpr(hasAnyDeclaration(namedDecl(hasName("::N::f"));
+  EXPECT_TRUE(notMatches(
+  "namespace N { template  void f(T t); }"
+  "template  void g() { using N::f; f(T()); }",
+  unresolvedLookupExpr(hasAnyDeclaration(namedDecl(hasName("::N::f"));
+}
+
 TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
   TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X")));
   EXPECT_TRUE(
@@ -2072,5 +2087,24 @@
   EXPECT_TRUE(notMatches(Code2, ForEachOverriddenInClass("A1")));
 }
 
+TEST(Matcher, HasAnyDeclaration) {
+  std::string Fragment = "void foo(int p1);"
+ "void foo(int *p2);"
+ "void bar(int p3);"
+ "template  void baz(T t) { foo(t); }";
+
+  EXPECT_TRUE(
+  matches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl(
+hasParameter(0, parmVarDecl(hasName("p1";
+  EXPECT_TRUE(
+  matches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl(
+hasParameter(0, parmVarDecl(hasName("p2";
+  EXPECT_TRUE(
+  notMatches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl(
+   hasParameter(0, parmVarDecl(hasName("p3";
+  EXPECT_TRUE(notMatches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(
+   functionDecl(hasName("bar"));
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -198,6 +198,7 @@
   REGISTER_MATCHER(hasAncestor);
   REGISTER_MATCHER(hasAnyArgument);
   REGISTER_MATCHER(hasAnyConstructorInitializer);
+  REGISTER_MATCHER(hasAnyDeclaration);
   REGISTER_MATCHER(hasAnyName);
   REGISTER_MATCHER(hasAnyParameter);
   REGISTER_MATCHER(hasAnySubstatement);
@@ -265,6 +266,7 @@
   REGISTER_MATCHER(hasTypeLoc);
   REGISTER_MATCHER(hasUnaryOperand);
   REGISTER_MATCHER(hasUnarySelector);
+  REGISTER_MATCHER(hasUnderlyingDecl);
   REGISTER_MATCHER(hasValueType);
   REGISTER_MATCHER(ifStmt);
   REGISTER_MATCHER(ignoringImplicit);
Index: include/clang/ASTMatchers/ASTMatchers.h
===
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -2468,6 +2468,25 @@
   void(internal::HasDeclarationSupportedTypes)>(InnerMatcher);
 }
 
+/// \brief Matches a \c NamedDecl whose underlying declaration matches the given
+/// matcher.
+///
+/// Given
+/// \code
+///   namespace N { template void f(T t); }
+///   template  void g() { using N::f; f(T()); }
+/// \endcode
+/// \c unresolvedLookupExpr(hasAnyDeclaration(
+/// namedDecl(hasUnderlyingDecl(hasName("::N::f")
+///   matches the use of \c f in \c g() .
+AST_MATCHER_P(NamedDecl, hasUnderlyingDecl, internal::Matcher,
+  InnerMatcher) {
+  const NamedDecl *UnderlyingDecl = Node.getUnderlyingDecl();
+
+  return UnderlyingDecl != nullptr &&
+ InnerMatcher.matches(*UnderlyingDecl, Finder, Builder);
+}
+
 /// \brief Matches on the implicit object argument of a member call expression.
 ///
 /// Example matches y.x()
@@ -2823,6 +2842,27 @@
   return false;
 }
 
+/// \brief Matches an \c OverloadExpr if any of the declarations in the set of
+/// overloads matches the given matcher.
+///
+/// Given
+/// \code
+///   template  void foo(T);
+///   template  void bar(T);
+///   template  void baz(T t) {
+/// foo(t);
+/// bar(t);
+///   }
+/// \endcode
+/// unresolvedLookupExpr(hasAnyDeclaration(
+/// functionTemplateDecl(hasName("foo"
+///   matches \c foo in \c foo(t); but not \c bar in \c bar(t);
+AST_MATCHER_P(OverloadExpr, hasAnyDeclaration, internal::Matcher,
+  Inne

Re: [PATCH] D23004: [ASTMatchers] Add matchers canReferToDecl() and hasUnderlyingDecl()

2016-08-05 Thread Martin Böhme via cfe-commits
mboehme marked 5 inline comments as done.
mboehme added a comment.

https://reviews.llvm.org/D23004



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-05 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 66914.
mboehme marked 2 inline comments as done.
mboehme added a comment.

Renamed canReferToDecl to hasAnyDeclaration.

  

This is for consistency with the corresponding change in 
https://reviews.llvm.org/D23004.


https://reviews.llvm.org/D0

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-move-forwarding-reference.rst
  test/clang-tidy/misc-move-forwarding-reference.cpp

Index: test/clang-tidy/misc-move-forwarding-reference.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-move-forwarding-reference.cpp
@@ -0,0 +1,117 @@
+// RUN: %check_clang_tidy %s misc-move-forwarding-reference %t
+
+namespace std {
+template  struct remove_reference;
+
+template  struct remove_reference { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &> { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
+
+} // namespace std
+
+// Standard case.
+template  void f1(U &&SomeU) {
+  T SomeT(std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Ignore parentheses around the argument to std::move().
+template  void f2(U &&SomeU) {
+  T SomeT(std::move((SomeU)));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward((SomeU)));
+}
+
+// Handle the case correctly where std::move() is being used through a using
+// declaration.
+template  void f3(U &&SomeU) {
+  using std::move;
+  T SomeT(move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Handle the case correctly where a global specifier is prepended to
+// std::move().
+template  void f4(U &&SomeU) {
+  T SomeT(::std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(::std::forward(SomeU));
+}
+
+// Create a correct fix if there are spaces around the overload resolution
+// operator.
+template  void f5(U &&SomeU) {
+  {
+T SomeT(::std::move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(::std::forward(SomeU));
+  }
+  {
+T SomeT(std::move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(std::forward(SomeU));
+  }
+}
+
+// Ignore const rvalue reference parameters.
+template  void f6(const U &&SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the argument to std::move() is a lambda parameter (and
+// thus not actually a parameter of the function template).
+template  void f7() {
+  [](U &&SomeU) { T SomeT(std::move(SomeU)); };
+}
+
+// Ignore the case where the argument is a lvalue reference.
+template  void f8(U &SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the template parameter is a class template parameter
+// (i.e. no template argument deduction is taking place).
+template  class SomeClass {
+  void f(U &&SomeU) { T SomeT(std::move(SomeU)); }
+};
+
+// Ignore the case where the function parameter in the template isn't an rvalue
+// reference but the template argument is explicitly set to be an rvalue
+// reference.
+class A {};
+template  void foo(T);
+void f8() {
+  A a;
+  foo(std::move(a));
+}
+
+// A warning is output, but no fix is suggested, if a macro is used to rename
+// std::move.
+#define MOVE(x) std::move((x))
+template  void f9(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the argument is passed outside of the macro.
+#undef MOVE
+#define MOVE std::move
+template  void f10(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the macro does not include the "std" namespace.
+#undef MOVE
+#define MOVE move
+template  void f11(U &&SomeU) {
+  T SomeT(std::MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
Index: docs/clang-tidy/checks/misc-move-forwarding-reference.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-move-forwarding-reference.rst
@@ -0,0 +1,60 @@
+.. title:: clang-tidy - misc-move-forwarding-reference
+
+misc-move-forwarding-reference
+==
+
+Warns if ``std::move`` is called on a forwarding reference, for example:
+
+  .. code-block:: c++
+
+template 
+void fo

Re: [PATCH] D23004: [ASTMatchers] Add matchers canReferToDecl() and hasUnderlyingDecl()

2016-08-09 Thread Martin Böhme via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL278123: [ASTMatchers] Add matchers canReferToDecl() and 
hasUnderlyingDecl() (authored by mboehme).

Changed prior to commit:
  https://reviews.llvm.org/D23004?vs=66912&id=67353#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D23004

Files:
  cfe/trunk/docs/LibASTMatchersReference.html
  cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
  cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
  cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -198,6 +198,7 @@
   REGISTER_MATCHER(hasAncestor);
   REGISTER_MATCHER(hasAnyArgument);
   REGISTER_MATCHER(hasAnyConstructorInitializer);
+  REGISTER_MATCHER(hasAnyDeclaration);
   REGISTER_MATCHER(hasAnyName);
   REGISTER_MATCHER(hasAnyParameter);
   REGISTER_MATCHER(hasAnySubstatement);
@@ -265,6 +266,7 @@
   REGISTER_MATCHER(hasTypeLoc);
   REGISTER_MATCHER(hasUnaryOperand);
   REGISTER_MATCHER(hasUnarySelector);
+  REGISTER_MATCHER(hasUnderlyingDecl);
   REGISTER_MATCHER(hasValueType);
   REGISTER_MATCHER(ifStmt);
   REGISTER_MATCHER(ignoringImplicit);
Index: cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -241,6 +241,21 @@
 hasDeclaration(namedDecl(hasName("A";
 }
 
+TEST(HasUnderlyingDecl, Matches) {
+  EXPECT_TRUE(matches("namespace N { template  void f(T t); }"
+  "template  void g() { using N::f; f(T()); }",
+  unresolvedLookupExpr(hasAnyDeclaration(
+  namedDecl(hasUnderlyingDecl(hasName("::N::f")));
+  EXPECT_TRUE(matches(
+  "namespace N { template  void f(T t); }"
+  "template  void g() { N::f(T()); }",
+  unresolvedLookupExpr(hasAnyDeclaration(namedDecl(hasName("::N::f"));
+  EXPECT_TRUE(notMatches(
+  "namespace N { template  void f(T t); }"
+  "template  void g() { using N::f; f(T()); }",
+  unresolvedLookupExpr(hasAnyDeclaration(namedDecl(hasName("::N::f"));
+}
+
 TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
   TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X")));
   EXPECT_TRUE(
@@ -2072,5 +2087,24 @@
   EXPECT_TRUE(notMatches(Code2, ForEachOverriddenInClass("A1")));
 }
 
+TEST(Matcher, HasAnyDeclaration) {
+  std::string Fragment = "void foo(int p1);"
+ "void foo(int *p2);"
+ "void bar(int p3);"
+ "template  void baz(T t) { foo(t); }";
+
+  EXPECT_TRUE(
+  matches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl(
+hasParameter(0, parmVarDecl(hasName("p1";
+  EXPECT_TRUE(
+  matches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl(
+hasParameter(0, parmVarDecl(hasName("p2";
+  EXPECT_TRUE(
+  notMatches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl(
+   hasParameter(0, parmVarDecl(hasName("p3";
+  EXPECT_TRUE(notMatches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(
+   functionDecl(hasName("bar"));
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: cfe/trunk/docs/LibASTMatchersReference.html
===
--- cfe/trunk/docs/LibASTMatchersReference.html
+++ cfe/trunk/docs/LibASTMatchersReference.html
@@ -4970,6 +4970,19 @@
 
 
 
+MatcherNamedDecl>hasUnderlyingDeclMatcherNamedDecl> InnerMatcher
+Matches a NamedDecl whose underlying declaration matches the given
+matcher.
+
+Given
+  namespace N { template void f(T t); }
+  template  void g() { using N::f; f(T()); }
+unresolvedLookupExpr(hasAnyDeclaration(
+namedDecl(hasUnderlyingDecl(hasName("::N::f")
+  matches the use of f in g() .
+
+
+
 MatcherNestedNameSpecifierLoc>hasPrefixMatcherNestedNameSpecifierLoc> InnerMatcher
 Matches on the prefix of a NestedNameSpecifierLoc.
 
@@ -5057,6 +5070,23 @@
 
 
 
+MatcherOverloadExpr>hasAnyDeclarationMatcherDecl> InnerMatcher
+Matches an OverloadExpr if any of the declarations in the set of
+overloads matches the given matcher.
+
+

Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-10 Thread Martin Böhme via cfe-commits
mboehme added a comment.

Now that https://reviews.llvm.org/D23004 is submitted, can you take another 
look?


https://reviews.llvm.org/D0



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D23353: [clang-tidy] Add check 'misc-use-after-move'

2016-08-10 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: alexfh.
mboehme added a subscriber: cfe-commits.

The check warns if an object is used after it has been moved, without an
intervening reinitialization.

See user-facing documentation for details.

https://reviews.llvm.org/D23353

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/UseAfterMoveCheck.cpp
  clang-tidy/misc/UseAfterMoveCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-use-after-move.rst
  test/clang-tidy/misc-use-after-move.cpp

Index: test/clang-tidy/misc-use-after-move.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-use-after-move.cpp
@@ -0,0 +1,1013 @@
+// RUN: %check_clang_tidy %s misc-use-after-move %t
+
+typedef decltype(nullptr) nullptr_t;
+
+namespace std {
+typedef unsigned size_t;
+
+template 
+struct unique_ptr {
+  unique_ptr();
+  T *get() const;
+};
+
+template 
+struct shared_ptr {
+  shared_ptr();
+  T *get() const;
+};
+
+#define DECLARE_STANDARD_CONTAINER(name) \
+  template   \
+  struct name {  \
+name();  \
+void clear();\
+bool empty();\
+  }
+
+#define DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(name) \
+  template   \
+  struct name {  \
+name();  \
+void clear();\
+bool empty();\
+void assign(size_t, const T &);  \
+  }
+
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(basic_string);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(vector);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(deque);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(forward_list);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(list);
+DECLARE_STANDARD_CONTAINER(set);
+DECLARE_STANDARD_CONTAINER(map);
+DECLARE_STANDARD_CONTAINER(multiset);
+DECLARE_STANDARD_CONTAINER(multimap);
+DECLARE_STANDARD_CONTAINER(unordered_set);
+DECLARE_STANDARD_CONTAINER(unordered_map);
+DECLARE_STANDARD_CONTAINER(unordered_multiset);
+DECLARE_STANDARD_CONTAINER(unordered_multimap);
+
+typedef basic_string string;
+
+template 
+struct remove_reference;
+
+template 
+struct remove_reference {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &> {
+  typedef _Tp type;
+};
+
+template 
+struct remove_reference<_Tp &&> {
+  typedef _Tp type;
+};
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) noexcept {
+  return static_cast::type &&>(__t);
+}
+
+} // namespace std
+
+class A {
+public:
+  A();
+  A(const A &);
+  A(A &&);
+
+  A &operator=(const A &);
+  A &operator=(A &&);
+
+  void foo() const;
+  int getInt() const;
+
+  operator bool() const;
+
+  int i;
+};
+
+
+// General tests.
+
+// Simple case.
+void simple() {
+  A a;
+  a.foo();
+  A other_a = std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:15: note: move occurred here
+}
+
+// A warning should only be emitted for one use-after-move.
+void onlyFlagOneUseAfterMove() {
+  A a;
+  a.foo();
+  A other_a = std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:15: note: move occurred here
+  a.foo();
+}
+
+void moveAfterMove() {
+  // Move-after-move also counts as a use.
+  {
+A a;
+std::move(a);
+std::move(a);
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: 'a' used after it was moved
+// CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+  }
+  // This is also true if the move itself turns into the use on the second loop
+  // iteration.
+  {
+A a;
+for (int i = 0; i < 10; ++i) {
+  std::move(a);
+  // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-2]]:7: note: move occurred here
+}
+  }
+}
+
+// Checks also works on function parameters that have a use-after move.
+void parameters(A a) {
+  std::move(a);
+  a.foo();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+  // CHECK-MESSAGES: [[@LINE-3]]:3: note: move occurred here
+}
+
+void uniquePtrAndSharedPtr() {
+  // Use-after-moves on std::unique_ptr<> or std::shared_ptr<> aren't flagged.
+  {
+std::unique_ptr ptr;
+std::move(ptr);
+ptr.get();
+  }
+  {
+std::shared_ptr ptr;
+std::move(ptr);
+ptr.get();
+  }
+  // This is also true if the std::unique_ptr<> or std::shared_ptr<> is wrapped
+  // in a typedef.
+  {
+typedef std::unique_ptr PtrToA;
+PtrToA ptr;
+std::move(ptr);
+ptr.get();
+  }
+  {
+typedef std::shared_ptr PtrToA;
+PtrToA ptr;
+std::move(p

Re: [PATCH] D23353: [clang-tidy] Add check 'misc-use-after-move'

2016-08-10 Thread Martin Böhme via cfe-commits
mboehme added a comment.

Apologies for the size of this patch. alexfh@ said he was willing to review it 
as-is -- however, I'm happy to resubmit in smaller pieces if necessary.


https://reviews.llvm.org/D23353



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-12 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 67828.
mboehme added a comment.

Handle case where the forwarding reference is a parameter of a generic lambda.


https://reviews.llvm.org/D0

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-move-forwarding-reference.rst
  test/clang-tidy/misc-move-forwarding-reference.cpp

Index: test/clang-tidy/misc-move-forwarding-reference.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-move-forwarding-reference.cpp
@@ -0,0 +1,125 @@
+// RUN: %check_clang_tidy %s misc-move-forwarding-reference %t -- -- -std=c++14
+
+namespace std {
+template  struct remove_reference;
+
+template  struct remove_reference { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &> { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
+
+} // namespace std
+
+// Standard case.
+template  void f1(U &&SomeU) {
+  T SomeT(std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Ignore parentheses around the argument to std::move().
+template  void f2(U &&SomeU) {
+  T SomeT(std::move((SomeU)));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward((SomeU)));
+}
+
+// Handle the case correctly where std::move() is being used through a using
+// declaration.
+template  void f3(U &&SomeU) {
+  using std::move;
+  T SomeT(move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Handle the case correctly where a global specifier is prepended to
+// std::move().
+template  void f4(U &&SomeU) {
+  T SomeT(::std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(::std::forward(SomeU));
+}
+
+// Create a correct fix if there are spaces around the overload resolution
+// operator.
+template  void f5(U &&SomeU) {
+  {
+T SomeT(::std::move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(::std::forward(SomeU));
+  }
+  {
+T SomeT(std::move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(std::forward(SomeU));
+  }
+}
+
+// Ignore const rvalue reference parameters.
+template  void f6(const U &&SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the argument to std::move() is a lambda parameter (and
+// thus not actually a parameter of the function template).
+template  void f7() {
+  [](U &&SomeU) { T SomeT(std::move(SomeU)); };
+}
+
+// Ignore the case where the argument is a lvalue reference.
+template  void f8(U &SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the template parameter is a class template parameter
+// (i.e. no template argument deduction is taking place).
+template  class SomeClass {
+  void f(U &&SomeU) { T SomeT(std::move(SomeU)); }
+};
+
+// Ignore the case where the function parameter in the template isn't an rvalue
+// reference but the template argument is explicitly set to be an rvalue
+// reference.
+class A {};
+template  void foo(T);
+void f8() {
+  A a;
+  foo(std::move(a));
+}
+
+// A warning is output, but no fix is suggested, if a macro is used to rename
+// std::move.
+#define MOVE(x) std::move((x))
+template  void f9(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the argument is passed outside of the macro.
+#undef MOVE
+#define MOVE std::move
+template  void f10(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the macro does not include the "std" namespace.
+#undef MOVE
+#define MOVE move
+template  void f11(U &&SomeU) {
+  T SomeT(std::MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Handle the case correctly where the forwarding reference is a parameter of a
+// generic lambda.
+template  void f12() {
+  [] (auto&& x) { T SomeT(std::move(x)); };
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: forwarding reference passed to
+  // CHECK-FIXES: [] (auto&& x) { T SomeT(std::forward(x)); }
+}
Index: docs/clang-tidy/checks/misc-move-forwarding-reference.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-move-forwarding-reference.rst
@@ -0,0 +1,60 @@
+.. title:: clang-tidy - m

Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-12 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 67830.
mboehme added a comment.

Restore spaces around scope resolution operator in test case


https://reviews.llvm.org/D0

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-move-forwarding-reference.rst
  test/clang-tidy/misc-move-forwarding-reference.cpp

Index: test/clang-tidy/misc-move-forwarding-reference.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-move-forwarding-reference.cpp
@@ -0,0 +1,125 @@
+// RUN: %check_clang_tidy %s misc-move-forwarding-reference %t -- -- -std=c++14
+
+namespace std {
+template  struct remove_reference;
+
+template  struct remove_reference { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &> { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
+
+} // namespace std
+
+// Standard case.
+template  void f1(U &&SomeU) {
+  T SomeT(std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Ignore parentheses around the argument to std::move().
+template  void f2(U &&SomeU) {
+  T SomeT(std::move((SomeU)));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward((SomeU)));
+}
+
+// Handle the case correctly where std::move() is being used through a using
+// declaration.
+template  void f3(U &&SomeU) {
+  using std::move;
+  T SomeT(move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Handle the case correctly where a global specifier is prepended to
+// std::move().
+template  void f4(U &&SomeU) {
+  T SomeT(::std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(::std::forward(SomeU));
+}
+
+// Create a correct fix if there are spaces around the scope resolution
+// operator.
+template  void f5(U &&SomeU) {
+  {
+T SomeT(::  std  ::  move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(::std::forward(SomeU));
+  }
+  {
+T SomeT(std  ::  move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(std::forward(SomeU));
+  }
+}
+
+// Ignore const rvalue reference parameters.
+template  void f6(const U &&SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the argument to std::move() is a lambda parameter (and
+// thus not actually a parameter of the function template).
+template  void f7() {
+  [](U &&SomeU) { T SomeT(std::move(SomeU)); };
+}
+
+// Ignore the case where the argument is a lvalue reference.
+template  void f8(U &SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the template parameter is a class template parameter
+// (i.e. no template argument deduction is taking place).
+template  class SomeClass {
+  void f(U &&SomeU) { T SomeT(std::move(SomeU)); }
+};
+
+// Ignore the case where the function parameter in the template isn't an rvalue
+// reference but the template argument is explicitly set to be an rvalue
+// reference.
+class A {};
+template  void foo(T);
+void f8() {
+  A a;
+  foo(std::move(a));
+}
+
+// A warning is output, but no fix is suggested, if a macro is used to rename
+// std::move.
+#define MOVE(x) std::move((x))
+template  void f9(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the argument is passed outside of the macro.
+#undef MOVE
+#define MOVE std::move
+template  void f10(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the macro does not include the "std" namespace.
+#undef MOVE
+#define MOVE move
+template  void f11(U &&SomeU) {
+  T SomeT(std::MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Handle the case correctly where the forwarding reference is a parameter of a
+// generic lambda.
+template  void f12() {
+  [] (auto&& x) { T SomeT(std::move(x)); };
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: forwarding reference passed to
+  // CHECK-FIXES: [] (auto&& x) { T SomeT(std::forward(x)); }
+}
Index: docs/clang-tidy/checks/misc-move-forwarding-reference.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-move-forwarding-reference.rst
@@ -0,0 +1,60 @@
+.. title:: clang-tidy - misc-move-fo

Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-12 Thread Martin Böhme via cfe-commits
mboehme added inline comments.


Comment at: test/clang-tidy/misc-move-forwarding-reference.cpp:50
@@ +49,3 @@
+// operator.
+template  void f5(U &&SomeU) {
+  {

Sorry, that should have been "scope resolution operator". Comment changed.

What this is trying to test is that the replacements still happen as desired 
even if there are spaces around the scope resolution operator. Unfortunately, I 
inadvertently deleted those spaces when I clang-formatted this entire file... 
I've now restored the spaces.


Comment at: test/clang-tidy/misc-move-forwarding-reference.cpp:118
@@ +117,3 @@
+}
+
+// Handle the case correctly where the forwarding reference is a parameter of a

Good point. Done.

As it turns out, the detection didn't yet work quite correctly. This was due to 
the special format of LambdaExprs for generic lambdas. In particular, what 
tripped my test up is that the same TemplateTypeParmDecl is contained in two 
different FunctionTemplateDecls -- one for operator() and one for __invoke.

As a result, I've needed to rewrite the detection to do a little more work 
outside of the matcher. (There was no way to do it inside the matcher as the 
FunctionTemplateDecl for operator() is actually not visited by the 
RecursiveASTVisitor.)


https://reviews.llvm.org/D0



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-08-12 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 67829.
mboehme marked 2 inline comments as done.
mboehme added a comment.

Fix typo in comment


https://reviews.llvm.org/D0

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-move-forwarding-reference.rst
  test/clang-tidy/misc-move-forwarding-reference.cpp

Index: test/clang-tidy/misc-move-forwarding-reference.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-move-forwarding-reference.cpp
@@ -0,0 +1,125 @@
+// RUN: %check_clang_tidy %s misc-move-forwarding-reference %t -- -- -std=c++14
+
+namespace std {
+template  struct remove_reference;
+
+template  struct remove_reference { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &> { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
+
+} // namespace std
+
+// Standard case.
+template  void f1(U &&SomeU) {
+  T SomeT(std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Ignore parentheses around the argument to std::move().
+template  void f2(U &&SomeU) {
+  T SomeT(std::move((SomeU)));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward((SomeU)));
+}
+
+// Handle the case correctly where std::move() is being used through a using
+// declaration.
+template  void f3(U &&SomeU) {
+  using std::move;
+  T SomeT(move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Handle the case correctly where a global specifier is prepended to
+// std::move().
+template  void f4(U &&SomeU) {
+  T SomeT(::std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(::std::forward(SomeU));
+}
+
+// Create a correct fix if there are spaces around the scope resolution
+// operator.
+template  void f5(U &&SomeU) {
+  {
+T SomeT(::std::move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(::std::forward(SomeU));
+  }
+  {
+T SomeT(std::move(SomeU));
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+// CHECK-FIXES: T SomeT(std::forward(SomeU));
+  }
+}
+
+// Ignore const rvalue reference parameters.
+template  void f6(const U &&SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the argument to std::move() is a lambda parameter (and
+// thus not actually a parameter of the function template).
+template  void f7() {
+  [](U &&SomeU) { T SomeT(std::move(SomeU)); };
+}
+
+// Ignore the case where the argument is a lvalue reference.
+template  void f8(U &SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the template parameter is a class template parameter
+// (i.e. no template argument deduction is taking place).
+template  class SomeClass {
+  void f(U &&SomeU) { T SomeT(std::move(SomeU)); }
+};
+
+// Ignore the case where the function parameter in the template isn't an rvalue
+// reference but the template argument is explicitly set to be an rvalue
+// reference.
+class A {};
+template  void foo(T);
+void f8() {
+  A a;
+  foo(std::move(a));
+}
+
+// A warning is output, but no fix is suggested, if a macro is used to rename
+// std::move.
+#define MOVE(x) std::move((x))
+template  void f9(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the argument is passed outside of the macro.
+#undef MOVE
+#define MOVE std::move
+template  void f10(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the macro does not include the "std" namespace.
+#undef MOVE
+#define MOVE move
+template  void f11(U &&SomeU) {
+  T SomeT(std::MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Handle the case correctly where the forwarding reference is a parameter of a
+// generic lambda.
+template  void f12() {
+  [] (auto&& x) { T SomeT(std::move(x)); };
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: forwarding reference passed to
+  // CHECK-FIXES: [] (auto&& x) { T SomeT(std::forward(x)); }
+}
Index: docs/clang-tidy/checks/misc-move-forwarding-reference.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-move-forwarding-reference.rst
@@ -0,0 +1,60 @@
+.. title:: clang-tidy - misc-move-forwarding-

[PATCH] D23448: [ASTMatchers] Add templateTypeParmDecl() to Registry.cpp

2016-08-12 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: alexfh.
mboehme added a subscriber: cfe-commits.
Herald added subscribers: samparker, rengolin, aemerson, klimek.

This appears to have been forgotten when templateTypeParmDecl() was initially
added.

https://reviews.llvm.org/D23448

Files:
  lib/ASTMatchers/Dynamic/Registry.cpp

Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -396,6 +396,7 @@
   REGISTER_MATCHER(templateName);
   REGISTER_MATCHER(templateArgumentCountIs);
   REGISTER_MATCHER(templateSpecializationType);
+  REGISTER_MATCHER(templateTypeParmDecl);
   REGISTER_MATCHER(templateTypeParmType);
   REGISTER_MATCHER(throughUsingDecl);
   REGISTER_MATCHER(to);


Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -396,6 +396,7 @@
   REGISTER_MATCHER(templateName);
   REGISTER_MATCHER(templateArgumentCountIs);
   REGISTER_MATCHER(templateSpecializationType);
+  REGISTER_MATCHER(templateTypeParmDecl);
   REGISTER_MATCHER(templateTypeParmType);
   REGISTER_MATCHER(throughUsingDecl);
   REGISTER_MATCHER(to);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D23448: [ASTMatchers] Add templateTypeParmDecl() to Registry.cpp

2016-08-12 Thread Martin Böhme via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL278507: [ASTMatchers] Add templateTypeParmDecl() to 
Registry.cpp (authored by mboehme).

Changed prior to commit:
  https://reviews.llvm.org/D23448?vs=67831&id=67832#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D23448

Files:
  cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp

Index: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -396,6 +396,7 @@
   REGISTER_MATCHER(templateName);
   REGISTER_MATCHER(templateArgumentCountIs);
   REGISTER_MATCHER(templateSpecializationType);
+  REGISTER_MATCHER(templateTypeParmDecl);
   REGISTER_MATCHER(templateTypeParmType);
   REGISTER_MATCHER(throughUsingDecl);
   REGISTER_MATCHER(to);


Index: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -396,6 +396,7 @@
   REGISTER_MATCHER(templateName);
   REGISTER_MATCHER(templateArgumentCountIs);
   REGISTER_MATCHER(templateSpecializationType);
+  REGISTER_MATCHER(templateTypeParmDecl);
   REGISTER_MATCHER(templateTypeParmType);
   REGISTER_MATCHER(throughUsingDecl);
   REGISTER_MATCHER(to);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D21223: [clang-tidy] misc-move-const-arg: Detect if result of std::move() is being passed as a const ref argument

2016-06-10 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added reviewers: alexfh, hokein.
mboehme added a subscriber: cfe-commits.

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.

http://reviews.llvm.org/D21223

Files:
  clang-tidy/misc/MoveConstantArgumentCheck.cpp
  docs/clang-tidy/checks/misc-move-const-arg.rst
  test/clang-tidy/misc-move-const-arg.cpp

Index: test/clang-tidy/misc-move-const-arg.cpp
===
--- test/clang-tidy/misc-move-const-arg.cpp
+++ test/clang-tidy/misc-move-const-arg.cpp
@@ -71,3 +71,90 @@
   f10(1);
   f10(1);
 }
+
+struct NonMoveable {
+ public:
+  NonMoveable();
+  NonMoveable(const NonMoveable &);
+
+  NonMoveable &operator=(const NonMoveable &);
+};
+
+void callByConstRef(const NonMoveable &);
+void callByConstRef(int i, const NonMoveable &);
+
+void moveToConstReferencePositives() {
+  NonMoveable 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(NonMoveable()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as
+  // CHECK-FIXES: callByConstRef(NonMoveable());
+
+  // Works if calling a copy constructor.
+  NonMoveable other(std::move(obj));
+  // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: passing result of std::move() as
+  // CHECK-FIXES: NonMoveable 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;
+}
+
+struct Moveable {
+ public:
+  Moveable();
+  Moveable(Moveable &&);
+
+  Moveable &operator=(Moveable &&);
+};
+
+void callByValue(Moveable);
+
+void callByRValueRef(Moveable &&);
+
+template 
+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.
+  Moveable moveable;
+  callByValue(std::move(moveable));
+  callByRValueRef(std::move(moveable));
+  Moveable other(std::move(moveable));
+  other = std::move(moveable);
+
+  // No warning if std::move() not used.
+  NonMoveable non_moveable;
+  callByConstRef(non_moveable);
+
+  // No warning if instantiating a template.
+  templateFunction(non_moveable);
+
+  // No warning inside of macro expansions.
+  M3(NonMoveable, non_moveable);
+
+  // 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([non_moveable] { M3(NonMoveable, non_moveable); });
+}
Index: docs/clang-tidy/checks/misc-move-const-arg.rst
===
--- docs/clang-tidy/checks/misc-move-const-arg.rst
+++ docs/clang-tidy/checks/misc-move-const-arg.rst
@@ -3,13 +3,26 @@
 misc-move-const-arg
 ===
 
-The check warns if ``std::move()`` is called with a constant argument or an
-argument of a trivially-copyable type, e.g.:
+The check warns
+
+  - if ``std::move()`` is called with a constant argument,
+  - if ``std::move()`` is called with an argument of a trivially-copyable type,
+or
+  - if the result of ``std::move()`` is passed as a const reference argument.
+
+In all three cases, the check will suggest a fix that removes the
+``std::move()``.
+
+Here are examples of each of the three cases:
 
 .. code:: c++
 
   const string s;
   return std::move(s);  // Warning: std::move of the const variable has no effect
 
   int x;
   return std::move(x);  // Warning: std::move of the variable of a trivially-copyable type has no effect
+
+  void f(const string &s);
+  string s;
+  f(std::move(s));  // Warning: passing result of std::move as a const reference argument; no move will actually happen
Index: clang-tidy/misc/MoveConstantArgumentCheck.cpp
===
--- clang-tidy/misc/MoveConstantArgumentCheck.cpp
+++ clang-tidy/misc/MoveConstantArgumentCheck.cpp
@@ -17,5

Re: [PATCH] D21223: [clang-tidy] misc-move-const-arg: Detect if result of std::move() is being passed as a const ref argument

2016-06-13 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 60506.

http://reviews.llvm.org/D21223

Files:
  clang-tidy/misc/MoveConstantArgumentCheck.cpp
  docs/clang-tidy/checks/misc-move-const-arg.rst
  test/clang-tidy/misc-move-const-arg.cpp

Index: test/clang-tidy/misc-move-const-arg.cpp
===
--- test/clang-tidy/misc-move-const-arg.cpp
+++ test/clang-tidy/misc-move-const-arg.cpp
@@ -71,3 +71,90 @@
   f10(1);
   f10(1);
 }
+
+struct NonMoveable {
+ public:
+  NonMoveable();
+  NonMoveable(const NonMoveable &);
+
+  NonMoveable &operator=(const NonMoveable &);
+};
+
+void callByConstRef(const NonMoveable &);
+void callByConstRef(int i, const NonMoveable &);
+
+void moveToConstReferencePositives() {
+  NonMoveable 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(NonMoveable()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as
+  // CHECK-FIXES: callByConstRef(NonMoveable());
+
+  // Works if calling a copy constructor.
+  NonMoveable other(std::move(obj));
+  // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: passing result of std::move() as
+  // CHECK-FIXES: NonMoveable 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;
+}
+
+struct Moveable {
+ public:
+  Moveable();
+  Moveable(Moveable &&);
+
+  Moveable &operator=(Moveable &&);
+};
+
+void callByValue(Moveable);
+
+void callByRValueRef(Moveable &&);
+
+template 
+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.
+  Moveable moveable;
+  callByValue(std::move(moveable));
+  callByRValueRef(std::move(moveable));
+  Moveable other(std::move(moveable));
+  other = std::move(moveable);
+
+  // No warning if std::move() not used.
+  NonMoveable non_moveable;
+  callByConstRef(non_moveable);
+
+  // No warning if instantiating a template.
+  templateFunction(non_moveable);
+
+  // No warning inside of macro expansions.
+  M3(NonMoveable, non_moveable);
+
+  // 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([non_moveable] { M3(NonMoveable, non_moveable); });
+}
Index: docs/clang-tidy/checks/misc-move-const-arg.rst
===
--- docs/clang-tidy/checks/misc-move-const-arg.rst
+++ docs/clang-tidy/checks/misc-move-const-arg.rst
@@ -3,8 +3,17 @@
 misc-move-const-arg
 ===
 
-The check warns if ``std::move()`` is called with a constant argument or an
-argument of a trivially-copyable type, e.g.:
+The check warns
+
+  - if ``std::move()`` is called with a constant argument,
+  - if ``std::move()`` is called with an argument of a trivially-copyable type,
+or
+  - if the result of ``std::move()`` is passed as a const reference argument.
+
+In all three cases, the check will suggest a fix that removes the
+``std::move()``.
+
+Here are examples of each of the three cases:
 
 .. code:: c++
 
@@ -13,3 +22,7 @@
 
   int x;
   return std::move(x);  // Warning: std::move of the variable of a trivially-copyable type has no effect
+
+  void f(const string &s);
+  string s;
+  f(std::move(s));  // Warning: passing result of std::move as a const reference argument; no move will actually happen
Index: clang-tidy/misc/MoveConstantArgumentCheck.cpp
===
--- clang-tidy/misc/MoveConstantArgumentCheck.cpp
+++ clang-tidy/misc/MoveConstantArgumentCheck.cpp
@@ -17,30 +17,62 @@
 namespace tidy {
 namespace misc {
 
+static void ReplaceCallWithArg(const CallExpr *Call, DiagnosticBuilder &Diag,
+   const SourceManager &SM,
+   const LangOptions &LangOpts) {
+  const Expr *Arg = Call->getArg(0);
+
+  CharSourceRange BeforeArgumentsRange = Lexer::makeFileCharRange(
+  CharSourceRange::getCharRange(Call->getLocStart(), Arg->getLocStart()),
+  SM, LangOpts);
+  CharSourceRange AfterArgumentsRange = Lexer::makeFileCharRange(
+  CharSourceRange::getCharRange(Call->getLocEnd(),
+Call->getLocEnd().getLocWithOffset(1)),
+  SM, LangOpts);
+
+  if (BeforeArgumentsRange.isValid() && AfterArgumentsRa

Re: [PATCH] D21223: [clang-tidy] misc-move-const-arg: Detect if result of std::move() is being passed as a const ref argument

2016-06-13 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 60507.

http://reviews.llvm.org/D21223

Files:
  clang-tidy/misc/MoveConstantArgumentCheck.cpp
  docs/clang-tidy/checks/misc-move-const-arg.rst
  test/clang-tidy/misc-move-const-arg.cpp

Index: test/clang-tidy/misc-move-const-arg.cpp
===
--- test/clang-tidy/misc-move-const-arg.cpp
+++ test/clang-tidy/misc-move-const-arg.cpp
@@ -71,3 +71,90 @@
   f10(1);
   f10(1);
 }
+
+struct NonMoveable {
+ public:
+  NonMoveable();
+  NonMoveable(const NonMoveable &);
+
+  NonMoveable &operator=(const NonMoveable &);
+};
+
+void callByConstRef(const NonMoveable &);
+void callByConstRef(int i, const NonMoveable &);
+
+void moveToConstReferencePositives() {
+  NonMoveable 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(NonMoveable()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as
+  // CHECK-FIXES: callByConstRef(NonMoveable());
+
+  // Works if calling a copy constructor.
+  NonMoveable other(std::move(obj));
+  // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: passing result of std::move() as
+  // CHECK-FIXES: NonMoveable 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;
+}
+
+struct Moveable {
+ public:
+  Moveable();
+  Moveable(Moveable &&);
+
+  Moveable &operator=(Moveable &&);
+};
+
+void callByValue(Moveable);
+
+void callByRValueRef(Moveable &&);
+
+template 
+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.
+  Moveable moveable;
+  callByValue(std::move(moveable));
+  callByRValueRef(std::move(moveable));
+  Moveable other(std::move(moveable));
+  other = std::move(moveable);
+
+  // No warning if std::move() not used.
+  NonMoveable non_moveable;
+  callByConstRef(non_moveable);
+
+  // No warning if instantiating a template.
+  templateFunction(non_moveable);
+
+  // No warning inside of macro expansions.
+  M3(NonMoveable, non_moveable);
+
+  // 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([non_moveable] { M3(NonMoveable, non_moveable); });
+}
Index: docs/clang-tidy/checks/misc-move-const-arg.rst
===
--- docs/clang-tidy/checks/misc-move-const-arg.rst
+++ docs/clang-tidy/checks/misc-move-const-arg.rst
@@ -3,13 +3,26 @@
 misc-move-const-arg
 ===
 
-The check warns if ``std::move()`` is called with a constant argument or an
-argument of a trivially-copyable type, e.g.:
+The check warns
+
+  - if ``std::move()`` is called with a constant argument,
+  - if ``std::move()`` is called with an argument of a trivially-copyable type,
+or
+  - if the result of ``std::move()`` is passed as a const reference argument.
+
+In all three cases, the check will suggest a fix that removes the
+``std::move()``.
+
+Here are examples of each of the three cases:
 
 .. code:: c++
 
   const string s;
   return std::move(s);  // Warning: std::move of the const variable has no effect
 
   int x;
   return std::move(x);  // Warning: std::move of the variable of a trivially-copyable type has no effect
+
+  void f(const string &s);
+  string s;
+  f(std::move(s));  // Warning: passing result of std::move as a const reference argument; no move will actually happen
Index: clang-tidy/misc/MoveConstantArgumentCheck.cpp
===
--- clang-tidy/misc/MoveConstantArgumentCheck.cpp
+++ clang-tidy/misc/MoveConstantArgumentCheck.cpp
@@ -17,51 +17,103 @@
 namespace tidy {
 namespace misc {
 
+static void ReplaceCallWithArg(const CallExpr *Call, DiagnosticBuilder &Diag,
+   const SourceManager &SM,
+   const LangOptions &LangOpts) {
+  const Expr *Arg = Call->getArg(0);
+
+  CharSourceRange BeforeArgumentsRange = Lexer::makeFileCharRange(
+  CharSourceRange::getCharRange(Call->getLocStart(), Arg->getLocStart()),
+  SM, LangOpts);
+  CharSourceRange AfterArgumentsRange = Lexer::makeFileCharRange(
+  CharSourceRange::getCharRange(Call->getLocEnd(),
+Call->getLocEnd().getLocWithOffset(

Re: [PATCH] D21223: [clang-tidy] misc-move-const-arg: Detect if result of std::move() is being passed as a const ref argument

2016-06-13 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 60523.
mboehme marked 4 inline comments as done.

http://reviews.llvm.org/D21223

Files:
  clang-tidy/misc/MoveConstantArgumentCheck.cpp
  docs/clang-tidy/checks/misc-move-const-arg.rst
  test/clang-tidy/misc-move-const-arg.cpp

Index: test/clang-tidy/misc-move-const-arg.cpp
===
--- test/clang-tidy/misc-move-const-arg.cpp
+++ test/clang-tidy/misc-move-const-arg.cpp
@@ -71,3 +71,90 @@
   f10(1);
   f10(1);
 }
+
+struct NonMoveable {
+ public:
+  NonMoveable();
+  NonMoveable(const NonMoveable &);
+
+  NonMoveable &operator=(const NonMoveable &);
+};
+
+void callByConstRef(const NonMoveable &);
+void callByConstRef(int i, const NonMoveable &);
+
+void moveToConstReferencePositives() {
+  NonMoveable 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(NonMoveable()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as
+  // CHECK-FIXES: callByConstRef(NonMoveable());
+
+  // Works if calling a copy constructor.
+  NonMoveable other(std::move(obj));
+  // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: passing result of std::move() as
+  // CHECK-FIXES: NonMoveable 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;
+}
+
+struct Moveable {
+ public:
+  Moveable();
+  Moveable(Moveable &&);
+
+  Moveable &operator=(Moveable &&);
+};
+
+void callByValue(Moveable);
+
+void callByRValueRef(Moveable &&);
+
+template 
+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.
+  Moveable moveable;
+  callByValue(std::move(moveable));
+  callByRValueRef(std::move(moveable));
+  Moveable other(std::move(moveable));
+  other = std::move(moveable);
+
+  // No warning if std::move() not used.
+  NonMoveable non_moveable;
+  callByConstRef(non_moveable);
+
+  // No warning if instantiating a template.
+  templateFunction(non_moveable);
+
+  // No warning inside of macro expansions.
+  M3(NonMoveable, non_moveable);
+
+  // 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([non_moveable] { M3(NonMoveable, non_moveable); });
+}
Index: docs/clang-tidy/checks/misc-move-const-arg.rst
===
--- docs/clang-tidy/checks/misc-move-const-arg.rst
+++ docs/clang-tidy/checks/misc-move-const-arg.rst
@@ -3,13 +3,26 @@
 misc-move-const-arg
 ===
 
-The check warns if ``std::move()`` is called with a constant argument or an
-argument of a trivially-copyable type, e.g.:
+The check warns
+
+  - if ``std::move()`` is called with a constant argument,
+  - if ``std::move()`` is called with an argument of a trivially-copyable type,
+or
+  - if the result of ``std::move()`` is passed as a const reference argument.
+
+In all three cases, the check will suggest a fix that removes the
+``std::move()``.
+
+Here are examples of each of the three cases:
 
 .. code:: c++
 
   const string s;
   return std::move(s);  // Warning: std::move of the const variable has no effect
 
   int x;
   return std::move(x);  // Warning: std::move of the variable of a trivially-copyable type has no effect
+
+  void f(const string &s);
+  string s;
+  f(std::move(s));  // Warning: passing result of std::move as a const reference argument; no move will actually happen
Index: clang-tidy/misc/MoveConstantArgumentCheck.cpp
===
--- clang-tidy/misc/MoveConstantArgumentCheck.cpp
+++ clang-tidy/misc/MoveConstantArgumentCheck.cpp
@@ -17,51 +17,77 @@
 namespace tidy {
 namespace misc {
 
+static void ReplaceCallWithArg(const CallExpr *Call, DiagnosticBuilder &Diag,
+   const SourceManager &SM,
+   const LangOptions &LangOpts) {
+  const Expr *Arg = Call->getArg(0);
+
+  CharSourceRange BeforeArgumentsRange = Lexer::makeFileCharRange(
+  CharSourceRange::getCharRange(Call->getLocStart(), Arg->getLocStart()),
+  SM, LangOpts);
+  CharSourceRange AfterArgumentsRange = Lexer::makeFileCharRange(
+  CharSourceRange::getCharRange(Call->getLocEnd(),
+  

Re: [PATCH] D21223: [clang-tidy] misc-move-const-arg: Detect if result of std::move() is being passed as a const ref argument

2016-06-13 Thread Martin Böhme via cfe-commits
mboehme added inline comments.


Comment at: clang-tidy/misc/MoveConstantArgumentCheck.cpp:37
@@ +36,3 @@
+  if (BeforeArgumentsRange.isValid() && AfterArgumentsRange.isValid()) {
+(*Diag) << FixItHint::CreateRemoval(BeforeArgumentsRange)
+<< FixItHint::CreateRemoval(AfterArgumentsRange);

alexfh wrote:
> Alternatively, this function could return a `llvm::SmallVector` 
> (either empty or with the fixes) and the caller could just feed it to the 
> result of `diag()`. Not much difference though, just pointing to this 
> possibility.
Thanks for the suggestion! If it's OK with you, though, I'd like to keep this 
as-is -- I feel it makes the call-site clearer.


Comment at: clang-tidy/misc/MoveConstantArgumentCheck.cpp:42
@@ +41,3 @@
+
+CharSourceRange FileCharRangeForExpr(const Expr *TheExpr,
+ const SourceManager &SM,

alexfh wrote:
> With two lines of implementation and just one caller, this function doesn't 
> seem to add any value.
I've inlined the function. (I think I originally had two places where it got 
called, so I factored it out, but then one of those places went away.)


Comment at: clang-tidy/misc/MoveConstantArgumentCheck.cpp:116
@@ +115,3 @@
+// and that appears to take precendence.
+if (SM.isMacroBodyExpansion(CallMove->getLocStart()) ||
+SM.isMacroArgExpansion(CallMove->getLocStart())) {

alexfh wrote:
> Is this equivalent to just ignoring all cases where 
> `CallMove->getLocStart().isMacroID()`? If not, what's the subset of the cases 
> that would be ignored by `isMacroID()`, but not with the current condition?
Actually, having looked into this some more, it seems that the macro cases are 
already handled by the check "if (!FileMoveRange.isValid())" above -- so I'm 
deleting this entire block of code.

(I think I added the isMacroBodyExpansion() and isMacroArgExpansion() checks 
first before I moved the FileMoveRange.isValid() check, which then made them 
unnecessary.)


http://reviews.llvm.org/D21223



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D21223: [clang-tidy] misc-move-const-arg: Detect if result of std::move() is being passed as a const ref argument

2016-06-14 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 60671.

http://reviews.llvm.org/D21223

Files:
  clang-tidy/misc/MoveConstantArgumentCheck.cpp
  docs/clang-tidy/checks/misc-move-const-arg.rst
  test/clang-tidy/misc-move-const-arg.cpp

Index: test/clang-tidy/misc-move-const-arg.cpp
===
--- test/clang-tidy/misc-move-const-arg.cpp
+++ test/clang-tidy/misc-move-const-arg.cpp
@@ -71,3 +71,90 @@
   f10(1);
   f10(1);
 }
+
+class NonMoveable {
+ public:
+  NonMoveable();
+  NonMoveable(const NonMoveable &);
+
+  NonMoveable &operator=(const NonMoveable &);
+};
+
+void callByConstRef(const NonMoveable &);
+void callByConstRef(int i, const NonMoveable &);
+
+void moveToConstReferencePositives() {
+  NonMoveable 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(NonMoveable()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as
+  // CHECK-FIXES: callByConstRef(NonMoveable());
+
+  // Works if calling a copy constructor.
+  NonMoveable other(std::move(obj));
+  // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: passing result of std::move() as
+  // CHECK-FIXES: NonMoveable 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 Moveable {
+ public:
+  Moveable();
+  Moveable(Moveable &&);
+
+  Moveable &operator=(Moveable &&);
+};
+
+void callByValue(Moveable);
+
+void callByRValueRef(Moveable &&);
+
+template 
+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.
+  Moveable moveable;
+  callByValue(std::move(moveable));
+  callByRValueRef(std::move(moveable));
+  Moveable other(std::move(moveable));
+  other = std::move(moveable);
+
+  // No warning if std::move() not used.
+  NonMoveable non_moveable;
+  callByConstRef(non_moveable);
+
+  // No warning if instantiating a template.
+  templateFunction(non_moveable);
+
+  // No warning inside of macro expansions.
+  M3(NonMoveable, non_moveable);
+
+  // 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([non_moveable] { M3(NonMoveable, non_moveable); });
+}
Index: docs/clang-tidy/checks/misc-move-const-arg.rst
===
--- docs/clang-tidy/checks/misc-move-const-arg.rst
+++ docs/clang-tidy/checks/misc-move-const-arg.rst
@@ -3,13 +3,26 @@
 misc-move-const-arg
 ===
 
-The check warns if ``std::move()`` is called with a constant argument or an
-argument of a trivially-copyable type, e.g.:
+The check warns
+
+  - if ``std::move()`` is called with a constant argument,
+  - if ``std::move()`` is called with an argument of a trivially-copyable type,
+or
+  - if the result of ``std::move()`` is passed as a const reference argument.
+
+In all three cases, the check will suggest a fix that removes the
+``std::move()``.
+
+Here are examples of each of the three cases:
 
 .. code:: c++
 
   const string s;
   return std::move(s);  // Warning: std::move of the const variable has no effect
 
   int x;
   return std::move(x);  // Warning: std::move of the variable of a trivially-copyable type has no effect
+
+  void f(const string &s);
+  string s;
+  f(std::move(s));  // Warning: passing result of std::move as a const reference argument; no move will actually happen
Index: clang-tidy/misc/MoveConstantArgumentCheck.cpp
===
--- clang-tidy/misc/MoveConstantArgumentCheck.cpp
+++ clang-tidy/misc/MoveConstantArgumentCheck.cpp
@@ -17,51 +17,77 @@
 namespace tidy {
 namespace misc {
 
+static void ReplaceCallWithArg(const CallExpr *Call, DiagnosticBuilder &Diag,
+   const SourceManager &SM,
+   const LangOptions &LangOpts) {
+  const Expr *Arg = Call->getArg(0);
+
+  CharSourceRange BeforeArgumentsRange = Lexer::makeFileCharRange(
+  CharSourceRange::getCharRange(Call->getLocStart(), Arg->getLocStart()),
+  SM, LangOpts);
+  CharSourceRange AfterArgumentsRange = Lexer::makeFileCharRange(
+  CharSourceRange::getCharRange(Call->getLocEnd(),
+Call->getLocEnd().getLocWithOffset(1))

Re: [PATCH] D21223: [clang-tidy] misc-move-const-arg: Detect if result of std::move() is being passed as a const ref argument

2016-06-14 Thread Martin Böhme via cfe-commits
mboehme added inline comments.


Comment at: test/clang-tidy/misc-move-const-arg.cpp:75-76
@@ +74,4 @@
+
+struct NonMoveable {
+ public:
+  NonMoveable();

aaron.ballman wrote:
> This type isn't non-moveable. For that, you need to explicitly delete the 
> move constructor. Perhaps a better name is `NonMoveConstructible`?
> 
> Also, no need for the `public` access specifier.
> This type isn't non-moveable. For that, you need to explicitly delete the 
> move constructor.

Can you expand on this?

The standard says: "If the definition of a class X does not explicitly declare 
a move constructor, one will be implicitly declared as defaulted if and only if 
- X does not have a user-declared copy constructor [...]" (12.8/9).

Because I'm declaring a copy constructor, I would thus have expected not to get 
an implicitly-declared move constructor. Where am I going wrong here?

> Perhaps a better name is NonMoveConstructible?

But the type _is_ move-constructible (in the sense of 
std::is_move_constructible<>).

> Also, no need for the public access specifier.

Oops -- thanks for catching this.

Actually, I meant to make this a class -- not sure how the "struct" slipped in 
there.


Comment at: test/clang-tidy/misc-move-const-arg.cpp:116
@@ +115,3 @@
+struct Moveable {
+ public:
+  Moveable();

aaron.ballman wrote:
> No need for the `public` access specifier.
Thanks for cathching this -- as above, I meant to make this a class.


http://reviews.llvm.org/D21223



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D21223: [clang-tidy] misc-move-const-arg: Detect if result of std::move() is being passed as a const ref argument

2016-06-14 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 60686.

http://reviews.llvm.org/D21223

Files:
  clang-tidy/misc/MoveConstantArgumentCheck.cpp
  docs/clang-tidy/checks/misc-move-const-arg.rst
  test/clang-tidy/misc-move-const-arg.cpp

Index: test/clang-tidy/misc-move-const-arg.cpp
===
--- test/clang-tidy/misc-move-const-arg.cpp
+++ test/clang-tidy/misc-move-const-arg.cpp
@@ -71,3 +71,90 @@
   f10(1);
   f10(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 
+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); });
+}
Index: docs/clang-tidy/checks/misc-move-const-arg.rst
===
--- docs/clang-tidy/checks/misc-move-const-arg.rst
+++ docs/clang-tidy/checks/misc-move-const-arg.rst
@@ -3,13 +3,26 @@
 misc-move-const-arg
 ===
 
-The check warns if ``std::move()`` is called with a constant argument or an
-argument of a trivially-copyable type, e.g.:
+The check warns
+
+  - if ``std::move()`` is called with a constant argument,
+  - if ``std::move()`` is called with an argument of a trivially-copyable type,
+or
+  - if the result of ``std::move()`` is passed as a const reference argument.
+
+In all three cases, the check will suggest a fix that removes the
+``std::move()``.
+
+Here are examples of each of the three cases:
 
 .. code:: c++
 
   const string s;
   return std::move(s);  // Warning: std::move of the const variable has no effect
 
   int x;
   return std::move(x);  // Warning: std::move of the variable of a trivially-copyable type has no effect
+
+  void f(const string &s);
+  string s;
+  f(std::move(s));  // Warning: passing result of std::move as a const reference argument; no move will actually happen
Index: clang-tidy/misc/MoveConstantArgumentCheck.cpp
===
--- clang-tidy/misc/MoveConstantArgumentCheck.cpp
+++ clang-tidy/misc/MoveConstantArgumentCheck.cpp
@@ -17,51 +17,77 @@
 namespace tidy {
 namespace misc {
 
+static void ReplaceCallWithArg(const CallExpr *Call, DiagnosticBuilder &Diag,
+   const SourceManager &SM,
+   const LangOptions &LangOpts) {
+  const Expr *Arg = Call->getArg(0);
+
+  CharSourceRange BeforeArgumentsRange = Lexer::makeFileCharRange(
+  CharSourceRange::getCharRange(Call->getLocStart(), Arg->getLocStart()),
+  SM, LangOpts);
+  CharSourceRange After

Re: [PATCH] D21223: [clang-tidy] misc-move-const-arg: Detect if result of std::move() is being passed as a const ref argument

2016-06-14 Thread Martin Böhme via cfe-commits
mboehme added inline comments.


Comment at: test/clang-tidy/misc-move-const-arg.cpp:75-76
@@ +74,4 @@
+
+class NonMoveable {
+ public:
+  NonMoveable();

aaron.ballman wrote:
> > Can you expand on this?
> >
> > The standard says: "If the definition of a class X does not explicitly 
> > declare a move constructor, one will be implicitly declared as defaulted if 
> > and only if - X does not have a user-declared copy constructor [...]" 
> > (12.8/9).
> >
> > Because I'm declaring a copy constructor, I would thus have expected not to 
> > get an implicitly-declared move constructor. Where am I going wrong here?
> 
> Move operations are optimized versions of a copy operation, so a failed move 
> operation can fall back to perform a copy operation instead and achieve the 
> same operational semantics but with slightly worse performance. Because you 
> have a copy constructor, you do not get an implicitly-declared move 
> constructor (so that's correct), but that doesn't mean the type cannot be 
> used in a context where the user expects a move (i.e., calling `std::move()` 
> on it) -- the operation just falls back on the copy constructor.
> 
> Basically, there's an operational difference between not having the 
> implicitly-declared move constructor and having a deleted move constructor. 
> In the former, fallback to copy happens and in the latter you get a 
> diagnostic. So when I hear "non-moveable type", my brain assumes you mean 
> "get a diagnostic when you try to move."
Ah, now I see what you mean.

I've renamed "NonMoveable" to "NoMoveSemantics" (and "Moveable" to 
"MoveSemantics" for consistency). What do you think?

(I don't like NonMoveConstructible because it's prone to the same ambiguity -- 
or even more so, because std::is_move_constructible<> uses exactly the same 
term and the type is move constructible in the sense of that trait.)


http://reviews.llvm.org/D21223



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D21366: [clang-tidy] misc-move-const-arg: Fix typos

2016-06-15 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: alexfh.
mboehme added a subscriber: cfe-commits.

http://reviews.llvm.org/D21366

Files:
  clang-tidy/misc/MoveConstantArgumentCheck.cpp
  clang-tidy/misc/MoveConstantArgumentCheck.h

Index: clang-tidy/misc/MoveConstantArgumentCheck.h
===
--- clang-tidy/misc/MoveConstantArgumentCheck.h
+++ clang-tidy/misc/MoveConstantArgumentCheck.h
@@ -1,14 +1,14 @@
-//===--- MoveConstandArgumentCheck.h - clang-tidy 
-===//
+//===--- MoveConstantArgumentCheck.h - clang-tidy 
-===//
 //
 // 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_MISC_MOVECONTANTARGUMENTCHECK_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONTANTARGUMENTCHECK_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H
 
 #include "../ClangTidy.h"
 
@@ -28,4 +28,4 @@
 } // namespace tidy
 } // namespace clang
 
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONTANTARGUMENTCHECK_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H
Index: clang-tidy/misc/MoveConstantArgumentCheck.cpp
===
--- clang-tidy/misc/MoveConstantArgumentCheck.cpp
+++ clang-tidy/misc/MoveConstantArgumentCheck.cpp
@@ -1,4 +1,4 @@
-//===--- MoveConstandArgumentCheck.cpp - clang-tidy 
---===//
+//===--- MoveConstantArgumentCheck.cpp - clang-tidy 
---===//
 //
 // The LLVM Compiler Infrastructure
 //


Index: clang-tidy/misc/MoveConstantArgumentCheck.h
===
--- clang-tidy/misc/MoveConstantArgumentCheck.h
+++ clang-tidy/misc/MoveConstantArgumentCheck.h
@@ -1,14 +1,14 @@
-//===--- MoveConstandArgumentCheck.h - clang-tidy -===//
+//===--- MoveConstantArgumentCheck.h - clang-tidy -===//
 //
 // 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_MISC_MOVECONTANTARGUMENTCHECK_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONTANTARGUMENTCHECK_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H
 
 #include "../ClangTidy.h"
 
@@ -28,4 +28,4 @@
 } // namespace tidy
 } // namespace clang
 
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONTANTARGUMENTCHECK_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H
Index: clang-tidy/misc/MoveConstantArgumentCheck.cpp
===
--- clang-tidy/misc/MoveConstantArgumentCheck.cpp
+++ clang-tidy/misc/MoveConstantArgumentCheck.cpp
@@ -1,4 +1,4 @@
-//===--- MoveConstandArgumentCheck.cpp - clang-tidy ---===//
+//===--- MoveConstantArgumentCheck.cpp - clang-tidy ---===//
 //
 // The LLVM Compiler Infrastructure
 //
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D21799: [ASTMatchers] Add missing forEachArgumentWithParam() to code sample

2016-06-28 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: klimek.
mboehme added a subscriber: cfe-commits.
Herald added a subscriber: klimek.

http://reviews.llvm.org/D21799

Files:
  include/clang/ASTMatchers/ASTMatchers.h

Index: include/clang/ASTMatchers/ASTMatchers.h
===
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -3154,8 +3154,11 @@
 ///   int y;
 ///   f(y);
 /// \endcode
-/// callExpr(declRefExpr(to(varDecl(hasName("y",
-/// parmVarDecl(hasType(isInteger(
+/// callExpr(
+///   forEachArgumentWithParam(
+/// declRefExpr(to(varDecl(hasName("y",
+/// parmVarDecl(hasType(isInteger()))
+/// ))
 ///   matches f(y);
 /// with declRefExpr(...)
 ///   matching int y


Index: include/clang/ASTMatchers/ASTMatchers.h
===
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -3154,8 +3154,11 @@
 ///   int y;
 ///   f(y);
 /// \endcode
-/// callExpr(declRefExpr(to(varDecl(hasName("y",
-/// parmVarDecl(hasType(isInteger(
+/// callExpr(
+///   forEachArgumentWithParam(
+/// declRefExpr(to(varDecl(hasName("y",
+/// parmVarDecl(hasType(isInteger()))
+/// ))
 ///   matches f(y);
 /// with declRefExpr(...)
 ///   matching int y
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D21895: CFGBuilder: Fix crash when visiting a range-based for over a dependent type

2016-06-30 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: klimek.
mboehme added a subscriber: cfe-commits.

CFG generation is expected to fail in this case, but it should not crash.

Also added a test that reproduces the crash.

http://reviews.llvm.org/D21895

Files:
  lib/Analysis/CFG.cpp
  unittests/Analysis/CFGTest.cpp
  unittests/Analysis/CMakeLists.txt
  unittests/CMakeLists.txt

Index: unittests/CMakeLists.txt
===
--- unittests/CMakeLists.txt
+++ unittests/CMakeLists.txt
@@ -13,6 +13,7 @@
 add_subdirectory(Lex)
 add_subdirectory(Driver)
 if(CLANG_ENABLE_STATIC_ANALYZER)
+  add_subdirectory(Analysis)
   add_subdirectory(StaticAnalyzer)
   add_subdirectory(Frontend)
 endif()
Index: unittests/Analysis/CMakeLists.txt
===
--- /dev/null
+++ unittests/Analysis/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  )
+
+add_clang_unittest(CFGTests
+  CFGTest.cpp
+  )
+
+target_link_libraries(CFGTests
+  clangAnalysis
+  clangASTMatchers
+  clangTooling
+  )
Index: unittests/Analysis/CFGTest.cpp
===
--- /dev/null
+++ unittests/Analysis/CFGTest.cpp
@@ -0,0 +1,54 @@
+//===- unittests/Analysis/CFGTest.cpp - CFG tests -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+#include 
+#include 
+
+namespace clang {
+namespace analysis {
+namespace {
+
+// Constructing a CFG for a range-based for over a dependent type fails (but
+// should not crash).
+TEST(CFG, RangeBasedForOverDependentType) {
+  const char *Code = "class Foo;\n"
+ "template \n"
+ "void f(const T &Range) {\n"
+ "  for (const Foo *TheFoo : Range) {\n"
+ "  }\n"
+ "}\n";
+
+  class CFGCallback : public ast_matchers::MatchFinder::MatchCallback {
+  public:
+void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
+  const auto *Func = Result.Nodes.getNodeAs("func");
+  Stmt *Body = Func->getBody();
+  if (!Body)
+return;
+  std::unique_ptr cfg =
+  CFG::buildCFG(nullptr, Body, Result.Context, CFG::BuildOptions());
+  EXPECT_EQ(nullptr, cfg);
+}
+  } Callback;
+
+  ast_matchers::MatchFinder Finder;
+  Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback);
+  std::unique_ptr Factory(
+  tooling::newFrontendActionFactory(&Finder));
+  std::vector Args = {"-std=c++11"};
+  ASSERT_TRUE(tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args));
+}
+
+} // namespace
+} // namespace analysis
+} // namespace clang
Index: lib/Analysis/CFG.cpp
===
--- lib/Analysis/CFG.cpp
+++ lib/Analysis/CFG.cpp
@@ -3457,6 +3457,8 @@
 // continue statements.
 Block = nullptr;
 Succ = addStmt(S->getInc());
+if (badCFG)
+  return nullptr;
 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
 
 // The starting block for the loop increment is the block that should
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D21895: CFGBuilder: Fix crash when visiting a range-based for over a dependent type

2016-06-30 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 62374.

http://reviews.llvm.org/D21895

Files:
  lib/Analysis/CFG.cpp
  unittests/Analysis/CFGTest.cpp
  unittests/Analysis/CMakeLists.txt
  unittests/CMakeLists.txt

Index: unittests/CMakeLists.txt
===
--- unittests/CMakeLists.txt
+++ unittests/CMakeLists.txt
@@ -13,6 +13,7 @@
 add_subdirectory(Lex)
 add_subdirectory(Driver)
 if(CLANG_ENABLE_STATIC_ANALYZER)
+  add_subdirectory(Analysis)
   add_subdirectory(StaticAnalyzer)
   add_subdirectory(Frontend)
 endif()
Index: unittests/Analysis/CMakeLists.txt
===
--- /dev/null
+++ unittests/Analysis/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  )
+
+add_clang_unittest(CFGTests
+  CFGTest.cpp
+  )
+
+target_link_libraries(CFGTests
+  clangAnalysis
+  clangASTMatchers
+  clangTooling
+  )
Index: unittests/Analysis/CFGTest.cpp
===
--- /dev/null
+++ unittests/Analysis/CFGTest.cpp
@@ -0,0 +1,58 @@
+//===- unittests/Analysis/CFGTest.cpp - CFG tests -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+#include 
+#include 
+
+namespace clang {
+namespace analysis {
+namespace {
+
+// Constructing a CFG for a range-based for over a dependent type fails (but
+// should not crash).
+TEST(CFG, RangeBasedForOverDependentType) {
+  const char *Code = "class Foo;\n"
+ "template \n"
+ "void f(const T &Range) {\n"
+ "  for (const Foo *TheFoo : Range) {\n"
+ "  }\n"
+ "}\n";
+
+  class CFGCallback : public ast_matchers::MatchFinder::MatchCallback {
+  public:
+bool SawFunctionBody = false;
+
+void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
+  const auto *Func = Result.Nodes.getNodeAs("func");
+  Stmt *Body = Func->getBody();
+  if (!Body)
+return;
+  SawFunctionBody = true;
+  std::unique_ptr cfg =
+  CFG::buildCFG(nullptr, Body, Result.Context, CFG::BuildOptions());
+  EXPECT_EQ(nullptr, cfg);
+}
+  } Callback;
+
+  ast_matchers::MatchFinder Finder;
+  Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback);
+  std::unique_ptr Factory(
+  tooling::newFrontendActionFactory(&Finder));
+  std::vector Args = {"-std=c++11"};
+  ASSERT_TRUE(tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args));
+  EXPECT_TRUE(Callback.SawFunctionBody);
+}
+
+} // namespace
+} // namespace analysis
+} // namespace clang
Index: lib/Analysis/CFG.cpp
===
--- lib/Analysis/CFG.cpp
+++ lib/Analysis/CFG.cpp
@@ -3457,6 +3457,8 @@
 // continue statements.
 Block = nullptr;
 Succ = addStmt(S->getInc());
+if (badCFG)
+  return nullptr;
 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
 
 // The starting block for the loop increment is the block that should
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D21895: CFGBuilder: Fix crash when visiting a range-based for over a dependent type

2016-06-30 Thread Martin Böhme via cfe-commits
mboehme marked an inline comment as done.
mboehme added a comment.

http://reviews.llvm.org/D21895



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-07-11 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: sbenza.
mboehme added a subscriber: cfe-commits.

The check emits a warning if std::move() is applied to a forwarding reference, 
i.e. an rvalue reference of a function template argument type.

If a developer is unaware of the special rules for template argument deduction 
on forwarding references, it will seem reasonable to apply std::move() to the 
forwarding reference, in the same way that this would be done for a "normal" 
rvalue reference.

This has a consequence that is usually unwanted and possibly surprising: If the 
function that takes the forwarding reference as its parameter is called with an 
lvalue, that lvalue will be moved from (and hence placed into an indeterminate 
state) even though no std::move() was applied to the lvalue at the callsite.

As a fix, the check will suggest replacing the std::move() with a 
std::forward().

http://reviews.llvm.org/D0

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.h
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-move-forwarding-reference.rst
  test/clang-tidy/misc-move-forwarding-reference.cpp

Index: test/clang-tidy/misc-move-forwarding-reference.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-move-forwarding-reference.cpp
@@ -0,0 +1,68 @@
+// RUN: %check_clang_tidy %s misc-move-forwarding-reference %t
+
+namespace std {
+template  struct remove_reference;
+
+template  struct remove_reference { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &> { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
+
+} // namespace std
+
+// Standard case.
+template  void f(U &&SomeU) {
+  T SomeT(std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Ignore parentheses around the argument to std::move().
+template  void f2(U &&SomeU) {
+  T SomeT(std::move((SomeU)));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward((SomeU)));
+}
+
+// Handle the case correctly where std::move() is being used through a using
+// declaration.
+template  void f3(U &&SomeU) {
+  using std::move;
+  T SomeT(move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Handle the case correctly where a global specifier is prepended to
+// std::move().
+template  void f4(U &&SomeU) {
+  T SomeT(::std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(::std::forward(SomeU));
+}
+
+// Ignore const rvalue reference parameters.
+template  void f5(const U &&SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the argument to std::move() is a lambda parameter (and
+// thus not actually a parameter of the function template).
+template  void f6() {
+  [](U &&SomeU) { T SomeT(std::move(SomeU)); };
+}
+
+// Ignore the case where the argument is a lvalue reference.
+template  void f7(U &SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the template parameter is a class template parameter
+// (i.e. no template argument deduction is taking place).
+template  class SomeClass {
+  void f(U &&SomeU) { T SomeT(std::move(SomeU)); }
+};
Index: docs/clang-tidy/checks/misc-move-forwarding-reference.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-move-forwarding-reference.rst
@@ -0,0 +1,60 @@
+.. title:: clang-tidy - misc-move-forwarding-reference
+
+misc-move-forwarding-reference
+==
+
+Warns if ``std::move`` is called on a forwarding reference, for example:
+
+  .. code-block:: c++
+
+template 
+void foo(T&& t) {
+  bar(std::move(t));
+}
+
+`Forwarding references
+`_ should
+typically be passed to ``std::forward`` instead of ``std::move``, and this is
+the fix that will be suggested.
+
+(A forwarding reference is an rvalue reference of a type that is a deduced
+function template argument.)
+
+In this example, the suggested fix would be
+
+  .. code-block:: c++
+
+bar(std::forward(t));
+
+Background
+--
+
+Code like the example above is often written in the expectation that ``T&&``
+will always end up being an rvalue reference, no matter what type is deduced for
+``T``, and that it is therefore not possible to pass an lvalue to ``foo()``.
+However, this is not true. Consider this example:
+
+  .. code-block:: c++
+
+std::string s = "Hello, world";
+foo(s);
+
+

[PATCH] D22263: [clang-tidy] Fix syntax error in modernize-use-emplace.rst

2016-07-12 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: alexfh.
mboehme added a subscriber: cfe-commits.

The missing newline after the ".. code:: c++" was causing a compile error when 
producing the documentation

http://reviews.llvm.org/D22263

Files:
  docs/clang-tidy/checks/modernize-use-emplace.rst

Index: docs/clang-tidy/checks/modernize-use-emplace.rst
===
--- docs/clang-tidy/checks/modernize-use-emplace.rst
+++ docs/clang-tidy/checks/modernize-use-emplace.rst
@@ -48,6 +48,7 @@
 In this case the calls of ``push_back`` won't be replaced.
 
 .. code:: c++
+
std::vector > v;
v.push_back(new int(5));
auto *ptr = int;


Index: docs/clang-tidy/checks/modernize-use-emplace.rst
===
--- docs/clang-tidy/checks/modernize-use-emplace.rst
+++ docs/clang-tidy/checks/modernize-use-emplace.rst
@@ -48,6 +48,7 @@
 In this case the calls of ``push_back`` won't be replaced.
 
 .. code:: c++
+
 	std::vector > v;
 	v.push_back(new int(5));
 	auto *ptr = int;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-07-12 Thread Martin Böhme via cfe-commits
mboehme updated this revision to Diff 63663.
mboehme added a comment.

Addressed Prazek's review comments.


http://reviews.llvm.org/D0

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.cpp
  clang-tidy/misc/MoveForwardingReferenceCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-move-forwarding-reference.rst
  test/clang-tidy/misc-move-forwarding-reference.cpp

Index: test/clang-tidy/misc-move-forwarding-reference.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-move-forwarding-reference.cpp
@@ -0,0 +1,83 @@
+// RUN: %check_clang_tidy %s misc-move-forwarding-reference %t
+
+namespace std {
+template  struct remove_reference;
+
+template  struct remove_reference { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &> { typedef _Tp type; };
+
+template  struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template 
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
+
+} // namespace std
+
+// Standard case.
+template  void f(U &&SomeU) {
+  T SomeT(std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Ignore parentheses around the argument to std::move().
+template  void f2(U &&SomeU) {
+  T SomeT(std::move((SomeU)));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward((SomeU)));
+}
+
+// Handle the case correctly where std::move() is being used through a using
+// declaration.
+template  void f3(U &&SomeU) {
+  using std::move;
+  T SomeT(move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(std::forward(SomeU));
+}
+
+// Handle the case correctly where a global specifier is prepended to
+// std::move().
+template  void f4(U &&SomeU) {
+  T SomeT(::std::move(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+  // CHECK-FIXES: T SomeT(::std::forward(SomeU));
+}
+
+// Ignore const rvalue reference parameters.
+template  void f5(const U &&SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the argument to std::move() is a lambda parameter (and
+// thus not actually a parameter of the function template).
+template  void f6() {
+  [](U &&SomeU) { T SomeT(std::move(SomeU)); };
+}
+
+// Ignore the case where the argument is a lvalue reference.
+template  void f7(U &SomeU) {
+  T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the template parameter is a class template parameter
+// (i.e. no template argument deduction is taking place).
+template  class SomeClass {
+  void f(U &&SomeU) { T SomeT(std::move(SomeU)); }
+};
+
+// No warning is output if the std::move happens inside a macro.
+#define MOVE(x) std::move((x))
+template  void f8(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+}
+
+// A warning is output, but no fix is suggested, if a macro is used to rename
+// std::move but the argument is passed outside of the macro.
+#undef MOVE
+#define MOVE std::move
+template  void f9(U &&SomeU) {
+  T SomeT(MOVE(SomeU));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
Index: docs/clang-tidy/checks/misc-move-forwarding-reference.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-move-forwarding-reference.rst
@@ -0,0 +1,60 @@
+.. title:: clang-tidy - misc-move-forwarding-reference
+
+misc-move-forwarding-reference
+==
+
+Warns if ``std::move`` is called on a forwarding reference, for example:
+
+  .. code-block:: c++
+
+template 
+void foo(T&& t) {
+  bar(std::move(t));
+}
+
+`Forwarding references
+`_ should
+typically be passed to ``std::forward`` instead of ``std::move``, and this is
+the fix that will be suggested.
+
+(A forwarding reference is an rvalue reference of a type that is a deduced
+function template argument.)
+
+In this example, the suggested fix would be
+
+  .. code-block:: c++
+
+bar(std::forward(t));
+
+Background
+--
+
+Code like the example above is often written in the expectation that ``T&&``
+will always end up being an rvalue reference, no matter what type is deduced for
+``T``, and that it is therefore not possible to pass an lvalue to ``foo()``.
+However, this is not true. Consider this example:
+
+  .. code-block:: c++
+
+std::string s = "Hello, world";
+foo(s);
+
+This code compiles and, after the call to ``foo()``, ``s`` is left in an
+indeterminate state because it has been moved from. This may be surprising to
+the caller of ``foo()`` because no ``std::move`` was used when calling
+``foo()``.
+
+The reason for this behavior lies in the special rule for t

Re: [PATCH] D22220: [clang-tidy] Add check 'misc-move-forwarding-reference'

2016-07-12 Thread Martin Böhme via cfe-commits
mboehme marked 5 inline comments as done.
mboehme added a comment.

In http://reviews.llvm.org/D0#480415, @mgehre wrote:

> Nice check. This should be mentioned in docs/ReleaseNotes.rst


Done.



Comment at: clang-tidy/misc/MoveForwardingReferenceCheck.cpp:34
@@ +33,3 @@
+  if (CallRange.isValid()) {
+const std::string ForwardName =
+"forward<" + TypeParmType->getDecl()->getName().str() + ">";

Prazek wrote:
> you could probably use llvm::StringRef here, but I am not sure about it - ask 
> Alex.
I've talked to Alex -- using a Twine to avoid multiple allocations is the best 
I can do here.


Comment at: docs/clang-tidy/checks/misc-move-forwarding-reference.rst:29
@@ +28,3 @@
+
+Background
+--

Prazek wrote:
> Very nice section! good idea.
> 
> So I have a thoughts about multiple sections in documentation (which is not a 
> issue for you).
> I think the check lists doc should not include sections - it doesn't look 
> good and it also prevents people from using sections in docs.
Do I understand correctly that you're not expecting me to change anything here?


http://reviews.llvm.org/D0



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22263: [clang-tidy] Fix syntax error in modernize-use-emplace.rst

2016-07-13 Thread Martin Böhme via cfe-commits
mboehme abandoned this revision.
mboehme added a comment.

Good to hear -- abandoning this patch then.


http://reviews.llvm.org/D22263



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22170: [OpenCL] Fixes opencl.cl testcase issues and cl-strict-aliasing only allowed with cl-std=CL

2016-07-14 Thread Martin Böhme via cfe-commits
mboehme added a subscriber: mboehme.
mboehme added a comment.

The test cfe/trunk/test/Frontend/opencl.cl that was added here appears to
fail.

Running "ninja check-clang" doesn't pick this up because
cfe/trunk/test/Frontend/lit.local.cfg doesn't contain '.cl' as a file
suffix:

config.suffixes = ['.c', '.cpp', '.m', '.mm', '.ll']

As soon as I add the suffix:

config.suffixes = ['.c', '.cpp', '.m', '.mm', '.ll', '.cl']

the test fails. The failure seems to happen because of the new
"CHECK_INVALID_OPENCL_VERSION" checks. For OpenCL versions 1.1 and 1.2,
compilation fails for these checks because of the expected error "blocks
support disabled".

A solution seems to be to add "-fblocks" to the command line for these two
checks.

I'll be sending a patch with this fix out for review shortly.


Repository:
  rL LLVM

https://reviews.llvm.org/D22170



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D22170: [OpenCL] Fixes opencl.cl testcase issues and cl-strict-aliasing only allowed with cl-std=CL

2016-07-14 Thread Martin Böhme via cfe-commits
The test cfe/trunk/test/Frontend/opencl.cl that was added here appears to
fail.

Running "ninja check-clang" doesn't pick this up because
cfe/trunk/test/Frontend/lit.local.cfg doesn't contain '.cl' as a file
suffix:

config.suffixes = ['.c', '.cpp', '.m', '.mm', '.ll']

As soon as I add the suffix:

config.suffixes = ['.c', '.cpp', '.m', '.mm', '.ll', '.cl']

the test fails. The failure seems to happen because of the new
"CHECK_INVALID_OPENCL_VERSION" checks. For OpenCL versions 1.1 and 1.2,
compilation fails for these checks because of the expected error "blocks
support disabled".

A solution seems to be to add "-fblocks" to the command line for these two
checks.

I'll be sending a patch with this fix out for review shortly.


On 13 July 2016 at 23:28, Yaxun Liu via cfe-commits <
cfe-commits@lists.llvm.org> wrote:

> This revision was automatically updated to reflect the committed changes.
> Closed by commit rL275318: [OpenCL] Fixes failures in test/Driver/
> opencl.cl. (authored by yaxunl).
>
> Changed prior to commit:
>   http://reviews.llvm.org/D22170?vs=63722&id=63862#toc
>
> Repository:
>   rL LLVM
>
> http://reviews.llvm.org/D22170
>
> Files:
>   cfe/trunk/lib/Frontend/CompilerInvocation.cpp
>   cfe/trunk/test/Driver/opencl.cl
>   cfe/trunk/test/Frontend/opencl-blocks.cl
>   cfe/trunk/test/Frontend/opencl.cl
>
>
> ___
> cfe-commits mailing list
> cfe-commits@lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
>


-- 

Martin Böhme

Software Engineer

mboe...@google.com
+49 176 64059273

Google Germany GmbH
Maria-Goeppert-Str. 3
23562 Lübeck

Geschäftsführer: Matthew Scott Sucherman, Paul Terence Manicle

Registergericht und -nummer: Hamburg, HRB 86891

Sitz der Gesellschaft: Hamburg

Diese E-Mail ist vertraulich. Wenn Sie nicht der richtige Adressat sind,
leiten Sie diese bitte nicht weiter, informieren Sie den Absender und
löschen Sie die E-Mail und alle Anhänge. Vielen Dank.



This e-mail is confidential. If you are not the right addressee please do
not forward it, please inform the sender, and please erase this e-mail
including any attachments. Thanks.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D22349: [OpenCL] Actually activate Frontend/opencl.cl test and fix test bugs

2016-07-14 Thread Martin Böhme via cfe-commits
mboehme created this revision.
mboehme added a reviewer: bkramer.
mboehme added subscribers: cfe-commits, ashi1.

rL275318 added the test Frontend/opencl.cl test, but that test was never 
actually run because Frontend/lit.local.cfg doesn't contain the '.cl' file 
suffix.

Once the test is activated, it fails with (unintended) compile errors in the 
newly added CHECK_INVALID_OPENCL_VERSION checks.

This patch adds the '.cl' file suffix to Frontend/lit.local.cfg to activate the 
test and fixes the test bug by adding '-fblocks' to the relevant command lines.

https://reviews.llvm.org/D22349

Files:
  test/Frontend/lit.local.cfg
  test/Frontend/opencl.cl

Index: test/Frontend/opencl.cl
===
--- test/Frontend/opencl.cl
+++ test/Frontend/opencl.cl
@@ -6,8 +6,8 @@
 // RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL1.1 -fblocks -DBLOCKS
 // RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL1.2 -fblocks -DBLOCKS
 // RUN: %clang_cc1 %s -triple amdgcn--amdhsa -x c -std=c99 -verify 
-fsyntax-only
-// RUN: %clang_cc1 -cl-std=CL1.1 -cl-strict-aliasing %s 2>&1 | FileCheck 
--check-prefix=CHECK-INVALID-OPENCL-VERSION11 %s
-// RUN: %clang_cc1 -cl-std=CL1.2 -cl-strict-aliasing %s 2>&1 | FileCheck 
--check-prefix=CHECK-INVALID-OPENCL-VERSION12 %s
+// RUN: %clang_cc1 -cl-std=CL1.1 -cl-strict-aliasing -fblocks %s 2>&1 | 
FileCheck --check-prefix=CHECK-INVALID-OPENCL-VERSION11 %s
+// RUN: %clang_cc1 -cl-std=CL1.2 -cl-strict-aliasing -fblocks %s 2>&1 | 
FileCheck --check-prefix=CHECK-INVALID-OPENCL-VERSION12 %s
 // RUN: %clang_cc1 -cl-std=CL2.0 -cl-strict-aliasing %s 2>&1 | FileCheck 
--check-prefix=CHECK-INVALID-OPENCL-VERSION20 %s
 
 void f(void (^g)(void)) {
@@ -24,4 +24,4 @@
 
 // CHECK-INVALID-OPENCL-VERSION11: warning: OpenCL version 1.1 does not 
support the option '-cl-strict-aliasing'
 // CHECK-INVALID-OPENCL-VERSION12: warning: OpenCL version 1.2 does not 
support the option '-cl-strict-aliasing'
-// CHECK-INVALID-OPENCL-VERSION20: warning: OpenCL version 2.0 does not 
support the option '-cl-strict-aliasing'
\ No newline at end of file
+// CHECK-INVALID-OPENCL-VERSION20: warning: OpenCL version 2.0 does not 
support the option '-cl-strict-aliasing'
Index: test/Frontend/lit.local.cfg
===
--- test/Frontend/lit.local.cfg
+++ test/Frontend/lit.local.cfg
@@ -1 +1 @@
-config.suffixes = ['.c', '.cpp', '.m', '.mm', '.ll']
+config.suffixes = ['.c', '.cpp', '.m', '.mm', '.ll', '.cl']


Index: test/Frontend/opencl.cl
===
--- test/Frontend/opencl.cl
+++ test/Frontend/opencl.cl
@@ -6,8 +6,8 @@
 // RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL1.1 -fblocks -DBLOCKS
 // RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL1.2 -fblocks -DBLOCKS
 // RUN: %clang_cc1 %s -triple amdgcn--amdhsa -x c -std=c99 -verify -fsyntax-only
-// RUN: %clang_cc1 -cl-std=CL1.1 -cl-strict-aliasing %s 2>&1 | FileCheck --check-prefix=CHECK-INVALID-OPENCL-VERSION11 %s
-// RUN: %clang_cc1 -cl-std=CL1.2 -cl-strict-aliasing %s 2>&1 | FileCheck --check-prefix=CHECK-INVALID-OPENCL-VERSION12 %s
+// RUN: %clang_cc1 -cl-std=CL1.1 -cl-strict-aliasing -fblocks %s 2>&1 | FileCheck --check-prefix=CHECK-INVALID-OPENCL-VERSION11 %s
+// RUN: %clang_cc1 -cl-std=CL1.2 -cl-strict-aliasing -fblocks %s 2>&1 | FileCheck --check-prefix=CHECK-INVALID-OPENCL-VERSION12 %s
 // RUN: %clang_cc1 -cl-std=CL2.0 -cl-strict-aliasing %s 2>&1 | FileCheck --check-prefix=CHECK-INVALID-OPENCL-VERSION20 %s
 
 void f(void (^g)(void)) {
@@ -24,4 +24,4 @@
 
 // CHECK-INVALID-OPENCL-VERSION11: warning: OpenCL version 1.1 does not support the option '-cl-strict-aliasing'
 // CHECK-INVALID-OPENCL-VERSION12: warning: OpenCL version 1.2 does not support the option '-cl-strict-aliasing'
-// CHECK-INVALID-OPENCL-VERSION20: warning: OpenCL version 2.0 does not support the option '-cl-strict-aliasing'
\ No newline at end of file
+// CHECK-INVALID-OPENCL-VERSION20: warning: OpenCL version 2.0 does not support the option '-cl-strict-aliasing'
Index: test/Frontend/lit.local.cfg
===
--- test/Frontend/lit.local.cfg
+++ test/Frontend/lit.local.cfg
@@ -1 +1 @@
-config.suffixes = ['.c', '.cpp', '.m', '.mm', '.ll']
+config.suffixes = ['.c', '.cpp', '.m', '.mm', '.ll', '.cl']
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   >