[PATCH] D43745: Fix cppcoreguidelines-pro-bounds-pointer-arithmetic not working for functions with auto return specifier.

2018-07-27 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

Does it also work with lambdas (being implicitly auto) that return pointers? A 
test case for that would be nice.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D43745



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


[PATCH] D16403: Add scope information to CFG

2017-06-23 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

Please consider also https://reviews.llvm.org/D15031
It already handles all possible control flows. Instead of ScopeBegin and 
ScopeEnd,
it introduces LifetimeEnds elements. It's a more specific in that is also
correctly models the order of lifetime expiry of variables and the order
or destructor calls / lifetime ending.


Repository:
  rL LLVM

https://reviews.llvm.org/D16403



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


[PATCH] D18914: [clang-tidy] new readability-redundant-inline

2019-05-08 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

Thank you for the review input! After learning about `inlinehint`, I don't feel 
its worthwhile for me to continue this check.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D18914/new/

https://reviews.llvm.org/D18914



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


[PATCH] D24892: [clang-tidy] Add option "LiteralInitializers" to cppcoreguidelines-pro-type-member-init

2019-05-08 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 198714.
mgehre added a comment.
Herald added a project: clang.

Implement review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D24892/new/

https://reviews.llvm.org/D24892

Files:
  clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
  clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst
  
clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-use-assignment.cpp

Index: clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-use-assignment.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-use-assignment.cpp
@@ -0,0 +1,40 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -config="{CheckOptions: [{key: "cppcoreguidelines-pro-type-member-init.UseAssignment", value: 1}]}" -- -std=c++11
+
+struct T {
+  int i;
+};
+
+struct S {
+  bool b;
+  // CHECK-FIXES: bool b = false;
+  char c;
+  // CHECK-FIXES: char c = 0;
+  signed char sc;
+  // CHECK-FIXES: signed char sc = 0;
+  unsigned char uc;
+  // CHECK-FIXES: unsigned char uc = 0U;
+  int i;
+  // CHECK-FIXES: int i = 0;
+  unsigned u;
+  // CHECK-FIXES: unsigned u = 0U;
+  long l;
+  // CHECK-FIXES: long l = 0L;
+  unsigned long ul;
+  // CHECK-FIXES: unsigned long ul = 0UL;
+  long long ll;
+  // CHECK-FIXES: long long ll = 0LL;
+  unsigned long long ull;
+  // CHECK-FIXES: unsigned long long ull = 0ULL;
+  float f;
+  // CHECK-FIXES: float f = 0.0F;
+  double d;
+  // CHECK-FIXES: double d = 0.0;
+  long double ld;
+  // CHECK-FIXES: double ld = 0.0L;
+  int *ptr;
+  // CHECK-FIXES: int *ptr = nullptr;
+  T t;
+  // CHECK-FIXES: T t{};
+  S() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields:
+};
Index: clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst
+++ clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst
@@ -33,6 +33,10 @@
zero-initialized during construction. For performance critical code, it may
be important to not initialize fixed-size array members. Default is `0`.
 
+.. option:: UseAssignment
+   If set to non-zero, the check will provide fix-its with literal initializers
+   (``int i = 0;``) instead of curly braces (``int i{};``).
+
 This rule is part of the "Type safety" profile of the C++ Core
 Guidelines, corresponding to rule Type.6. See
 https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-type-memberinit.
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -63,6 +63,11 @@
 
 
 The improvements are...
+- Added `UseAssignment` option to `cppcoreguidelines-pro-type-member-init`
+
+  If set to true, the check will provide fix-its with literal initializers
+  (``int i = 0;``) instead of curly braces (``int i{};``).
+
 
 Improvements to clang-tidy
 --
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
===
--- clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
@@ -65,6 +65,11 @@
 
   // Whether arrays need to be initialized or not. Default is false.
   bool IgnoreArrays;
+
+  // Whether fix-its for initialization of fundamental type use assignment
+  // instead of brace initalization. Only effective in C++11 mode. Default is
+  // false.
+  bool UseAssignment;
 };
 
 } // namespace cppcoreguidelines
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
===
--- clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
@@ -251,7 +251,8 @@
 ProTypeMemberInitCheck::ProTypeMemberInitCheck(StringRef Name,
ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context),
-  IgnoreArrays(Options.get("IgnoreArrays", false)) {}
+  IgnoreArrays(Options.get("IgnoreArrays", false)),
+  UseAssignment(Options.getLocalOrGlobal("UseAssignment", false)) {}
 
 void ProTypeMemberInitCheck::registerMatchers(MatchFinder *Finder) {
   if (!getLangOpts().CPlusPlus)
@@ -315,6 +316,7 @@
 
 void ProTypeMemberInitCheck::

[PATCH] D61700: [clang-tidy] readability-redundant-declaration: fix false positive with C "extern inline"

2019-05-08 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre created this revision.
mgehre added reviewers: alexfh, danielmarjamaki.
Herald added a subscriber: xazax.hun.
Herald added a project: clang.

readability-redundant-declaration was diagnosing a redundant declaration
on "extern inline void f();", which is needed in C code to force an external 
definition
of the inline function f. (This is different to how inline behaves in C++).


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D61700

Files:
  clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
  clang-tools-extra/test/clang-tidy/readability-redundant-declaration.c
  clang-tools-extra/test/clang-tidy/readability-redundant-declaration.cpp


Index: clang-tools-extra/test/clang-tidy/readability-redundant-declaration.cpp
===
--- clang-tools-extra/test/clang-tidy/readability-redundant-declaration.cpp
+++ clang-tools-extra/test/clang-tidy/readability-redundant-declaration.cpp
@@ -68,3 +68,13 @@
 // CHECK-FIXES: {{^}}DEFINE(test);{{$}}
 
 } // namespace macros
+
+inline void g() {}
+
+inline void g(); // g
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant 'g' declaration
+// CHECK-FIXES: {{^}}// g{{$}}
+
+extern inline void g(); // extern g
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: redundant 'g' declaration
+// CHECK-FIXES: {{^}}// extern g{{$}}
\ No newline at end of file
Index: clang-tools-extra/test/clang-tidy/readability-redundant-declaration.c
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/readability-redundant-declaration.c
@@ -0,0 +1,31 @@
+// RUN: %check_clang_tidy %s readability-redundant-declaration %t
+
+extern int Xyz;
+extern int Xyz; // Xyz
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant 'Xyz' declaration 
[readability-redundant-declaration]
+// CHECK-FIXES: {{^}}// Xyz{{$}}
+int Xyz = 123;
+
+extern int A;
+extern int A, B;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant 'A' declaration
+// CHECK-FIXES: {{^}}extern int A, B;{{$}}
+
+extern int Buf[10];
+extern int Buf[10]; // Buf[10]
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant 'Buf' declaration
+// CHECK-FIXES: {{^}}// Buf[10]{{$}}
+
+static int f();
+static int f(); // f
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant 'f' declaration
+// CHECK-FIXES: {{^}}// f{{$}}
+static int f() {}
+
+inline void g() {}
+
+inline void g();
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant 'g' declaration
+
+// OK: Needed to emit an external definition.
+extern inline void g();
\ No newline at end of file
Index: clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
@@ -18,6 +18,10 @@
 namespace tidy {
 namespace readability {
 
+AST_MATCHER(FunctionDecl, doesDeclarationForceExternallyVisibleDefinition) {
+  return Node.doesDeclarationForceExternallyVisibleDefinition();
+}
+
 RedundantDeclarationCheck::RedundantDeclarationCheck(StringRef Name,
  ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context),
@@ -26,8 +30,10 @@
 void RedundantDeclarationCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
   namedDecl(anyOf(varDecl(unless(isDefinition())),
-  functionDecl(unless(anyOf(isDefinition(), isDefaulted(),
-hasParent(friendDecl()))
+  functionDecl(unless(anyOf(
+  isDefinition(), isDefaulted(),
+  doesDeclarationForceExternallyVisibleDefinition(),
+  hasParent(friendDecl()))
   .bind("Decl"),
   this);
 }


Index: clang-tools-extra/test/clang-tidy/readability-redundant-declaration.cpp
===
--- clang-tools-extra/test/clang-tidy/readability-redundant-declaration.cpp
+++ clang-tools-extra/test/clang-tidy/readability-redundant-declaration.cpp
@@ -68,3 +68,13 @@
 // CHECK-FIXES: {{^}}DEFINE(test);{{$}}
 
 } // namespace macros
+
+inline void g() {}
+
+inline void g(); // g
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant 'g' declaration
+// CHECK-FIXES: {{^}}// g{{$}}
+
+extern inline void g(); // extern g
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: redundant 'g' declaration
+// CHECK-FIXES: {{^}}// extern g{{$}}
\ No newline at end of file
Index: clang-tools-extra/test/clang-tidy/readability-redundant-declaration.c
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/readability-redundant-declaration.c
@@ -0,0 +1,31 @@
+// RUN: %check_clang_tidy %s readability-redundant-declaration %t
+
+extern int Xyz;
+extern int Xyz

[PATCH] D61749: [clang-tidy] initial version of readability-static-const-method

2019-05-09 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre created this revision.
mgehre added reviewers: alexfh, aaron.ballman.
Herald added subscribers: xazax.hun, mgorny.
Herald added a project: clang.

Finds non-static member functions that can be made ``const`` or ``static``.
The check conservatively tries to preserve logical costness in favor of
physical costness. It will not recommend to make member functions ``const``
that call (const) member functions on a non-static data members,
e.g. ``std::unique_ptr::get`` because that might indicate logical
non-costness. Currently, it will only make member functions ``const`` if they
only access to ``this`` is to read members of builtin type.

I have run this check (repeatedly) over llvm-project. It made 1708 member 
functions
``static``. Out of those, I had to exclude 22 via ``NOLINT`` because their 
address
was taken and stored in a variable of pointer-to-member type (e.g. passed to
llvm::StringSwitch).
It also made 243 member functions ``const``. (This is currently very 
conservative
to have no false-positives and can hopefully be extended in the future.)

You can find the results here: 
https://github.com/mgehre/llvm-project/commits/static_const_eval


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D61749

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/StaticConstMethodCheck.cpp
  clang-tools-extra/clang-tidy/readability/StaticConstMethodCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability-static-const-method.rst
  clang-tools-extra/test/clang-tidy/readability-static-const-method.cpp

Index: clang-tools-extra/test/clang-tidy/readability-static-const-method.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/readability-static-const-method.cpp
@@ -0,0 +1,317 @@
+// RUN: %check_clang_tidy %s readability-static-const-method %t
+
+class DoNotMakeEmptyStatic {
+  void emptyMethod() {}
+  void empty_method_out_of_line();
+};
+
+void DoNotMakeEmptyStatic::empty_method_out_of_line() {}
+
+struct Str {
+  void const_method() const;
+  void non_const_method();
+};
+
+class A;
+
+void const_use(const A *);
+void non_const_use(A *);
+void const_use(const A &);
+void non_const_use(A &);
+
+class A {
+  int field;
+  const int const_field;
+  static int static_field;
+  Str S;
+  Str Sref;
+  Str *Sptr;
+
+  void no_use() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'no_use' can be made static
+// CHECK-FIXES: {{^}}  static void no_use() {
+int i = 1;
+  }
+
+  int read_field() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_field' can be made const
+// CHECK-FIXES: {{^}}  int read_field() const {
+return field;
+  }
+
+  int read_const_field() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_const_field' can be made const
+// CHECK-FIXES: {{^}}  int read_const_field() const {
+return const_field;
+  }
+
+  void write_field() {
+field = 1;
+  }
+
+  int call_non_const_member() { return read_field(); }
+
+  int call_const_member() {
+// TODO: :[[@LINE-1]]:7: warning: method 'call_const_member' can be made const
+// TODO: {{^}}  int call_const_member() const {
+return already_const();
+  }
+
+  int call_static_member() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'call_static_member' can be made static
+// CHECK-FIXES: {{^}}  static int call_static_member() {
+already_static();
+  }
+
+  void call_non_const_member_on_field() { S.non_const_method(); }
+
+  void call_const_member_on_field() {
+// Technically, this method could be const-qualified,
+// but it might not be logically const.
+S.const_method();
+  }
+
+  void call_non_const_member_on_pointee() {
+Sptr->non_const_method();
+  }
+
+  void call_const_member_on_pointee() {
+// Technically, this method could be const-qualified,
+// but it might not be logically const.
+Sptr->const_method();
+  }
+
+  Str *return_pointer() {
+// Technically, this method could be const-qualified,
+// but it might not be logically const.
+return Sptr;
+  }
+
+  void call_non_const_member_on_ref() {
+Sref.non_const_method();
+  }
+
+  void call_const_member_on_ref() {
+// Technically, this method could be const-qualified,
+// but it might not be logically const.
+Sref.const_method();
+  }
+
+  void call_const_member_on_ref_of_ref() {
+const auto &L = Sref;
+// Technically, this method could be const-qualified,
+// but it might not be logically const.
+L.const_method();
+  }
+
+  Str &return_ref() {
+// Technically, this method could be const-qualified,
+// but it might not be logically const.
+return Sref;
+  }
+
+  int read_static() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: me

[PATCH] D61749: [clang-tidy] initial version of readability-static-const-method

2019-06-10 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

Ping


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61749/new/

https://reviews.llvm.org/D61749



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


[PATCH] D63088: [clang-tidy] misc-unused-parameters: don't comment out parameter name for C code

2019-06-10 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre created this revision.
mgehre added reviewers: klimek, ilya-biryukov, lebedev.ri, aaron.ballman.
Herald added a subscriber: xazax.hun.
Herald added a project: clang.

The fixit `int square(int /*num*/)` yields `error: parameter name omitted` for 
C code. Enable it only for C++ code.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D63088

Files:
  clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
  clang-tools-extra/test/clang-tidy/misc-unused-parameters.c


Index: clang-tools-extra/test/clang-tidy/misc-unused-parameters.c
===
--- clang-tools-extra/test/clang-tidy/misc-unused-parameters.c
+++ clang-tools-extra/test/clang-tidy/misc-unused-parameters.c
@@ -4,7 +4,7 @@
 // =
 void a(int i) {;}
 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused 
[misc-unused-parameters]
-// CHECK-FIXES: {{^}}void a(int  /*i*/) {;}{{$}}
+// CHECK-FIXES: {{^}}void a(int i) {;}{{$}}
 
 static void b(); // In C, forward declarations can leave out parameters.
 static void b(int i) {;}
Index: clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
@@ -138,16 +138,21 @@
 Indexer = llvm::make_unique(*Result.Context);
   }
 
-  // Comment out parameter name for non-local functions.
+  // Cannot remove parameter for non-local functions.
   if (Function->isExternallyVisible() ||
   !Result.SourceManager->isInMainFile(Function->getLocation()) ||
   !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function)) {
-SourceRange RemovalRange(Param->getLocation());
-// Note: We always add a space before the '/*' to not accidentally create a
-// '*/*' for pointer types, which doesn't start a comment. clang-format 
will
-// clean this up afterwards.
-MyDiag << FixItHint::CreateReplacement(
-RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
+
+// Comment out parameter name.
+if (Result.Context->getLangOpts().CPlusPlus) {
+  SourceRange RemovalRange(Param->getLocation());
+  // Note: We always add a space before the '/*' to not accidentally create
+  // a
+  // '*/*' for pointer types, which doesn't start a comment. clang-format
+  // will clean this up afterwards.
+  MyDiag << FixItHint::CreateReplacement(
+  RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
+}
 return;
   }
 


Index: clang-tools-extra/test/clang-tidy/misc-unused-parameters.c
===
--- clang-tools-extra/test/clang-tidy/misc-unused-parameters.c
+++ clang-tools-extra/test/clang-tidy/misc-unused-parameters.c
@@ -4,7 +4,7 @@
 // =
 void a(int i) {;}
 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
-// CHECK-FIXES: {{^}}void a(int  /*i*/) {;}{{$}}
+// CHECK-FIXES: {{^}}void a(int i) {;}{{$}}
 
 static void b(); // In C, forward declarations can leave out parameters.
 static void b(int i) {;}
Index: clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
@@ -138,16 +138,21 @@
 Indexer = llvm::make_unique(*Result.Context);
   }
 
-  // Comment out parameter name for non-local functions.
+  // Cannot remove parameter for non-local functions.
   if (Function->isExternallyVisible() ||
   !Result.SourceManager->isInMainFile(Function->getLocation()) ||
   !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function)) {
-SourceRange RemovalRange(Param->getLocation());
-// Note: We always add a space before the '/*' to not accidentally create a
-// '*/*' for pointer types, which doesn't start a comment. clang-format will
-// clean this up afterwards.
-MyDiag << FixItHint::CreateReplacement(
-RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
+
+// Comment out parameter name.
+if (Result.Context->getLangOpts().CPlusPlus) {
+  SourceRange RemovalRange(Param->getLocation());
+  // Note: We always add a space before the '/*' to not accidentally create
+  // a
+  // '*/*' for pointer types, which doesn't start a comment. clang-format
+  // will clean this up afterwards.
+  MyDiag << FixItHint::CreateReplacement(
+  RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
+}
 return;
   }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D63088: [clang-tidy] misc-unused-parameters: don't comment out parameter name for C code

2019-06-10 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 203873.
mgehre added a comment.

Fix rewrapped comment


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63088/new/

https://reviews.llvm.org/D63088

Files:
  clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
  clang-tools-extra/test/clang-tidy/misc-unused-parameters.c


Index: clang-tools-extra/test/clang-tidy/misc-unused-parameters.c
===
--- clang-tools-extra/test/clang-tidy/misc-unused-parameters.c
+++ clang-tools-extra/test/clang-tidy/misc-unused-parameters.c
@@ -4,7 +4,7 @@
 // =
 void a(int i) {;}
 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused 
[misc-unused-parameters]
-// CHECK-FIXES: {{^}}void a(int  /*i*/) {;}{{$}}
+// CHECK-FIXES: {{^}}void a(int i) {;}{{$}}
 
 static void b(); // In C, forward declarations can leave out parameters.
 static void b(int i) {;}
Index: clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
@@ -138,16 +138,20 @@
 Indexer = llvm::make_unique(*Result.Context);
   }
 
-  // Comment out parameter name for non-local functions.
+  // Cannot remove parameter for non-local functions.
   if (Function->isExternallyVisible() ||
   !Result.SourceManager->isInMainFile(Function->getLocation()) ||
   !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function)) {
-SourceRange RemovalRange(Param->getLocation());
-// Note: We always add a space before the '/*' to not accidentally create a
-// '*/*' for pointer types, which doesn't start a comment. clang-format 
will
-// clean this up afterwards.
-MyDiag << FixItHint::CreateReplacement(
-RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
+
+// Comment out parameter name.
+if (Result.Context->getLangOpts().CPlusPlus) {
+  SourceRange RemovalRange(Param->getLocation());
+  // Note: We always add a space before the '/*' to not accidentally create
+  // a '*/*' for pointer types, which doesn't start a comment. clang-format
+  // will clean this up afterwards.
+  MyDiag << FixItHint::CreateReplacement(
+  RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
+}
 return;
   }
 


Index: clang-tools-extra/test/clang-tidy/misc-unused-parameters.c
===
--- clang-tools-extra/test/clang-tidy/misc-unused-parameters.c
+++ clang-tools-extra/test/clang-tidy/misc-unused-parameters.c
@@ -4,7 +4,7 @@
 // =
 void a(int i) {;}
 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
-// CHECK-FIXES: {{^}}void a(int  /*i*/) {;}{{$}}
+// CHECK-FIXES: {{^}}void a(int i) {;}{{$}}
 
 static void b(); // In C, forward declarations can leave out parameters.
 static void b(int i) {;}
Index: clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
@@ -138,16 +138,20 @@
 Indexer = llvm::make_unique(*Result.Context);
   }
 
-  // Comment out parameter name for non-local functions.
+  // Cannot remove parameter for non-local functions.
   if (Function->isExternallyVisible() ||
   !Result.SourceManager->isInMainFile(Function->getLocation()) ||
   !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function)) {
-SourceRange RemovalRange(Param->getLocation());
-// Note: We always add a space before the '/*' to not accidentally create a
-// '*/*' for pointer types, which doesn't start a comment. clang-format will
-// clean this up afterwards.
-MyDiag << FixItHint::CreateReplacement(
-RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
+
+// Comment out parameter name.
+if (Result.Context->getLangOpts().CPlusPlus) {
+  SourceRange RemovalRange(Param->getLocation());
+  // Note: We always add a space before the '/*' to not accidentally create
+  // a '*/*' for pointer types, which doesn't start a comment. clang-format
+  // will clean this up afterwards.
+  MyDiag << FixItHint::CreateReplacement(
+  RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
+}
 return;
   }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D63088: [clang-tidy] misc-unused-parameters: don't comment out parameter name for C code

2019-06-16 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked an inline comment as done.
mgehre added inline comments.



Comment at: clang-tools-extra/test/clang-tidy/misc-unused-parameters.c:1-7
 // RUN: %check_clang_tidy %s misc-unused-parameters %t -- -- -xc
 
 // Basic removal
 // =
 void a(int i) {;}
 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused 
[misc-unused-parameters]
-// CHECK-FIXES: {{^}}void a(int  /*i*/) {;}{{$}}

lebedev.ri wrote:
> This screams a separate bug to me.
> Does `%check_clang_tidy` not check that sources, after applying fix-it's, 
> still parse?
Unfortunately, no :-(


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63088/new/

https://reviews.llvm.org/D63088



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


[PATCH] D63088: [clang-tidy] misc-unused-parameters: don't comment out parameter name for C code

2019-06-16 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked an inline comment as done.
mgehre added inline comments.



Comment at: clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp:141-156
+  // Cannot remove parameter for non-local functions.
   if (Function->isExternallyVisible() ||
   !Result.SourceManager->isInMainFile(Function->getLocation()) ||
   !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function)) {
-SourceRange RemovalRange(Param->getLocation());
-// Note: We always add a space before the '/*' to not accidentally create a
-// '*/*' for pointer types, which doesn't start a comment. clang-format 
will
-// clean this up afterwards.
-MyDiag << FixItHint::CreateReplacement(
-RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
+
+// Comment out parameter name.
+if (Result.Context->getLangOpts().CPlusPlus) {

lebedev.ri wrote:
> I'd recommend to instead do less confusing
> ```
>   // Cannot remove parameter for non-local functions.
>   if (Function->isExternallyVisible() ||
>   !Result.SourceManager->isInMainFile(Function->getLocation()) ||
>   !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function)) 
> {
> // It is illegal to omit parameter name here in C code, so early-out.
> if (!Result.Context->getLangOpts().CPlusPlus)
>   return;
> 
> SourceRange RemovalRange(Param->getLocation());
> // Note: We always add a space before the '/*' to not accidentally create
> // a '*/*' for pointer types, which doesn't start a comment. clang-format
> // will clean this up afterwards.
> MyDiag << FixItHint::CreateReplacement(
> RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
> return;
>   }
> ```
Good idea, will do!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63088/new/

https://reviews.llvm.org/D63088



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


[PATCH] D64448: gsl::Owner/gsl::Pointer: Add implicit annotations for some std types

2019-07-11 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked 5 inline comments as done.
mgehre added a comment.

In D64448#159 , @gribozavr wrote:

> For example, libc++ wraps everything in std in an inline namespace.


I believed that I had written a test for inline namespaces, but seems that I 
shouldn't be working in the middle of the night.
I will add one.

In D64448#159 , @gribozavr wrote:

> I don't know how various versions of libstdc++ differ.


The current implementation passed the (partial) test case
https://github.com/mgehre/llvm-project/blob/lifetime-ci/lifetime-attr-test.cpp
for different standard libraries, namely libc++ 7.1.0, libc++ 8.0.1rc2, 
libstdc++ 4.6.4, libstdc++ 4.8.5,
libstdc++ 4.9.4, libstdc++ 5.4.0, libstdc++ 6.5.0, libstdc++ 7.3.0,
libstdc++ 8.3.0 and libstdc++ 9.1.0.




Comment at: clang/include/clang/Basic/TokenKinds.def:486
+TYPE_TRAIT_1(__is_gsl_owner, IsGslOwner, KEYCXX)
+TYPE_TRAIT_1(__is_gsl_pointer, IsGslPointer, KEYCXX)
 KEYWORD(__underlying_type   , KEYCXX)

gribozavr wrote:
> I'd suggest to split type trait implementations into a separate patch.
> 
> Are these type traits being exposed only for testing? I'm not sure it is a 
> good idea to do that -- people will end up using them in production code -- 
> is that a concern? If so, maybe it would be better to test through warnings.
I copied that approach from https://reviews.llvm.org/D50119.
If people do it in production code, then at least the two leading underscores 
should tell them "I'm not supposed to use this".

I considered a test through warnings, but how would I trigger them? Add 
`-Wlifetime-categories-debug` which emits notes whenever a 
[[gsl::Owner/Pointer]] is implicitly/explicitly attached to class?



Comment at: clang/test/AST/ast-dump-attr.cpp:222
+
+class [[gsl::Pointer]] PointerWithoutArgument{};
+// CHECK: CXXRecordDecl{{.*}} class PointerWithoutArgument

gribozavr wrote:
> This test and related code changes could be split off into a separate patch.
I was thinking whether it made sense to separate
- fixing the AST dump of attributes with optional type parameter when there is 
not such attribute
- introduce and attribute with optional type parameter while AST dumping it is 
broken
so I decided that both are closely related. Otherwise the fix and its test are 
in separate PRs?



Comment at: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp:86
+
+// Test builtin annotation for std types.
+namespace std {

gribozavr wrote:
> I feel like these tests would be better off in a separate file.
> 
> It would be also good to explain which exact library we are trying to imitate 
> in this test. Different libraries use different coding patterns.
This is imitating techniques from different libraries - all techniques that 
this implementation supports.

To check if all techniques that this implementation supports are enough for 
real standard library implementations,
I use 
https://github.com/mgehre/llvm-project/blob/lifetime-ci/lifetime-attr-test.cpp 
against them. Various versions of libstdc++
and libc++ passed. I will test MSVC standard library next. If they would use a 
technique that this implementation does not support yet,
I will add support for that and the corresponding test here.
I might fix MSVC support (if needed) only in the following PR:



Comment at: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp:103
+template 
+class set_iterator {};
+

gribozavr wrote:
> Is it actually defined like that?
There might be a standard library implementation that does it like this. This 
tests that we will use the `using iterator = set_iterator;` in `class set {` 
to attach the [[gsl::Pointer]] to the `set_iterator`. 



Comment at: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp:140
+
+class thread;
+static_assert(!__is_gsl_pointer(thread), "");

gribozavr wrote:
> Unclear what this test is testing.
> 
> If there's something special about thread (e.g., it looks very much like an 
> owner or a pointer, and a buggy implementation can easily declare thread to 
> be an owner or a pointer), please explain that in a comment.
> 
> If you're testing that some random name is not being picked up by inference 
> rules, I'd suggest to use an obviously-fictional name ("class 
> type_unknown_to_compiler;")
Agreed, I will rename this to an obviously-fictional name.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64448/new/

https://reviews.llvm.org/D64448



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


[PATCH] D61749: [clang-tidy] initial version of readability-convert-member-functions-to-static

2019-07-11 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 209360.
mgehre added a comment.

Implement comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61749/new/

https://reviews.llvm.org/D61749

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ConvertMemberFunctionsToStatic.cpp
  clang-tools-extra/clang-tidy/readability/ConvertMemberFunctionsToStatic.h
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/docs/clang-tidy/checks/readability-convert-member-functions-to-static.rst
  
clang-tools-extra/test/clang-tidy/readability-convert-member-functions-to-static.cpp

Index: clang-tools-extra/test/clang-tidy/readability-convert-member-functions-to-static.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/readability-convert-member-functions-to-static.cpp
@@ -0,0 +1,218 @@
+// RUN: %check_clang_tidy %s readability-convert-member-functions-to-static %t
+
+class DoNotMakeEmptyStatic {
+  void emptyMethod() {}
+  void empty_method_out_of_line();
+};
+
+void DoNotMakeEmptyStatic::empty_method_out_of_line() {}
+
+class A {
+  int field;
+  const int const_field;
+  static int static_field;
+
+  void no_use() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'no_use' can be made static
+// CHECK-FIXES: {{^}}  static void no_use() {
+int i = 1;
+  }
+
+  int read_field() {
+return field;
+  }
+
+  void write_field() {
+field = 1;
+  }
+
+  int call_non_const_member() { return read_field(); }
+
+  int call_static_member() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'call_static_member' can be made static
+// CHECK-FIXES: {{^}}  static int call_static_member() {
+already_static();
+  }
+
+  int read_static() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_static' can be made static
+// CHECK-FIXES: {{^}}  static int read_static() {
+return static_field;
+  }
+  void write_static() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'write_static' can be made static
+// CHECK-FIXES: {{^}}  static void write_static() {
+static_field = 1;
+  }
+
+  static int already_static() { return static_field; }
+
+  int already_const() const { return field; }
+
+  int already_const_convert_to_static() const {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'already_const_convert_to_static' can be made static
+// CHECK-FIXES: {{^}}  static int already_const_convert_to_static() {
+return static_field;
+  }
+
+  static int out_of_line_already_static();
+
+  void out_of_line_call_static();
+  // CHECK-FIXES: {{^}}  static void out_of_line_call_static();
+  int out_of_line_const_to_static() const;
+  // CHECK-FIXES: {{^}}  static int out_of_line_const_to_static() ;
+};
+
+int A::out_of_line_already_static() { return 0; }
+
+void A::out_of_line_call_static() {
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: method 'out_of_line_call_static' can be made static
+  // CHECK-FIXES: {{^}}void A::out_of_line_call_static() {
+  already_static();
+}
+
+int A::out_of_line_const_to_static() const {
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'out_of_line_const_to_static' can be made static
+  // CHECK-FIXES: {{^}}int A::out_of_line_const_to_static() {
+  return 0;
+}
+
+struct KeepVirtual {
+  virtual int f() { return 0; }
+  virtual int h() const { return 0; }
+};
+
+struct KeepVirtualDerived : public KeepVirtual {
+  int f() { return 0; }
+  int h() const override { return 0; }
+};
+
+// Don't add 'static' to special member functions and operators.
+struct KeepSpecial {
+  KeepSpecial() { int L = 0; }
+  ~KeepSpecial() { int L = 0; }
+  int operator+() { return 0; }
+  operator int() { return 0; }
+};
+
+void KeepLambdas() {
+  using FT = int (*)();
+  auto F = static_cast([]() { return 0; });
+  auto F2 = []() { return 0; };
+}
+
+template 
+struct KeepWithTemplateBase : public Base {
+  int i;
+  // We cannot make these methods static because they might need to override
+  // a function from Base.
+  int static_f() { return 0; }
+};
+
+template 
+struct KeepTemplateClass {
+  int i;
+  // We cannot make these methods static because a specialization
+  // might use *this differently.
+  int static_f() { return 0; }
+};
+
+struct KeepTemplateMethod {
+  int i;
+  // We cannot make these methods static because a specialization
+  // might use *this differently.
+  template 
+  static int static_f() { return 0; }
+};
+
+void instantiate() {
+  struct S {};
+  KeepWithTemplateBase I1;
+  I1.static_f();
+
+  KeepTemplateClass I2;
+  I2.static_f();
+
+  KeepTemplateMethod I3;
+  I3.static_f();
+}
+
+struct Trailing {
+  auto g() const -> int {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'g' can be made static
+// CHECK-FIXES: {{^}}  static

[PATCH] D61749: [clang-tidy] initial version of readability-convert-member-functions-to-static

2019-07-11 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

This should address all remaining comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61749/new/

https://reviews.llvm.org/D61749



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


[PATCH] D64448: gsl::Owner/gsl::Pointer: Add implicit annotations for some std types

2019-07-11 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 209370.
mgehre marked 9 inline comments as done.
mgehre added a comment.

- Implement comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64448/new/

https://reviews.llvm.org/D64448

Files:
  clang/include/clang/Basic/AttrDocs.td
  clang/test/SemaCXX/attr-gsl-owner-pointer.cpp

Index: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
===
--- clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
+++ clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
@@ -83,14 +83,14 @@
 static_assert(__is_gsl_pointer(int &), "");
 static_assert(__is_gsl_pointer(int *), "");
 
-// Test builtin annotation for std types.
+// Test builtin attributes for std types.
 namespace std {
-// Complete class
+// Attributes are added to a (complete) class.
 class any {
 };
 static_assert(__is_gsl_owner(any), "");
 
-// Complete template
+// Attributes are added to a instantiatons of a complete template.
 template 
 class vector {
 public:
@@ -99,45 +99,60 @@
 static_assert(__is_gsl_owner(vector), "");
 static_assert(__is_gsl_pointer(vector::iterator), "");
 
+// If std::container::iterator is a using declaration, Attributes are added to
+// the underlying class
 template 
-class set_iterator {};
+class __set_iterator {};
 
 template 
 class set {
 public:
-  using iterator = set_iterator;
+  using iterator = __set_iterator;
 };
 static_assert(__is_gsl_pointer(set::iterator), "");
 
+// If std::container::iterator is a typedef, Attributes are added to the
+// underlying class. Inline namespaces are ignored when checking if
+// the class lives in the std namespace.
+inline namespace inlinens {
 template 
-class map_iterator {};
+class __map_iterator {};
 
 template 
 class map {
 public:
-  typedef map_iterator iterator;
+  typedef __map_iterator iterator;
 };
+} // namespace inlinens
 static_assert(__is_gsl_pointer(map::iterator), "");
 
-// list has an implicit gsl::Owner attribute,
+// std::list has an implicit gsl::Owner attribute,
 // but explicit attributes take precedence.
 template 
 class [[gsl::Pointer]] list{};
 static_assert(!__is_gsl_owner(list), "");
 static_assert(__is_gsl_pointer(list), "");
 
-// Forward declared template
+// Forward declared template (Owner)
 template <
 class CharT,
 class Traits>
 class basic_regex;
 static_assert(__is_gsl_owner(basic_regex), "");
 
+// Forward declared template (Pointer)
 template 
 class reference_wrapper;
 static_assert(__is_gsl_pointer(reference_wrapper), "");
 
-class thread;
-static_assert(!__is_gsl_pointer(thread), "");
-static_assert(!__is_gsl_owner(thread), "");
+class some_unknown_type;
+static_assert(!__is_gsl_pointer(some_unknown_type), "");
+static_assert(!__is_gsl_owner(some_unknown_type), "");
 } // namespace std
+
+namespace user {
+// If a class is not in the std namespace, we don't add implicit attributes.
+class any {
+};
+static_assert(!__is_gsl_owner(any), "");
+} // namespace user
Index: clang/include/clang/Basic/AttrDocs.td
===
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -4164,7 +4164,7 @@
 When annotating a class ``O`` with ``[[gsl::Owner(T)]]``, then each function
 that returns cv-qualified ``T&`` or ``T*`` is assumed to return a
 pointer/reference to the data owned by ``O``. The owned data is assumed to end
-its lifetime once the owning object's lifetime ends. The argument is ``T`` is
+its lifetime once the owning object's lifetime ends. The argument ``T`` is
 optional.
 
 This attribute may be used by analysis tools but will not have effect on code
@@ -4177,7 +4177,7 @@
   let Content = [{
 When annotating a class with ``[[gsl::Pointer(T)]]``, it assumed to be a
 non-owning type whose objects can point to ``T`` type objects or dangle.
-The argument is ``T`` is optional.
+The argument ``T`` is optional.
 
 This attribute may be used by analysis tools but will not have effect on code
 generation.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D64448: gsl::Owner/gsl::Pointer: Add implicit annotations for some std types

2019-07-11 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

In D64448#1581771 , @gribozavr wrote:

> In D64448#1581719 , @mgehre wrote:
>
> > In D64448#159 , @gribozavr 
> > wrote:
> >
> > > I don't know how various versions of libstdc++ differ.
> >
> >
> > The current implementation passed the (partial) test case
> >  
> > https://github.com/mgehre/llvm-project/blob/lifetime-ci/lifetime-attr-test.cpp
> >  for different standard libraries, namely libc++ 7.1.0, libc++ 8.0.1rc2, 
> > libstdc++ 4.6.4, libstdc++ 4.8.5,
> >  libstdc++ 4.9.4, libstdc++ 5.4.0, libstdc++ 6.5.0, libstdc++ 7.3.0,
> >  libstdc++ 8.3.0 and libstdc++ 9.1.0.
>
>
> Yes, I saw the testcase -- but how do different libstdc++ versions differ?


I didn't know whether they would differ, but the test tells me that they don't 
differ significantly (i.e. in introducing new techniques). 
Would you like me to test with other standard libraries (besides MSVC, which I 
already planned)?




Comment at: clang/include/clang/Basic/TokenKinds.def:486
+TYPE_TRAIT_1(__is_gsl_owner, IsGslOwner, KEYCXX)
+TYPE_TRAIT_1(__is_gsl_pointer, IsGslPointer, KEYCXX)
 KEYWORD(__underlying_type   , KEYCXX)

gribozavr wrote:
> mgehre wrote:
> > gribozavr wrote:
> > > I'd suggest to split type trait implementations into a separate patch.
> > > 
> > > Are these type traits being exposed only for testing? I'm not sure it is 
> > > a good idea to do that -- people will end up using them in production 
> > > code -- is that a concern? If so, maybe it would be better to test 
> > > through warnings.
> > I copied that approach from https://reviews.llvm.org/D50119.
> > If people do it in production code, then at least the two leading 
> > underscores should tell them "I'm not supposed to use this".
> > 
> > I considered a test through warnings, but how would I trigger them? Add 
> > `-Wlifetime-categories-debug` which emits notes whenever a 
> > [[gsl::Owner/Pointer]] is implicitly/explicitly attached to class?
> > If people do it in production code, then at least the two leading 
> > underscores should tell them "I'm not supposed to use this".
> 
> That's not what two underscores mean. These custom type traits, being 
> language extensions, must have a name that won't collide with any 
> user-defined name, hence two underscores. Two underscores mean nothing about 
> whether the user is allowed to use it or not. Sure the code might become 
> non-portable to other compilers, but that's not what the concern is. My 
> concern is that code that people write might become unportable to future 
> versions of Clang, where we would have to change behavior of these type 
> traits (or it would just subtly change in some corner case and we won't 
> notice since we don't consider it a public API).
> 
> > I considered a test through warnings, but how would I trigger them?
> 
> I meant regular warnings, that are the objective of this analysis -- warnings 
> about dereferencing dangling pointers. If we get those warnings for the 
> types-under-test, then obviously they have the correct annotations from the 
> compiler's point of view.
I spent a lot of time debugging on the full lifetime analysis, and knowing 
exactly which type has which Attribute (especially if inference is involved) 
was quite important.
I would say that adding additional code to trigger a real lifetime warning 
- requires that we first add some lifetime warnings to clang (currently in a 
different PR)
- obscures the purpose of the check, i.e. checking the attributes and not the 
warnings themselves
- and makes debugging hard when the test fails (warnings involve at least one 
Owner and one Pointer, so either of those could have made the test fail)
I'd prefer if we can test the attributes directly.



Comment at: clang/test/AST/ast-dump-attr.cpp:222
+
+class [[gsl::Pointer]] PointerWithoutArgument{};
+// CHECK: CXXRecordDecl{{.*}} class PointerWithoutArgument

gribozavr wrote:
> mgehre wrote:
> > gribozavr wrote:
> > > This test and related code changes could be split off into a separate 
> > > patch.
> > I was thinking whether it made sense to separate
> > - fixing the AST dump of attributes with optional type parameter when there 
> > is not such attribute
> > - introduce and attribute with optional type parameter while AST dumping it 
> > is broken
> > so I decided that both are closely related. Otherwise the fix and its test 
> > are in separate PRs?
> Totally makes sense to have the fix and the test is the same PR, but they 
> seem to be separable from attribute inference for std types, right?
Yes, you are right. And Aaron would like to have the type parameter already 
optional in D63954, so I will move this part over there.



Comment at: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp:86
+
+// Test builtin annotation for std types.
+namespace s

[PATCH] D63954: Add lifetime categories attributes

2019-07-14 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added inline comments.



Comment at: clang/include/clang/Basic/Attr.td:2770
+def Owner : InheritableAttr {
+  let Spellings = [CXX11<"gsl", "Owner">];
+  let Subjects = SubjectList<[CXXRecord]>;

aaron.ballman wrote:
> xazax.hun wrote:
> > aaron.ballman wrote:
> > > xazax.hun wrote:
> > > > aaron.ballman wrote:
> > > > > Has Microsoft already added support for this? We had an unfortunate 
> > > > > problem with `gsl::suppress` where we introduced the attribute first 
> > > > > and MSVC introduced it under a different, incompatible syntax. I 
> > > > > would strongly like to avoid repeating that.
> > > > I will double check this. Her Sutter's paper have this spelling and I 
> > > > believe that the Microsoft implementation is following the same 
> > > > spelling. The main difference is that the MSVC version does not have a 
> > > > type argument at this point but they do plan to add it as an optional 
> > > > argument. (They want to infer the pointee type when it is not 
> > > > provided.) The clang community do not want the inference, hence we made 
> > > > the type argument required. Always providing the type argument should 
> > > > be compatible with future versions of the MSVC implementation.
> > > I take this to mean that we're not implementing the same attribute as 
> > > MSVC is, and that worries me.
> > > 
> > > > Always providing the type argument should be compatible with future 
> > > > versions of the MSVC implementation.
> > > 
> > > The problem is that code written for MSVC (where the type argument is not 
> > > required) will not compile with Clang (where the type argument is 
> > > required), if I understand properly.
> > > 
> > > Generally speaking, when we implement an attribute from another vendor 
> > > namespace, we expect the attribute to have the same semantics as whoever 
> > > "owns" that vendor namespace. It's a bit trickier here because `gsl` 
> > > isn't really a vendor so much as a collective, so I don't know who is the 
> > > authority to turn to.
> > > 
> > > On a completely different note: would this attribute also make sense 
> > > within C with a C2x spelling?
> > I see, that is a valid concern. A followup patch makes the type argument 
> > optional so it will be fully compatible with MSVC.  I don't think it makes 
> > sense with C or at least I am not sure what would I annotate using these 
> > attributes in C code as the subjects are classes. I know that it is 
> > possible to simulate classes in C but I am not sure how well the analysis 
> > would work in such cases. 
> > 
> > Are you OK with making the argument optional in a followup patch or do you 
> > want us to cherry-pick that modification into this one?
> > I don't think it makes sense with C or at least I am not sure what would I 
> > annotate using these attributes in C code as the subjects are classes. I 
> > know that it is possible to simulate classes in C but I am not sure how 
> > well the analysis would work in such cases.
> 
> I couldn't think of a reason to expose this in C either, so I think the 
> current spelling is good as-is.
> 
> > Are you OK with making the argument optional in a followup patch or do you 
> > want us to cherry-pick that modification into this one?
> 
> I'd prefer the argument be optional in this patch.
The argument is now optional.



Comment at: clang/include/clang/Basic/AttrDocs.td:4164
+  let Content = [{
+When annotating a class ``O`` with ``[[gsl::Owner(T)]]``, then each function
+that returns cv-qualified ``T&`` or ``T*`` is assumed to return a

gribozavr wrote:
> Slightly better: "In a class annotated with ..., each function that returns 
> ... is assumed to ..."
> 
> However, the "is assumed" part throws me off. There's no assumption here -- 
> this is what this attribute means, intentionally, by design, no guessing 
> involved.
> 
> So how about this?
> 
> The attribute `[[gsl::Owner(T)]]` applies to structs and classes that own an 
> object of type `T`:
> 
> ```
> [[gsl::Owner(int)]] class IntOwner {
> private:
>   int value;
> public:
>   int *getInt() { return &value; }
>   long *getLong();
> };
> ```
> 
> In a class annotated like this each member function that returns `T&` or `T*` 
> returns a pointer/reference to the data owned by the class instance:
> 
> ```
> IntOwner int_owner;
> int *x = int_owner.getInt();
> // `x` points to memory owned by `int_owner`.
> ```
> 
> Therefore, that the lifetime of that data ends when ... For example:
> 
> ```
> int *x = IntOwner().getInt();
> // `x` points to memory owned by the temporary `IntOwner()`, which has been 
> destroyed now.
> 
> long *y = IntOwner().getLong();
> // Can't make any conclusion about validity of `y`.
> ```
> 
What I meant to express by "is assumed to" is that this attribute does not 
change what member functions do. E.g. if I had `int* f() { static int i; return 
&i; }`, then `f` would not return data owned by the class instance, even

[PATCH] D63954: Add lifetime categories attributes

2019-07-14 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 209750.
mgehre marked 23 inline comments as done.
mgehre added a comment.

- Don't crash when pretty-printing an Attribute with optional type argument
- Don't crash AST dump when Owner/Pointer has no Type argument
- gsl::Owner/gsl::Pointer: Make DerefType parameter optional
- Unify type and non-type attribute parsing; don't add OwnerAttr/PointerAttr 
twice
- Improve documentation


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/AST/ast-dump-attr.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/SemaCXX/attr-gsl-owner-pointer-parsing.cpp
  clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
  clang/utils/TableGen/ClangAttrEmitter.cpp

Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -303,6 +303,8 @@
 std::string getIsOmitted() const override {
   if (type == "IdentifierInfo *")
 return "!get" + getUpperName().str() + "()";
+  if (type == "TypeSourceInfo *")
+return "!get" + getUpperName().str() + "Loc()";
   if (type == "ParamIdx")
 return "!get" + getUpperName().str() + "().isValid()";
   return "false";
@@ -336,6 +338,8 @@
<< "  OS << \" \" << SA->get" << getUpperName()
<< "()->getName();\n";
   } else if (type == "TypeSourceInfo *") {
+if (isOptional())
+  OS << "if (SA->get" << getUpperName() << "Loc())";
 OS << "OS << \" \" << SA->get" << getUpperName()
<< "().getAsString();\n";
   } else if (type == "bool") {
Index: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -ast-dump %s | \
+// RUN: FileCheck --implicit-check-not OwnerAttr --implicit-check-not PointerAttr %s
+
+class [[gsl::Owner]] OwnerMissingParameter{};
+// CHECK: CXXRecordDecl {{.*}} OwnerMissingParameter
+// CHECK: OwnerAttr
+
+class [[gsl::Pointer]] PointerMissingParameter{};
+// CHECK: CXXRecordDecl {{.*}} PointerMissingParameter
+// CHECK: PointerAttr
+
+class [[gsl::Owner()]] OwnerWithEmptyParameterList{};
+// CHECK: CXXRecordDecl {{.*}} OwnerWithEmptyParameterList
+// CHECK: OwnerAttr {{.*}}
+
+class [[gsl::Pointer()]] PointerWithEmptyParameterList{};
+// CHECK: CXXRecordDecl {{.*}} PointerWithEmptyParameterList
+// CHECK: PointerAttr {{.*}}
+
+class [[gsl::Owner(int)]] AnOwner{};
+// CHECK: CXXRecordDecl {{.*}} AnOwner
+// CHECK: OwnerAttr {{.*}} int
+
+struct S;
+class [[gsl::Pointer(S)]] APointer{};
+// CHECK: CXXRecordDecl {{.*}} APointer
+// CHECK: PointerAttr {{.*}} S
+
+class [[gsl::Owner(int)]] [[gsl::Owner(int)]] DuplicateOwner{};
+// CHECK: CXXRecordDecl {{.*}} DuplicateOwner
+// CHECK: OwnerAttr {{.*}} int
+
+class [[gsl::Pointer(int)]] [[gsl::Pointer(int)]] DuplicatePointer{};
+// CHECK: CXXRecordDecl {{.*}} DuplicatePointer
+// CHECK: PointerAttr {{.*}} int
+
+class [[gsl::Owner(int)]] AddTheSameLater{};
+// CHECK: CXXRecordDecl {{.*}} AddTheSameLater
+// CHECK: OwnerAttr {{.*}} int
+
+class [[gsl::Owner(int)]] AddTheSameLater;
+// CHECK: CXXRecordDecl {{.*}} prev {{.*}} AddTheSameLater
+// CHECK: OwnerAttr {{.*}} int
Index: clang/test/SemaCXX/attr-gsl-owner-pointer-parsing.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer-parsing.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int [[gsl::Owner]] i;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+void [[gsl::Owner]] f();
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+[[gsl::Owner]] void f();
+// expected-warning@-1 {{'Owner' attribute only applies to classes}}
+
+struct S {
+};
+
+S [[gsl::Owner]] Instance;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+class [[gsl::Owner(7)]] OwnerDerefNoType{};
+// expected-error@-1 {{expected a type}}
+
+class [[gsl::Pointer("int")]] PointerDerefNoType{};
+// expected-error@-1 {{expected a type}}
+
+class [[gsl::Owner(int)]] [[gsl::Pointer(int)]] BothOwnerPointer{};
+// expected-error@-1 {{'Pointer' and 'Owner' attributes are not compatible}}
+// expected-note@-2 {{conflicting attribute is here}}
+
+class [[gsl::Owner(void)]] OwnerVoidDerefType{};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Owner'}}
+class [[gsl::Pointer(void)]] PointerVoidDerefType{};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Pointer'}}

[PATCH] D61749: [clang-tidy] initial version of readability-convert-member-functions-to-static

2019-07-16 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

Thank you for the review, Aaron!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61749/new/

https://reviews.llvm.org/D61749



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


[PATCH] D61749: [clang-tidy] initial version of readability-convert-member-functions-to-static

2019-07-16 Thread Matthias Gehre via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL366265: [clang-tidy] initial version of 
readability-convert-member-functions-to-static (authored by mgehre, committed 
by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D61749?vs=209360&id=210176#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61749/new/

https://reviews.llvm.org/D61749

Files:
  clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt
  
clang-tools-extra/trunk/clang-tidy/readability/ConvertMemberFunctionsToStatic.cpp
  
clang-tools-extra/trunk/clang-tidy/readability/ConvertMemberFunctionsToStatic.h
  clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp
  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/readability-convert-member-functions-to-static.rst
  
clang-tools-extra/trunk/test/clang-tidy/readability-convert-member-functions-to-static.cpp

Index: clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp
===
--- clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -13,6 +13,7 @@
 #include "BracesAroundStatementsCheck.h"
 #include "ConstReturnTypeCheck.h"
 #include "ContainerSizeEmptyCheck.h"
+#include "ConvertMemberFunctionsToStatic.h"
 #include "DeleteNullPointerCheck.h"
 #include "DeletedDefaultCheck.h"
 #include "ElseAfterReturnCheck.h"
@@ -57,6 +58,8 @@
 "readability-const-return-type");
 CheckFactories.registerCheck(
 "readability-container-size-empty");
+CheckFactories.registerCheck(
+"readability-convert-member-functions-to-static");
 CheckFactories.registerCheck(
 "readability-delete-null-pointer");
 CheckFactories.registerCheck(
Index: clang-tools-extra/trunk/clang-tidy/readability/ConvertMemberFunctionsToStatic.cpp
===
--- clang-tools-extra/trunk/clang-tidy/readability/ConvertMemberFunctionsToStatic.cpp
+++ clang-tools-extra/trunk/clang-tidy/readability/ConvertMemberFunctionsToStatic.cpp
@@ -0,0 +1,172 @@
+//===--- ConvertMemberFunctionsToStatic.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 "ConvertMemberFunctionsToStatic.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/SourceLocation.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+AST_MATCHER(CXXMethodDecl, isStatic) { return Node.isStatic(); }
+
+AST_MATCHER(CXXMethodDecl, hasTrivialBody) { return Node.hasTrivialBody(); }
+
+AST_MATCHER(CXXMethodDecl, isOverloadedOperator) {
+  return Node.isOverloadedOperator();
+}
+
+AST_MATCHER(CXXRecordDecl, hasAnyDependentBases) {
+  return Node.hasAnyDependentBases();
+}
+
+AST_MATCHER(CXXMethodDecl, isTemplate) {
+  return Node.getTemplatedKind() != FunctionDecl::TK_NonTemplate;
+}
+
+AST_MATCHER(CXXMethodDecl, isDependentContext) {
+  return Node.isDependentContext();
+}
+
+AST_MATCHER(CXXMethodDecl, isInsideMacroDefinition) {
+  const ASTContext &Ctxt = Finder->getASTContext();
+  return clang::Lexer::makeFileCharRange(
+ clang::CharSourceRange::getCharRange(
+ Node.getTypeSourceInfo()->getTypeLoc().getSourceRange()),
+ Ctxt.getSourceManager(), Ctxt.getLangOpts())
+  .isInvalid();
+}
+
+AST_MATCHER_P(CXXMethodDecl, hasCanonicalDecl,
+  ast_matchers::internal::Matcher, InnerMatcher) {
+  return InnerMatcher.matches(*Node.getCanonicalDecl(), Finder, Builder);
+}
+
+AST_MATCHER(CXXMethodDecl, usesThis) {
+  class FindUsageOfThis : public RecursiveASTVisitor {
+  public:
+bool Used = false;
+
+bool VisitCXXThisExpr(const CXXThisExpr *E) {
+  Used = true;
+  return false; // Stop traversal.
+}
+  } UsageOfThis;
+
+  // TraverseStmt does not modify its argument.
+  UsageOfThis.TraverseStmt(const_cast(Node.getBody()));
+
+  return UsageOfThis.Used;
+}
+
+void ConvertMemberFunctionsToStatic::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  cxxMethodDecl(
+  isDefinition(), isUserProvided(),
+  unless(anyOf(
+  isExpansionInSystemHeader(), isVirtual(), isStatic(),
+  hasTrivialBody(), isOverloadedOperator(), cxxConstructorDecl(),
+  cxxDestructorDecl(), cxxConver

[PATCH] D63954: Add lifetime categories attributes

2019-07-21 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

I think that I have addressed all open comments.




Comment at: clang/include/clang/Basic/AttrDocs.td:4164
+  let Content = [{
+When annotating a class ``O`` with ``[[gsl::Owner(T)]]``, then each function
+that returns cv-qualified ``T&`` or ``T*`` is assumed to return a

gribozavr wrote:
> mgehre wrote:
> > gribozavr wrote:
> > > Slightly better: "In a class annotated with ..., each function that 
> > > returns ... is assumed to ..."
> > > 
> > > However, the "is assumed" part throws me off. There's no assumption here 
> > > -- this is what this attribute means, intentionally, by design, no 
> > > guessing involved.
> > > 
> > > So how about this?
> > > 
> > > The attribute `[[gsl::Owner(T)]]` applies to structs and classes that own 
> > > an object of type `T`:
> > > 
> > > ```
> > > [[gsl::Owner(int)]] class IntOwner {
> > > private:
> > >   int value;
> > > public:
> > >   int *getInt() { return &value; }
> > >   long *getLong();
> > > };
> > > ```
> > > 
> > > In a class annotated like this each member function that returns `T&` or 
> > > `T*` returns a pointer/reference to the data owned by the class instance:
> > > 
> > > ```
> > > IntOwner int_owner;
> > > int *x = int_owner.getInt();
> > > // `x` points to memory owned by `int_owner`.
> > > ```
> > > 
> > > Therefore, that the lifetime of that data ends when ... For example:
> > > 
> > > ```
> > > int *x = IntOwner().getInt();
> > > // `x` points to memory owned by the temporary `IntOwner()`, which has 
> > > been destroyed now.
> > > 
> > > long *y = IntOwner().getLong();
> > > // Can't make any conclusion about validity of `y`.
> > > ```
> > > 
> > What I meant to express by "is assumed to" is that this attribute does not 
> > change what member functions do. E.g. if I had `int* f() { static int i; 
> > return &i; }`, then `f` would not return data owned by the class instance, 
> > even when annotating the class with `[[gsl::Owner(T)]]`. The point is that 
> > when member functions with return type `T*`/`T&` don't return data owned by 
> > the class instance, one should not add the `[[gsl::Owner(T)]]` attribute - 
> > or the analysis will produce wrong results. Here, we would warn if code 
> > uses the returned value of `f` after the class instances has been destroyed 
> > even though it would be safe.
> > 
> > There is a chicken and egg problem here. With this PR, we don't get any 
> > analysis yet, so providing examples of analysis results like "`x` points to 
> > memory owned by the temporary `IntOwner()`, which has been destroyed now." 
> > can be misleading. On the other hand, if we would just document the current 
> > meaning of the attribute, it would be nothing.
> > The implication "member function that returns `T&` or ` T*` returns a 
> > pointer/reference to the data owned by the class instance" is just one part 
> > of being an Owner. Herb's paper
> > uses this in more ways (e.g. output arguments, handling of move semantics, 
> > etc.), which we would implement incrementally together with the respective 
> > documentation update.
> > 
> > So I propose to keep the documentation basic for this PR and update the 
> > documentation with the upcoming PRs that add to the analysis. Would that be 
> > acceptable?
> > I added a note that the attribute is currently experimental and subject to 
> > change.
> > What I meant to express by "is assumed to" is that this attribute does not 
> > change what member functions do.
> 
> I don't think we should be making allowances for code that uses an attribute 
> to promise something and then does some other thing. In that model, there's 
> alignment between what code does and what attribute says.
> 
> And I mean of course the attribute does not change what the code does... that 
> must be obvious but you can mention it explicitly if you want.
> 
> > With this PR, we don't get any analysis yet
> 
> I don't think the analysis must be automatic in order to show what analysis 
> can be done. Attribute documentation needs enough examples to give people a 
> flavor of what the attribute does, and what possible benefits it can bring.
> 
> Documentation for the specific analysis that is actually done should go 
> elsewhere into Clang's documentation (if necessary).
I added an example to the documentation to show how the initial analysis will 
look like to give a feeling for what the attribute does.



Comment at: clang/lib/Sema/SemaDeclAttr.cpp:4546-4547
+
+  if (ParmType->isVoidType()) {
+S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) << "'void'" << 
AL;
+return;

gribozavr wrote:
> xazax.hun wrote:
> > aaron.ballman wrote:
> > > Is `void` really the only problematic type? What about incomplete types, 
> > > for instance?
> > I think incomplete types are fine. The only information we actually need 
> > here is the name the pointee types. E.g. for a `SomeOwner` 
> > which is annotated `Owner(Incomplete)`

[PATCH] D63954: Add lifetime categories attributes

2019-07-21 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 211008.
mgehre marked 6 inline comments as done.
mgehre added a comment.

- Disallow reference and array types as DerefType
- Add example to documentation.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/AST/ast-dump-attr.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/SemaCXX/attr-gsl-owner-pointer-parsing.cpp
  clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
  clang/utils/TableGen/ClangAttrEmitter.cpp

Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -303,6 +303,8 @@
 std::string getIsOmitted() const override {
   if (type == "IdentifierInfo *")
 return "!get" + getUpperName().str() + "()";
+  if (type == "TypeSourceInfo *")
+return "!get" + getUpperName().str() + "Loc()";
   if (type == "ParamIdx")
 return "!get" + getUpperName().str() + "().isValid()";
   return "false";
@@ -336,6 +338,8 @@
<< "  OS << \" \" << SA->get" << getUpperName()
<< "()->getName();\n";
   } else if (type == "TypeSourceInfo *") {
+if (isOptional())
+  OS << "if (SA->get" << getUpperName() << "Loc())";
 OS << "OS << \" \" << SA->get" << getUpperName()
<< "().getAsString();\n";
   } else if (type == "bool") {
Index: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -ast-dump %s | \
+// RUN: FileCheck --implicit-check-not OwnerAttr --implicit-check-not PointerAttr %s
+
+class [[gsl::Owner]] OwnerMissingParameter{};
+// CHECK: CXXRecordDecl {{.*}} OwnerMissingParameter
+// CHECK: OwnerAttr
+
+class [[gsl::Pointer]] PointerMissingParameter{};
+// CHECK: CXXRecordDecl {{.*}} PointerMissingParameter
+// CHECK: PointerAttr
+
+class [[gsl::Owner()]] OwnerWithEmptyParameterList{};
+// CHECK: CXXRecordDecl {{.*}} OwnerWithEmptyParameterList
+// CHECK: OwnerAttr {{.*}}
+
+class [[gsl::Pointer()]] PointerWithEmptyParameterList{};
+// CHECK: CXXRecordDecl {{.*}} PointerWithEmptyParameterList
+// CHECK: PointerAttr {{.*}}
+
+class [[gsl::Owner(int)]] AnOwner{};
+// CHECK: CXXRecordDecl {{.*}} AnOwner
+// CHECK: OwnerAttr {{.*}} int
+
+struct S;
+class [[gsl::Pointer(S)]] APointer{};
+// CHECK: CXXRecordDecl {{.*}} APointer
+// CHECK: PointerAttr {{.*}} S
+
+class [[gsl::Owner(int)]] [[gsl::Owner(int)]] DuplicateOwner{};
+// CHECK: CXXRecordDecl {{.*}} DuplicateOwner
+// CHECK: OwnerAttr {{.*}} int
+
+class [[gsl::Pointer(int)]] [[gsl::Pointer(int)]] DuplicatePointer{};
+// CHECK: CXXRecordDecl {{.*}} DuplicatePointer
+// CHECK: PointerAttr {{.*}} int
+
+class [[gsl::Owner(int)]] AddTheSameLater{};
+// CHECK: CXXRecordDecl {{.*}} AddTheSameLater
+// CHECK: OwnerAttr {{.*}} int
+
+class [[gsl::Owner(int)]] AddTheSameLater;
+// CHECK: CXXRecordDecl {{.*}} prev {{.*}} AddTheSameLater
+// CHECK: OwnerAttr {{.*}} int
Index: clang/test/SemaCXX/attr-gsl-owner-pointer-parsing.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer-parsing.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int [[gsl::Owner]] i;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+void [[gsl::Owner]] f();
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+[[gsl::Owner]] void f();
+// expected-warning@-1 {{'Owner' attribute only applies to classes}}
+
+struct S {
+};
+
+S [[gsl::Owner]] Instance;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+class [[gsl::Owner(7)]] OwnerDerefNoType{};
+// expected-error@-1 {{expected a type}}
+
+class [[gsl::Pointer("int")]] PointerDerefNoType{};
+// expected-error@-1 {{expected a type}}
+
+class [[gsl::Owner(int)]] [[gsl::Pointer(int)]] BothOwnerPointer{};
+// expected-error@-1 {{'Pointer' and 'Owner' attributes are not compatible}}
+// expected-note@-2 {{conflicting attribute is here}}
+
+class [[gsl::Owner(void)]] OwnerVoidDerefType{};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Owner'}}
+class [[gsl::Pointer(void)]] PointerVoidDerefType{};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Pointer'}}
+
+class [[gsl::Pointer(int)]] AddConflictLater{};
+class [[gsl::Owner(int)]] AddConflictLater;
+// expected-error@-1 {{'Owner' and 'Pointer' attributes are not compatible}}
+// expected-note@-3 {{conflicting attribute is here

[PATCH] D64448: gsl::Owner/gsl::Pointer: Add implicit annotations for some std types

2019-07-21 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

This should fix all open comments.




Comment at: clang/include/clang/Basic/AttrDocs.td:4167-4168
 pointer/reference to the data owned by ``O``. The owned data is assumed to end
-its lifetime once the owning object's lifetime ends.
+its lifetime once the owning object's lifetime ends. The argument ``T`` is
+optional.
 

rsmith wrote:
> ... and what does the attribute mean when the argument is omitted?
I added text that it is currently ignored. We will use the argument in future 
analysis, but already add parsing of it for forward compatibility.
Per Aaron's request, this part moved to the parent PR, D63954.



Comment at: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp:86
+
+// Test builtin annotation for std types.
+namespace std {

mgehre wrote:
> gribozavr wrote:
> > mgehre wrote:
> > > gribozavr wrote:
> > > > I feel like these tests would be better off in a separate file.
> > > > 
> > > > It would be also good to explain which exact library we are trying to 
> > > > imitate in this test. Different libraries use different coding patterns.
> > > This is imitating techniques from different libraries - all techniques 
> > > that this implementation supports.
> > > 
> > > To check if all techniques that this implementation supports are enough 
> > > for real standard library implementations,
> > > I use 
> > > https://github.com/mgehre/llvm-project/blob/lifetime-ci/lifetime-attr-test.cpp
> > >  against them. Various versions of libstdc++
> > > and libc++ passed. I will test MSVC standard library next. If they would 
> > > use a technique that this implementation does not support yet,
> > > I will add support for that and the corresponding test here.
> > > I might fix MSVC support (if needed) only in the following PR:
> > > This is imitating techniques from different libraries - all techniques 
> > > that this implementation supports.
> > 
> > Okay -- please add comments about each technique then (and ideally, which 
> > libraries use them). Right now (for me, who didn't write the patch), the 
> > test looks like it is testing inference for a bunch of types, not for a 
> > bunch of techniques -- the differences are subtle and non-obvious.
> Sure, I will add comments.
I moved the `std` tests to a different file.



Comment at: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp:93
 
-// Complete template
+// Attributes are added to a instantiatons of a complete template.
 template 

gribozavr wrote:
> Sorry, but what do you mean by a "concrete template"?
> 
> "Attributes are inferred on class template instantiations."
It says "complete", and I mean "not forward declared".


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64448/new/

https://reviews.llvm.org/D64448



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


[PATCH] D64448: gsl::Owner/gsl::Pointer: Add implicit annotations for some std types

2019-07-21 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 211009.
mgehre marked 12 inline comments as done.
mgehre added a comment.

- Merge branch 'lifetime-categories' into hardcode-lifetime-categories; Split 
test; Move test to AST dump; fix for comments;


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64448/new/

https://reviews.llvm.org/D64448

Files:
  clang/docs/LanguageExtensions.rst
  clang/include/clang/Basic/TokenKinds.def
  clang/include/clang/Basic/TypeTraits.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp

Index: clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
@@ -0,0 +1,126 @@
+// RUN: %clang_cc1 -ast-dump %s | \
+// RUN: FileCheck --implicit-check-not OwnerAttr --implicit-check-not PointerAttr %s
+
+// Test attribute inference for types in the standard library.
+namespace std {
+// Attributes are inferred for a (complete) class.
+class any {
+  // CHECK: CXXRecordDecl {{.*}} any
+  // CHECK: OwnerAttr {{.*}}
+};
+
+// Attributes are inferred for instantiations of a complete template.
+template 
+class vector {
+public:
+  class iterator {};
+  // CHECK: ClassTemplateDecl {{.*}} vector
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: CXXRecordDecl {{.*}} iterator
+  // CHECK: PointerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} vector
+  // CHECK: TemplateArgument type 'int'
+  // CHECK: OwnerAttr
+  // CHECK: CXXRecordDecl {{.*}} iterator
+  // CHECK: PointerAttr {{.*}}
+};
+static_assert(sizeof(vector), "");   // Force instantiation.
+static_assert(sizeof(vector::iterator), ""); // Force instantiation.
+
+// If std::container::iterator is a using declaration, attributes are inferred
+// for the underlying class.
+template 
+class __set_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __set_iterator
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __set_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class set {
+  // CHECK: ClassTemplateDecl {{.*}} set
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} set
+  // CHECK: OwnerAttr {{.*}}
+public:
+  using iterator = __set_iterator;
+};
+static_assert(sizeof(set::iterator), ""); // Force instantiation.
+
+// If std::container::iterator is a typedef, attributes are inferred for the
+// underlying class.
+template 
+class __map_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __map_iterator
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __map_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class map {
+  // CHECK: ClassTemplateDecl {{.*}} map
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} map
+  // CHECK: OwnerAttr {{.*}}
+public:
+  typedef __map_iterator iterator;
+};
+static_assert(sizeof(map::iterator), ""); // Force instantiation.
+
+// Inline namespaces are ignored when checking if
+// the class lives in the std namespace.
+inline namespace inlinens {
+template 
+class __unordered_map_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __unordered_map_iterator
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_map_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class unordered_map {
+  // CHECK: ClassTemplateDecl {{.*}} unordered_map
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_map
+  // CHECK: OwnerAttr {{.*}}
+public:
+  typedef __unordered_map_iterator iterator;
+};
+static_assert(sizeof(unordered_map::iterator), ""); // Force instantiation.
+} // namespace inlinens
+
+// std::list has an implicit gsl::Owner attribute,
+// but explicit attributes take precedence.
+template 
+class [[gsl::Pointer]] list{};
+// CHECK: ClassTemplateDecl {{.*}} list
+// CHECK: PointerAttr {{.*}}
+// CHECK: ClassTemplateSpecializationDecl {{.*}} list
+// CHECK: PointerAttr {{.*}}
+
+static_assert(sizeof(list), ""); // Force instantiation.
+
+// Forward declared template (Owner).
+template <
+class CharT,
+class Traits>
+class basic_regex;
+// CHECK: ClassTemplateDecl {{.*}} basic_regex
+// CHECK: OwnerAttr {{.*}}
+
+// Forward declared template (Pointer).
+template 
+class reference_wrapper;
+// CHECK: ClassTemplateDecl {{.*}} reference_wrapper
+// CHECK: PointerAttr {{.*}}
+
+class some_unknown_type;
+// CHECK: CXXRecordDecl {{.*}} some_unknown_type
+
+} // namespace std
+
+namespace user {
+// If a class is not in the std namespace, we don't infer the attributes.
+class any {
+};
+} // namespace user
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===
---

[PATCH] D64448: gsl::Owner/gsl::Pointer: Add implicit annotations for some std types

2019-07-21 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 211010.
mgehre added a comment.

- Remove type traits


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64448/new/

https://reviews.llvm.org/D64448

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp

Index: clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
@@ -0,0 +1,126 @@
+// RUN: %clang_cc1 -ast-dump %s | \
+// RUN: FileCheck --implicit-check-not OwnerAttr --implicit-check-not PointerAttr %s
+
+// Test attribute inference for types in the standard library.
+namespace std {
+// Attributes are inferred for a (complete) class.
+class any {
+  // CHECK: CXXRecordDecl {{.*}} any
+  // CHECK: OwnerAttr {{.*}}
+};
+
+// Attributes are inferred for instantiations of a complete template.
+template 
+class vector {
+public:
+  class iterator {};
+  // CHECK: ClassTemplateDecl {{.*}} vector
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: CXXRecordDecl {{.*}} iterator
+  // CHECK: PointerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} vector
+  // CHECK: TemplateArgument type 'int'
+  // CHECK: OwnerAttr
+  // CHECK: CXXRecordDecl {{.*}} iterator
+  // CHECK: PointerAttr {{.*}}
+};
+static_assert(sizeof(vector), "");   // Force instantiation.
+static_assert(sizeof(vector::iterator), ""); // Force instantiation.
+
+// If std::container::iterator is a using declaration, attributes are inferred
+// for the underlying class.
+template 
+class __set_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __set_iterator
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __set_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class set {
+  // CHECK: ClassTemplateDecl {{.*}} set
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} set
+  // CHECK: OwnerAttr {{.*}}
+public:
+  using iterator = __set_iterator;
+};
+static_assert(sizeof(set::iterator), ""); // Force instantiation.
+
+// If std::container::iterator is a typedef, attributes are inferred for the
+// underlying class.
+template 
+class __map_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __map_iterator
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __map_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class map {
+  // CHECK: ClassTemplateDecl {{.*}} map
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} map
+  // CHECK: OwnerAttr {{.*}}
+public:
+  typedef __map_iterator iterator;
+};
+static_assert(sizeof(map::iterator), ""); // Force instantiation.
+
+// Inline namespaces are ignored when checking if
+// the class lives in the std namespace.
+inline namespace inlinens {
+template 
+class __unordered_map_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __unordered_map_iterator
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_map_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class unordered_map {
+  // CHECK: ClassTemplateDecl {{.*}} unordered_map
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_map
+  // CHECK: OwnerAttr {{.*}}
+public:
+  typedef __unordered_map_iterator iterator;
+};
+static_assert(sizeof(unordered_map::iterator), ""); // Force instantiation.
+} // namespace inlinens
+
+// std::list has an implicit gsl::Owner attribute,
+// but explicit attributes take precedence.
+template 
+class [[gsl::Pointer]] list{};
+// CHECK: ClassTemplateDecl {{.*}} list
+// CHECK: PointerAttr {{.*}}
+// CHECK: ClassTemplateSpecializationDecl {{.*}} list
+// CHECK: PointerAttr {{.*}}
+
+static_assert(sizeof(list), ""); // Force instantiation.
+
+// Forward declared template (Owner).
+template <
+class CharT,
+class Traits>
+class basic_regex;
+// CHECK: ClassTemplateDecl {{.*}} basic_regex
+// CHECK: OwnerAttr {{.*}}
+
+// Forward declared template (Pointer).
+template 
+class reference_wrapper;
+// CHECK: ClassTemplateDecl {{.*}} reference_wrapper
+// CHECK: PointerAttr {{.*}}
+
+class some_unknown_type;
+// CHECK: CXXRecordDecl {{.*}} some_unknown_type
+
+} // namespace std
+
+namespace user {
+// If a class is not in the std namespace, we don't infer the attributes.
+class any {
+};
+} // namespace user
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -699,6 +699,7 @@
   }
 
   SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
+  SemaRef.addDefaultGslPointerAttribute(Typedef);
 
   Typedef->setAccess(D->getAccess());
 
Index: clang/lib/Sema/Sem

[PATCH] D64448: gsl::Owner/gsl::Pointer: Add implicit annotations for some std types

2019-07-21 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

In D64448#1595017 , @lebedev.ri wrote:

> Just passing-by thought:
>  These attributes that are being added implicitly, it will be possible to 
> differentiate
>  whether an attribute was actually present in the code, or was added 
> implicitly,
>  say for clang-tidy check purposes?
>  Is there some 'implicit' bit on these, or they have a location not in the 
> source buffer?


Thanks for the question! The implicitly added attributes have an invalid source 
location.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64448/new/

https://reviews.llvm.org/D64448



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


[PATCH] D15032: [clang-tidy] new checker cppcoreguidelines-pro-lifetime

2019-07-21 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre abandoned this revision.
mgehre added a comment.
Herald added subscribers: wuzish, dmgreen.

Upstreaming of this checker will happen with D63954 
 and following revisions.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D15032/new/

https://reviews.llvm.org/D15032



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


[PATCH] D63954: Add lifetime categories attributes

2019-07-23 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked 2 inline comments as done.
mgehre added inline comments.



Comment at: clang/include/clang/Basic/AttrDocs.td:4167
+
+The attribute ``[[gsl::Owner(T)]]`` applies to structs and classes that own an
+object of type ``T``:

aaron.ballman wrote:
> Do either of these attributes make sense on a union type? If so, might be 
> worth mentioning unions here and below. If not, would it be worth diagnosing 
> on a union?
Good catch! I added diagnostics and a test.



Comment at: clang/include/clang/Basic/DiagnosticSemaKinds.td:2516
   "%0 and %1 attributes are not compatible">;
+def err_attribute_invalid_argument : Error<
+  "%0 is an invalid argument to attribute %1">;

aaron.ballman wrote:
> Can you combine this one with `err_attribute_argument_vec_type_hint`?
I'm not sure: vec_type_hint reads `"invalid attribute argument %0 - expecting a 
vector or vectorizable scalar type"` and here `""%0 is an invalid argument to 
attribute %1"`, i.e. one is positive ("expecting ...") and the other is 
negative ("%0 is an invalid argument").

I don't know how to describe "not void, not reference, not array type" in terms 
of "expecting ...", and I think that we should keep "expecting a vector or 
vectorizable scalar type" on the  VecTypeHint attribute diagnostic.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954



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


[PATCH] D63954: Add lifetime categories attributes

2019-07-23 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 211370.
mgehre marked 4 inline comments as done.
mgehre added a comment.

- Diagnose unions; improve other diagnostics; fix all comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/ParsedAttr.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/AST/ast-dump-attr.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/SemaCXX/attr-gsl-owner-pointer-parsing.cpp
  clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
  clang/utils/TableGen/ClangAttrEmitter.cpp

Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -303,6 +303,8 @@
 std::string getIsOmitted() const override {
   if (type == "IdentifierInfo *")
 return "!get" + getUpperName().str() + "()";
+  if (type == "TypeSourceInfo *")
+return "!get" + getUpperName().str() + "Loc()";
   if (type == "ParamIdx")
 return "!get" + getUpperName().str() + "().isValid()";
   return "false";
@@ -336,6 +338,8 @@
<< "  OS << \" \" << SA->get" << getUpperName()
<< "()->getName();\n";
   } else if (type == "TypeSourceInfo *") {
+if (isOptional())
+  OS << "if (SA->get" << getUpperName() << "Loc())";
 OS << "OS << \" \" << SA->get" << getUpperName()
<< "().getAsString();\n";
   } else if (type == "bool") {
Index: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -ast-dump %s | \
+// RUN: FileCheck --implicit-check-not OwnerAttr --implicit-check-not PointerAttr %s
+
+class [[gsl::Owner]] OwnerMissingParameter{};
+// CHECK: CXXRecordDecl {{.*}} OwnerMissingParameter
+// CHECK: OwnerAttr
+
+class [[gsl::Pointer]] PointerMissingParameter{};
+// CHECK: CXXRecordDecl {{.*}} PointerMissingParameter
+// CHECK: PointerAttr
+
+class [[gsl::Owner()]] OwnerWithEmptyParameterList{};
+// CHECK: CXXRecordDecl {{.*}} OwnerWithEmptyParameterList
+// CHECK: OwnerAttr {{.*}}
+
+class [[gsl::Pointer()]] PointerWithEmptyParameterList{};
+// CHECK: CXXRecordDecl {{.*}} PointerWithEmptyParameterList
+// CHECK: PointerAttr {{.*}}
+
+class [[gsl::Owner(int)]] AnOwner{};
+// CHECK: CXXRecordDecl {{.*}} AnOwner
+// CHECK: OwnerAttr {{.*}} int
+
+struct S;
+class [[gsl::Pointer(S)]] APointer{};
+// CHECK: CXXRecordDecl {{.*}} APointer
+// CHECK: PointerAttr {{.*}} S
+
+class [[gsl::Owner(int)]] [[gsl::Owner(int)]] DuplicateOwner{};
+// CHECK: CXXRecordDecl {{.*}} DuplicateOwner
+// CHECK: OwnerAttr {{.*}} int
+
+class [[gsl::Pointer(int)]] [[gsl::Pointer(int)]] DuplicatePointer{};
+// CHECK: CXXRecordDecl {{.*}} DuplicatePointer
+// CHECK: PointerAttr {{.*}} int
+
+class [[gsl::Owner(int)]] AddTheSameLater{};
+// CHECK: CXXRecordDecl {{.*}} AddTheSameLater
+// CHECK: OwnerAttr {{.*}} int
+
+class [[gsl::Owner(int)]] AddTheSameLater;
+// CHECK: CXXRecordDecl {{.*}} prev {{.*}} AddTheSameLater
+// CHECK: OwnerAttr {{.*}} int
Index: clang/test/SemaCXX/attr-gsl-owner-pointer-parsing.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer-parsing.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int [[gsl::Owner]] i;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+void [[gsl::Owner]] f();
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+[[gsl::Owner]] void f();
+// expected-warning@-1 {{'Owner' attribute only applies to classes}}
+
+struct S {
+};
+
+S [[gsl::Owner]] Instance;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+class [[gsl::Owner(7)]] OwnerDerefNoType{};
+// expected-error@-1 {{expected a type}}
+
+class [[gsl::Pointer("int")]] PointerDerefNoType{};
+// expected-error@-1 {{expected a type}}
+
+class [[gsl::Owner(int)]] [[gsl::Pointer(int)]] BothOwnerPointer{};
+// expected-error@-1 {{'Pointer' and 'Owner' attributes are not compatible}}
+// expected-note@-2 {{conflicting attribute is here}}
+
+class [[gsl::Owner(void)]] OwnerVoidDerefType{};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Owner'}}
+class [[gsl::Pointer(void)]] PointerVoidDerefType{};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Pointer'}}
+
+class [[gsl::Pointer(int)]] AddConflictLater{};
+class [[gsl::Owner(int)]] AddConflictLater;
+// expected-error@-1 {{'Owner' and 'Pointer' attributes are not compatible}}
+// expected-note@-3 {{conflict

[PATCH] D63954: Add lifetime categories attributes

2019-07-24 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 211600.
mgehre marked an inline comment as done.
mgehre added a comment.

- Fix all comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/AST/ast-dump-attr.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
  clang/test/SemaOpenCL/invalid-kernel-attrs.cl
  clang/utils/TableGen/ClangAttrEmitter.cpp

Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -303,6 +303,8 @@
 std::string getIsOmitted() const override {
   if (type == "IdentifierInfo *")
 return "!get" + getUpperName().str() + "()";
+  if (type == "TypeSourceInfo *")
+return "!get" + getUpperName().str() + "Loc()";
   if (type == "ParamIdx")
 return "!get" + getUpperName().str() + "().isValid()";
   return "false";
@@ -336,6 +338,8 @@
<< "  OS << \" \" << SA->get" << getUpperName()
<< "()->getName();\n";
   } else if (type == "TypeSourceInfo *") {
+if (isOptional())
+  OS << "if (SA->get" << getUpperName() << "Loc())";
 OS << "OS << \" \" << SA->get" << getUpperName()
<< "().getAsString();\n";
   } else if (type == "bool") {
Index: clang/test/SemaOpenCL/invalid-kernel-attrs.cl
===
--- clang/test/SemaOpenCL/invalid-kernel-attrs.cl
+++ clang/test/SemaOpenCL/invalid-kernel-attrs.cl
@@ -1,12 +1,12 @@
-// RUN: %clang_cc1 -verify %s 
+// RUN: %clang_cc1 -verify %s
 
 kernel __attribute__((vec_type_hint)) void kernel1() {} //expected-error{{'vec_type_hint' attribute takes one argument}}
 
 kernel __attribute__((vec_type_hint(not_type))) void kernel2() {} //expected-error{{unknown type name 'not_type'}}
 
-kernel __attribute__((vec_type_hint(void))) void kernel3() {} //expected-error{{invalid attribute argument 'void' - expecting a vector or vectorizable scalar type}}
+kernel __attribute__((vec_type_hint(void))) void kernel3() {} //expected-error{{a non-vector or non-vectorizable scalar type is an invalid argument to attribute 'vec_type_hint'}}
 
-kernel __attribute__((vec_type_hint(bool))) void kernel4() {} //expected-error{{invalid attribute argument 'bool' - expecting a vector or vectorizable scalar type}}
+kernel __attribute__((vec_type_hint(bool))) void kernel4() {} //expected-error{{a non-vector or non-vectorizable scalar type is an invalid argument to attribute 'vec_type_hint'}}
 
 kernel __attribute__((vec_type_hint(int))) __attribute__((vec_type_hint(float))) void kernel5() {} //expected-warning{{attribute 'vec_type_hint' is already applied with different parameters}}
 
Index: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
@@ -0,0 +1,107 @@
+// RUN: %clang_cc1 -verify -ast-dump %s | \
+// RUN: FileCheck --implicit-check-not OwnerAttr --implicit-check-not PointerAttr %s
+
+int [[gsl::Owner]] i;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+void [[gsl::Owner]] f();
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+[[gsl::Owner]] void f();
+// expected-warning@-1 {{'Owner' attribute only applies to structs}}
+
+union [[gsl::Owner(int)]] Union{};
+// expected-warning@-1 {{'Owner' attribute only applies to structs}}
+
+struct S {
+};
+
+S [[gsl::Owner]] Instance;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+class [[gsl::Owner(7)]] OwnerDerefNoType{};
+// expected-error@-1 {{expected a type}}
+
+class [[gsl::Pointer("int")]] PointerDerefNoType{};
+// expected-error@-1 {{expected a type}}
+
+class [[gsl::Owner(int)]] [[gsl::Pointer(int)]] BothOwnerPointer{};
+// expected-error@-1 {{'Pointer' and 'Owner' attributes are not compatible}}
+// expected-note@-2 {{conflicting attribute is here}}
+// CHECK: CXXRecordDecl {{.*}} BothOwnerPointer
+// CHECK: OwnerAttr {{.*}} int
+
+class [[gsl::Owner(void)]] OwnerVoidDerefType{};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Owner'}}
+class [[gsl::Pointer(void)]] PointerVoidDerefType{};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Pointer'}}
+
+class [[gsl::Pointer(int)]] AddConflictLater{};
+// CHECK: CXXRecordDecl {{.*}} AddConflictLater
+// CHECK: PointerAttr {{.*}} int
+class [[gsl::Owner(int)]] AddConflictLater;
+// expected-error@-1 {{'Owner' and 'Pointer' attributes are not compatible}}
+// expected-note@-5 {{conf

[PATCH] D63954: Add lifetime categories attributes

2019-07-24 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked 9 inline comments as done.
mgehre added inline comments.



Comment at: clang/test/SemaCXX/attr-gsl-owner-pointer-parsing.cpp:2
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int [[gsl::Owner]] i;

aaron.ballman wrote:
> This file tests part of parsing and part of Sema somewhat interchangeably. 
> I'm not strictly opposed to it being that way, but it would be a bit cleaner 
> to have the parsing tests in the Parser directory and the rest in SemaCXX 
> (that also reduces the confusion from the file name).
I had split the tests into two files due to a misconception that the ast-dump 
would not work when errors are emitted. It actually does work, and so I 
recombined the test cases.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954



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


[PATCH] D63954: Add lifetime categories attributes

2019-07-25 Thread Matthias Gehre via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL367040: Add lifetime categories attributes (authored by 
mgehre, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D63954?vs=211600&id=211792#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954

Files:
  cfe/trunk/include/clang/Basic/Attr.td
  cfe/trunk/include/clang/Basic/AttrDocs.td
  cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
  cfe/trunk/lib/Parse/ParseDecl.cpp
  cfe/trunk/lib/Sema/SemaDeclAttr.cpp
  cfe/trunk/test/AST/ast-dump-attr.cpp
  cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
  cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer.cpp
  cfe/trunk/test/SemaOpenCL/invalid-kernel-attrs.cl
  cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp

Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
===
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2519,6 +2519,9 @@
   "'NSObject' attribute is for pointer types only">;
 def err_attributes_are_not_compatible : Error<
   "%0 and %1 attributes are not compatible">;
+def err_attribute_invalid_argument : Error<
+  "%select{'void'|a reference type|an array type|a non-vector or "
+  "non-vectorizable scalar type}0 is an invalid argument to attribute %1">;
 def err_attribute_wrong_number_arguments : Error<
   "%0 attribute %plural{0:takes no arguments|1:takes one argument|"
   ":requires exactly %1 arguments}1">;
@@ -2567,8 +2570,6 @@
 def err_init_priority_object_attr : Error<
   "can only use 'init_priority' attribute on file-scope definitions "
   "of objects of class type">;
-def err_attribute_argument_vec_type_hint : Error<
-  "invalid attribute argument %0 - expecting a vector or vectorizable scalar type">;
 def err_attribute_argument_out_of_bounds : Error<
   "%0 attribute parameter %1 is out of bounds">;
 def err_attribute_only_once_per_parameter : Error<
Index: cfe/trunk/include/clang/Basic/AttrDocs.td
===
--- cfe/trunk/include/clang/Basic/AttrDocs.td
+++ cfe/trunk/include/clang/Basic/AttrDocs.td
@@ -4230,3 +4230,71 @@
 the initializer on host side.
   }];
 }
+
+def LifetimeOwnerDocs : Documentation {
+  let Category = DocCatDecl;
+  let Content = [{
+.. Note:: This attribute is experimental and its effect on analysis is subject to change in
+  a future version of clang.
+
+The attribute ``[[gsl::Owner(T)]]`` applies to structs and classes that own an
+object of type ``T``:
+
+.. code-block:: c++
+
+  class [[gsl::Owner(int)]] IntOwner {
+  private:
+int value;
+  public:
+int *getInt() { return &value; }
+  };
+
+The argument ``T`` is optional and currently ignored.
+This attribute may be used by analysis tools and has no effect on code
+generation.
+
+See Pointer_ for an example.
+}];
+}
+
+def LifetimePointerDocs : Documentation {
+  let Category = DocCatDecl;
+  let Content = [{
+.. Note:: This attribute is experimental and its effect on analysis is subject to change in
+  a future version of clang.
+
+The attribute ``[[gsl::Pointer(T)]]`` applies to structs and classes that behave
+like pointers to an object of type ``T``:
+
+.. code-block:: c++
+
+  class [[gsl::Pointer(int)]] IntPointer {
+  private:
+int *valuePointer;
+  public:
+int *getInt() { return &valuePointer; }
+  };
+
+The argument ``T`` is optional and currently ignored.
+This attribute may be used by analysis tools and has no effect on code
+generation.
+
+Example:
+When constructing an instance of a class annotated like this (a Pointer) from
+an instance of a class annotated with ``[[gsl::Owner]]`` (an Owner),
+then the analysis will consider the Pointer to point inside the Owner.
+When the Owner's lifetime ends, it will consider the Pointer to be dangling.
+
+.. code-block:: c++
+
+  int f() {
+IntPointer P;
+if (true) {
+  IntOwner O(7);
+  P = IntPointer(O); // P "points into" O
+} // P is dangling
+return P.get(); // error: Using a dangling Pointer.
+  }
+
+}];
+}
Index: cfe/trunk/include/clang/Basic/Attr.td
===
--- cfe/trunk/include/clang/Basic/Attr.td
+++ cfe/trunk/include/clang/Basic/Attr.td
@@ -2796,6 +2796,20 @@
   let Documentation = [TypeTagForDatatypeDocs];
 }
 
+def Owner : InheritableAttr {
+  let Spellings = [CXX11<"gsl", "Owner">];
+  let Subjects = SubjectList<[Struct]>;
+  let Args = [TypeArgument<"DerefType", /*opt=*/1>];
+  let Documentation = [LifetimeOwnerDocs];
+}
+
+def Pointer : InheritableAttr {
+  let Spellings = [CXX11<"gsl", "Pointer">];
+  let Subjects = SubjectList<[Struct]>;
+  let Args = [TypeArgument<"DerefType", /*opt=*/1>];
+  let Documentation = [LifetimePointerDocs];
+}

[PATCH] D63954: Add lifetime categories attributes

2019-07-25 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

Thank you very much for dedicating your time for the review. It improved the 
code a lot!


Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954



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


[PATCH] D65127: Even more warnings utilizing gsl::Owner/gsl::Pointer annotations

2019-07-30 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added inline comments.



Comment at: clang/lib/Sema/SemaInit.cpp:6581
+if (!Callee->getIdentifier()) {
+  auto OO = Callee->getOverloadedOperator();
+  return OO == OverloadedOperatorKind::OO_Subscript ||

xazax.hun wrote:
> If we want to relax the warnings to give more results we could extend the 
> checking of these overloaded operators for annotated types. But this would 
> imply that the user need to have the expected semantics for those types and 
> can only suppress false positives by removing some gsl:::owner/poinnter 
> annotations.
I see those options:
- Either gsl::Owner implies some specific form of those operators (and if that 
does not hold for a class, then one should not annotate it with gsl::Owner)
- or gsl::Owner only implies some specific behavior for the "gsl::Pointer 
constructed from gsl::Owner" case and everything else requires additional 
annotation
I expect that we will experiment a bit in the future to see what works well for 
real-world code.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D65127/new/

https://reviews.llvm.org/D65127



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


[PATCH] D63954: Add lifetime categories attributes

2019-07-30 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

I will include your latest comments into D64448 



Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954



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


[PATCH] D64448: gsl::Owner/gsl::Pointer: Add implicit annotations for some std types

2019-07-30 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 212439.
mgehre marked 6 inline comments as done.
mgehre added a comment.

- Fix comments
- Add Pointer via typedef on ClassTemplateDecl


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64448/new/

https://reviews.llvm.org/D64448

Files:
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp

Index: clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
@@ -0,0 +1,129 @@
+// RUN: %clang_cc1 -ast-dump %s | \
+// RUN: FileCheck --implicit-check-not OwnerAttr --implicit-check-not PointerAttr %s
+
+// Test attribute inference for types in the standard library.
+namespace std {
+// Attributes are inferred for a (complete) class.
+class any {
+  // CHECK: CXXRecordDecl {{.*}} any
+  // CHECK: OwnerAttr {{.*}}
+};
+
+// Attributes are inferred for instantiations of a complete template.
+template 
+class vector {
+public:
+  class iterator {};
+  // CHECK: ClassTemplateDecl {{.*}} vector
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: CXXRecordDecl {{.*}} iterator
+  // CHECK: PointerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} vector
+  // CHECK: TemplateArgument type 'int'
+  // CHECK: OwnerAttr
+  // CHECK: CXXRecordDecl {{.*}} iterator
+  // CHECK: PointerAttr {{.*}}
+};
+static_assert(sizeof(vector), "");   // Force instantiation.
+static_assert(sizeof(vector::iterator), ""); // Force instantiation.
+
+// If std::container::iterator is a using declaration, attributes are inferred
+// for the underlying class.
+template 
+class __set_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __set_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __set_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class set {
+  // CHECK: ClassTemplateDecl {{.*}} set
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} set
+  // CHECK: OwnerAttr {{.*}}
+public:
+  using iterator = __set_iterator;
+};
+static_assert(sizeof(set::iterator), ""); // Force instantiation.
+
+// If std::container::iterator is a typedef, attributes are inferred for the
+// underlying class.
+template 
+class __map_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __map_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __map_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class map {
+  // CHECK: ClassTemplateDecl {{.*}} map
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} map
+  // CHECK: OwnerAttr {{.*}}
+public:
+  typedef __map_iterator iterator;
+};
+static_assert(sizeof(map::iterator), ""); // Force instantiation.
+
+// Inline namespaces are ignored when checking if
+// the class lives in the std namespace.
+inline namespace inlinens {
+template 
+class __unordered_map_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __unordered_map_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_map_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class unordered_map {
+  // CHECK: ClassTemplateDecl {{.*}} unordered_map
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_map
+  // CHECK: OwnerAttr {{.*}}
+public:
+  typedef __unordered_map_iterator iterator;
+};
+static_assert(sizeof(unordered_map::iterator), ""); // Force instantiation.
+} // namespace inlinens
+
+// std::list has an implicit gsl::Owner attribute,
+// but explicit attributes take precedence.
+template 
+class [[gsl::Pointer]] list{};
+// CHECK: ClassTemplateDecl {{.*}} list
+// CHECK: PointerAttr {{.*}}
+// CHECK: ClassTemplateSpecializationDecl {{.*}} list
+// CHECK: PointerAttr {{.*}}
+
+static_assert(sizeof(list), ""); // Force instantiation.
+
+// Forward declared template (Owner).
+template <
+class CharT,
+class Traits>
+class basic_regex;
+// CHECK: ClassTemplateDecl {{.*}} basic_regex
+// CHECK: OwnerAttr {{.*}}
+
+// Forward declared template (Pointer).
+template 
+class reference_wrapper;
+// CHECK: ClassTemplateDecl {{.*}} reference_wrapper
+// CHECK: PointerAttr {{.*}}
+
+class some_unknown_type;
+// CHECK: CXXRecordDecl {{.*}} some_unknown_type
+
+} // namespace std
+
+namespace user {
+// If a class is not in the std namespace, we don't infer the attributes.
+class any {
+};
+} // namespace user
Index: clang/lib/Sema/SemaTemplate.cpp
===
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -1690,6 +1690,7 @@
 mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
 
   Ad

[PATCH] D64448: gsl::Owner/gsl::Pointer: Add implicit annotations for some std types

2019-07-30 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added inline comments.



Comment at: clang/include/clang/Sema/Sema.h:6097
+
+  /// Add [[gsl::Owner]] and [[gsl::Pointer]] attributes for std:: types.
+  void addDefaultGslPointerAttribute(TypedefNameDecl *TD);

gribozavr wrote:
> It seems like this function does not add gsl::Owner.
Fixed comment



Comment at: clang/lib/Sema/SemaTemplate.cpp:1689
   AddPushedVisibilityAttribute(NewClass);
+  addDefaultGslOwnerPointerAttribute(NewClass);
 

gribozavr wrote:
> It shouldn't be necessary to perform inference here, instead, the attributes 
> should be instantiated, see `instantiateDependentAlignedAttr` in 
> SemaTemplateInstantiateDecl.cpp for an example.
From what I understand, here the attribute is put on the `ClassTemplateDecl`. 
Without this, there would be no attribute to instantiate from?
The instantiation of OwnerAttr/PointerAttr is auto-generated into 
instantiateTemplateAttribute() in 
`build/tools/clang/include/clang/Sema/AttrTemplateInstantiate.inc`.



Comment at: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp:702
   SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
+  SemaRef.addDefaultGslPointerAttribute(Typedef);
 

gribozavr wrote:
> Ditto, should not be necessary to perform inference here.
I'll move this to already act on the typedef in the ClassTemplateDecl (instead 
of the instantiation here).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64448/new/

https://reviews.llvm.org/D64448



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


[PATCH] D64448: gsl::Owner/gsl::Pointer: Add implicit annotations for some std types

2019-07-30 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 212441.
mgehre added a comment.

- Add missing check


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64448/new/

https://reviews.llvm.org/D64448

Files:
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp

Index: clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
@@ -0,0 +1,129 @@
+// RUN: %clang_cc1 -ast-dump %s | \
+// RUN: FileCheck --implicit-check-not OwnerAttr --implicit-check-not PointerAttr %s
+
+// Test attribute inference for types in the standard library.
+namespace std {
+// Attributes are inferred for a (complete) class.
+class any {
+  // CHECK: CXXRecordDecl {{.*}} any
+  // CHECK: OwnerAttr {{.*}}
+};
+
+// Attributes are inferred for instantiations of a complete template.
+template 
+class vector {
+public:
+  class iterator {};
+  // CHECK: ClassTemplateDecl {{.*}} vector
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: CXXRecordDecl {{.*}} iterator
+  // CHECK: PointerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} vector
+  // CHECK: TemplateArgument type 'int'
+  // CHECK: OwnerAttr
+  // CHECK: CXXRecordDecl {{.*}} iterator
+  // CHECK: PointerAttr {{.*}}
+};
+static_assert(sizeof(vector), "");   // Force instantiation.
+static_assert(sizeof(vector::iterator), ""); // Force instantiation.
+
+// If std::container::iterator is a using declaration, attributes are inferred
+// for the underlying class.
+template 
+class __set_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __set_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __set_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class set {
+  // CHECK: ClassTemplateDecl {{.*}} set
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} set
+  // CHECK: OwnerAttr {{.*}}
+public:
+  using iterator = __set_iterator;
+};
+static_assert(sizeof(set::iterator), ""); // Force instantiation.
+
+// If std::container::iterator is a typedef, attributes are inferred for the
+// underlying class.
+template 
+class __map_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __map_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __map_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class map {
+  // CHECK: ClassTemplateDecl {{.*}} map
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} map
+  // CHECK: OwnerAttr {{.*}}
+public:
+  typedef __map_iterator iterator;
+};
+static_assert(sizeof(map::iterator), ""); // Force instantiation.
+
+// Inline namespaces are ignored when checking if
+// the class lives in the std namespace.
+inline namespace inlinens {
+template 
+class __unordered_map_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __unordered_map_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_map_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class unordered_map {
+  // CHECK: ClassTemplateDecl {{.*}} unordered_map
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_map
+  // CHECK: OwnerAttr {{.*}}
+public:
+  typedef __unordered_map_iterator iterator;
+};
+static_assert(sizeof(unordered_map::iterator), ""); // Force instantiation.
+} // namespace inlinens
+
+// std::list has an implicit gsl::Owner attribute,
+// but explicit attributes take precedence.
+template 
+class [[gsl::Pointer]] list{};
+// CHECK: ClassTemplateDecl {{.*}} list
+// CHECK: PointerAttr {{.*}}
+// CHECK: ClassTemplateSpecializationDecl {{.*}} list
+// CHECK: PointerAttr {{.*}}
+
+static_assert(sizeof(list), ""); // Force instantiation.
+
+// Forward declared template (Owner).
+template <
+class CharT,
+class Traits>
+class basic_regex;
+// CHECK: ClassTemplateDecl {{.*}} basic_regex
+// CHECK: OwnerAttr {{.*}}
+
+// Forward declared template (Pointer).
+template 
+class reference_wrapper;
+// CHECK: ClassTemplateDecl {{.*}} reference_wrapper
+// CHECK: PointerAttr {{.*}}
+
+class some_unknown_type;
+// CHECK: CXXRecordDecl {{.*}} some_unknown_type
+
+} // namespace std
+
+namespace user {
+// If a class is not in the std namespace, we don't infer the attributes.
+class any {
+};
+} // namespace user
Index: clang/lib/Sema/SemaTemplate.cpp
===
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -1690,6 +1690,7 @@
 mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
 
   AddPushedVisibilityAttribute(NewClass);
+  addDefaultGslOwnerPointerAttribute(NewClas

[PATCH] D64448: gsl::Owner/gsl::Pointer: Add implicit annotations for some std types

2019-07-30 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 212446.
mgehre added a comment.

- Fix crash


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64448/new/

https://reviews.llvm.org/D64448

Files:
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp

Index: clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
@@ -0,0 +1,129 @@
+// RUN: %clang_cc1 -ast-dump %s | \
+// RUN: FileCheck --implicit-check-not OwnerAttr --implicit-check-not PointerAttr %s
+
+// Test attribute inference for types in the standard library.
+namespace std {
+// Attributes are inferred for a (complete) class.
+class any {
+  // CHECK: CXXRecordDecl {{.*}} any
+  // CHECK: OwnerAttr {{.*}}
+};
+
+// Attributes are inferred for instantiations of a complete template.
+template 
+class vector {
+public:
+  class iterator {};
+  // CHECK: ClassTemplateDecl {{.*}} vector
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: CXXRecordDecl {{.*}} iterator
+  // CHECK: PointerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} vector
+  // CHECK: TemplateArgument type 'int'
+  // CHECK: OwnerAttr
+  // CHECK: CXXRecordDecl {{.*}} iterator
+  // CHECK: PointerAttr {{.*}}
+};
+static_assert(sizeof(vector), "");   // Force instantiation.
+static_assert(sizeof(vector::iterator), ""); // Force instantiation.
+
+// If std::container::iterator is a using declaration, attributes are inferred
+// for the underlying class.
+template 
+class __set_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __set_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __set_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class set {
+  // CHECK: ClassTemplateDecl {{.*}} set
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} set
+  // CHECK: OwnerAttr {{.*}}
+public:
+  using iterator = __set_iterator;
+};
+static_assert(sizeof(set::iterator), ""); // Force instantiation.
+
+// If std::container::iterator is a typedef, attributes are inferred for the
+// underlying class.
+template 
+class __map_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __map_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __map_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class map {
+  // CHECK: ClassTemplateDecl {{.*}} map
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} map
+  // CHECK: OwnerAttr {{.*}}
+public:
+  typedef __map_iterator iterator;
+};
+static_assert(sizeof(map::iterator), ""); // Force instantiation.
+
+// Inline namespaces are ignored when checking if
+// the class lives in the std namespace.
+inline namespace inlinens {
+template 
+class __unordered_map_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __unordered_map_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_map_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class unordered_map {
+  // CHECK: ClassTemplateDecl {{.*}} unordered_map
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_map
+  // CHECK: OwnerAttr {{.*}}
+public:
+  typedef __unordered_map_iterator iterator;
+};
+static_assert(sizeof(unordered_map::iterator), ""); // Force instantiation.
+} // namespace inlinens
+
+// std::list has an implicit gsl::Owner attribute,
+// but explicit attributes take precedence.
+template 
+class [[gsl::Pointer]] list{};
+// CHECK: ClassTemplateDecl {{.*}} list
+// CHECK: PointerAttr {{.*}}
+// CHECK: ClassTemplateSpecializationDecl {{.*}} list
+// CHECK: PointerAttr {{.*}}
+
+static_assert(sizeof(list), ""); // Force instantiation.
+
+// Forward declared template (Owner).
+template <
+class CharT,
+class Traits>
+class basic_regex;
+// CHECK: ClassTemplateDecl {{.*}} basic_regex
+// CHECK: OwnerAttr {{.*}}
+
+// Forward declared template (Pointer).
+template 
+class reference_wrapper;
+// CHECK: ClassTemplateDecl {{.*}} reference_wrapper
+// CHECK: PointerAttr {{.*}}
+
+class some_unknown_type;
+// CHECK: CXXRecordDecl {{.*}} some_unknown_type
+
+} // namespace std
+
+namespace user {
+// If a class is not in the std namespace, we don't infer the attributes.
+class any {
+};
+} // namespace user
Index: clang/lib/Sema/SemaTemplate.cpp
===
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -1690,6 +1690,7 @@
 mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
 
   AddPushedVisibilityAttribute(NewClass);
+  addDefaultGslOwnerPointerAttribute(NewClass);
 
  

[PATCH] D64448: gsl::Owner/gsl::Pointer: Add implicit annotations for some std types

2019-08-07 Thread Matthias Gehre via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL368147: gsl::Owner/gsl::Pointer: Add implicit annotations 
for some std types (authored by mgehre, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D64448?vs=212446&id=213836#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64448/new/

https://reviews.llvm.org/D64448

Files:
  cfe/trunk/include/clang/Basic/AttrDocs.td
  cfe/trunk/include/clang/Sema/Sema.h
  cfe/trunk/lib/Sema/SemaAttr.cpp
  cfe/trunk/lib/Sema/SemaDecl.cpp
  cfe/trunk/lib/Sema/SemaTemplate.cpp
  cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer-std.cpp

Index: cfe/trunk/include/clang/Sema/Sema.h
===
--- cfe/trunk/include/clang/Sema/Sema.h
+++ cfe/trunk/include/clang/Sema/Sema.h
@@ -6116,6 +6116,17 @@
   ClassTemplateSpecializationDecl *BaseTemplateSpec,
   SourceLocation BaseLoc);
 
+  /// Add gsl::Pointer attribute to std::container::iterator
+  /// \param ND The declaration that introduces the name
+  /// std::container::iterator. \param UnderlyingRecord The record named by ND.
+  void inferGslPointerAttribute(NamedDecl *ND, CXXRecordDecl *UnderlyingRecord);
+
+  /// Add [[gsl::Owner]] and [[gsl::Pointer]] attributes for std:: types.
+  void inferGslOwnerPointerAttribute(CXXRecordDecl *Record);
+
+  /// Add [[gsl::Pointer]] attributes for std:: types.
+  void inferGslPointerAttribute(TypedefNameDecl *TD);
+
   void CheckCompletedCXXClass(CXXRecordDecl *Record);
 
   /// Check that the C++ class annoated with "trivial_abi" satisfies all the
Index: cfe/trunk/include/clang/Basic/AttrDocs.td
===
--- cfe/trunk/include/clang/Basic/AttrDocs.td
+++ cfe/trunk/include/clang/Basic/AttrDocs.td
@@ -4249,7 +4249,7 @@
 int *getInt() { return &value; }
   };
 
-The argument ``T`` is optional and currently ignored.
+The argument ``T`` is optional and is ignored.
 This attribute may be used by analysis tools and has no effect on code
 generation.
 
@@ -4275,7 +4275,7 @@
 int *getInt() { return &valuePointer; }
   };
 
-The argument ``T`` is optional and currently ignored.
+The argument ``T`` is optional and is ignored.
 This attribute may be used by analysis tools and has no effect on code
 generation.
 
Index: cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
===
--- cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
+++ cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
@@ -0,0 +1,129 @@
+// RUN: %clang_cc1 -ast-dump %s | \
+// RUN: FileCheck --implicit-check-not OwnerAttr --implicit-check-not PointerAttr %s
+
+// Test attribute inference for types in the standard library.
+namespace std {
+// Attributes are inferred for a (complete) class.
+class any {
+  // CHECK: CXXRecordDecl {{.*}} any
+  // CHECK: OwnerAttr {{.*}}
+};
+
+// Attributes are inferred for instantiations of a complete template.
+template 
+class vector {
+public:
+  class iterator {};
+  // CHECK: ClassTemplateDecl {{.*}} vector
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: CXXRecordDecl {{.*}} iterator
+  // CHECK: PointerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} vector
+  // CHECK: TemplateArgument type 'int'
+  // CHECK: OwnerAttr
+  // CHECK: CXXRecordDecl {{.*}} iterator
+  // CHECK: PointerAttr {{.*}}
+};
+static_assert(sizeof(vector), "");   // Force instantiation.
+static_assert(sizeof(vector::iterator), ""); // Force instantiation.
+
+// If std::container::iterator is a using declaration, attributes are inferred
+// for the underlying class.
+template 
+class __set_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __set_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __set_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class set {
+  // CHECK: ClassTemplateDecl {{.*}} set
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} set
+  // CHECK: OwnerAttr {{.*}}
+public:
+  using iterator = __set_iterator;
+};
+static_assert(sizeof(set::iterator), ""); // Force instantiation.
+
+// If std::container::iterator is a typedef, attributes are inferred for the
+// underlying class.
+template 
+class __map_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __map_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __map_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class map {
+  // CHECK: ClassTemplateDecl {{.*}} map
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} map
+  // CHECK: OwnerAttr {{.*}}
+public:
+  typedef __map_iterator iterator;
+};
+static_assert(sizeof(map::iterator), ""); // Force instantiation.
+
+// Inline namespaces are igno

[PATCH] D66164: [LifetimeAnalysis] Support std::stack::top() and std::optional::value()

2019-08-13 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre created this revision.
mgehre added a reviewer: gribozavr.
Herald added a project: clang.

Diagnose dangling pointers that come from std::stack::top() and 
std::optional::value().


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D66164

Files:
  clang/lib/Sema/SemaInit.cpp
  clang/test/Sema/warn-lifetime-analysis-nocfg.cpp


Index: clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
===
--- clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -169,6 +169,12 @@
   optional();
   optional(const T&);
   T &operator*();
+  T &value();
+};
+
+template 
+struct stack {
+  T &top();
 };
 }
 
@@ -204,6 +210,8 @@
   int &r = *std::optional(); // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}}
   int &r2 = *std::optional(5); // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}}
   int &r3 = std::vector().at(3); // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}}
+  int &r4 = std::optional(5).value(); // expected-warning {{object 
backing the pointer will be destroyed at the end of the full-expression}}
+  int &r5 = std::stack().top();   // expected-warning {{object 
backing the pointer will be destroyed at the end of the full-expression}}
 }
 
 std::vector getTempVec();
Index: clang/lib/Sema/SemaInit.cpp
===
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -6580,7 +6580,7 @@
 return llvm::StringSwitch(Callee->getName())
 .Cases("begin", "rbegin", "cbegin", "crbegin", true)
 .Cases("end", "rend", "cend", "crend", true)
-.Cases("c_str", "data", "get", true)
+.Cases("c_str", "data", "get", "value", true)
 // Map and set types.
 .Cases("find", "equal_range", "lower_bound", "upper_bound", true)
 .Default(false);
@@ -6591,7 +6591,7 @@
  OO == OverloadedOperatorKind::OO_Star;
 }
 return llvm::StringSwitch(Callee->getName())
-.Cases("front", "back", "at", true)
+.Cases("front", "back", "at", "top", true)
 .Default(false);
   }
   return false;


Index: clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
===
--- clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -169,6 +169,12 @@
   optional();
   optional(const T&);
   T &operator*();
+  T &value();
+};
+
+template 
+struct stack {
+  T &top();
 };
 }
 
@@ -204,6 +210,8 @@
   int &r = *std::optional(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
   int &r2 = *std::optional(5); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
   int &r3 = std::vector().at(3); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
+  int &r4 = std::optional(5).value(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
+  int &r5 = std::stack().top();   // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
 }
 
 std::vector getTempVec();
Index: clang/lib/Sema/SemaInit.cpp
===
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -6580,7 +6580,7 @@
 return llvm::StringSwitch(Callee->getName())
 .Cases("begin", "rbegin", "cbegin", "crbegin", true)
 .Cases("end", "rend", "cend", "crend", true)
-.Cases("c_str", "data", "get", true)
+.Cases("c_str", "data", "get", "value", true)
 // Map and set types.
 .Cases("find", "equal_range", "lower_bound", "upper_bound", true)
 .Default(false);
@@ -6591,7 +6591,7 @@
  OO == OverloadedOperatorKind::OO_Star;
 }
 return llvm::StringSwitch(Callee->getName())
-.Cases("front", "back", "at", true)
+.Cases("front", "back", "at", "top", true)
 .Default(false);
   }
   return false;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66164: [LifetimeAnalysis] Support std::stack::top() and std::optional::value()

2019-08-13 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked an inline comment as done.
mgehre added inline comments.



Comment at: clang/test/Sema/warn-lifetime-analysis-nocfg.cpp:172
   T &operator*();
+  T &value();
+};

xazax.hun wrote:
> I actually was a bit lazy when I added these tests. Both `value` and 
> `operator*` is overloaded on `&&`. But if you do not feel like adjusting the 
> tests this is fine, I can do it myself later :)
I'll change it to use the `&` variant in the test - the `&&` cannot dangle as 
far as I understand.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66164/new/

https://reviews.llvm.org/D66164



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


[PATCH] D66179: [LifetimeAnalysis] Support more STL idioms (template forward declaration and DependentNameType)

2019-08-13 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre created this revision.
mgehre added a reviewer: gribozavr.
Herald added a subscriber: Szelethus.
Herald added a project: clang.

This fixes inference of gsl::Pointer on std::set::iterator with libstdc++ (the 
typedef for iterator
on the template is a DependentNameType - we can only put the gsl::Pointer 
attribute
on the underlaying record after instantiation)

inference of gsl::Pointer on std::vector::iterator with libc++ (the class was 
forward-declared,
we added the gsl::Pointer on the canonical decl (the forward decl), and later 
when the
template was instantiated, there was no attribute on the definition so it was 
not instantiated).

and a duplicate gsl::Pointer on some class with libstdc++ (we first added an 
attribute to
a incomplete instantiation, and then another was copied from the template 
definition
when the instantiation was completed).


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D66179

Files:
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp

Index: clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
===
--- clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
+++ clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp
@@ -92,6 +92,59 @@
 static_assert(sizeof(unordered_map::iterator), ""); // Force instantiation.
 } // namespace inlinens
 
+// The iterator typedef is a DependentNameType.
+template 
+class __unordered_multimap_iterator {};
+// CHECK: ClassTemplateDecl {{.*}} __unordered_multimap_iterator
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_multimap_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class __unordered_multimap_base {
+public:
+  using iterator = __unordered_multimap_iterator;
+};
+
+template 
+class unordered_multimap {
+  // CHECK: ClassTemplateDecl {{.*}} unordered_multimap
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_multimap
+  // CHECK: OwnerAttr {{.*}}
+public:
+  using _Mybase = __unordered_multimap_base;
+  using iterator = typename _Mybase::iterator;
+};
+static_assert(sizeof(unordered_multimap::iterator), ""); // Force instantiation.
+
+// The canonical declaration of the iterator template is not its definition.
+template 
+class __unordered_multiset_iterator;
+// CHECK: ClassTemplateDecl {{.*}} __unordered_multiset_iterator
+// CHECK: PointerAttr
+// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_multiset_iterator
+// CHECK: TemplateArgument type 'int'
+// CHECK: PointerAttr
+
+template 
+class __unordered_multiset_iterator {
+  // CHECK: ClassTemplateDecl {{.*}} prev {{.*}} __unordered_multiset_iterator
+  // CHECK: PointerAttr
+};
+
+template 
+class unordered_multiset {
+  // CHECK: ClassTemplateDecl {{.*}} unordered_multiset
+  // CHECK: OwnerAttr {{.*}}
+  // CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_multiset
+  // CHECK: OwnerAttr {{.*}}
+public:
+  using iterator = __unordered_multiset_iterator;
+};
+
+static_assert(sizeof(unordered_multiset::iterator), ""); // Force instantiation.
+
 // std::list has an implicit gsl::Owner attribute,
 // but explicit attributes take precedence.
 template 
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -552,6 +552,18 @@
   continue;
 }
 
+if (auto *A = dyn_cast(TmplAttr)) {
+  if (!New->hasAttr())
+New->addAttr(A->clone(Context));
+  continue;
+}
+
+if (auto *A = dyn_cast(TmplAttr)) {
+  if (!New->hasAttr())
+New->addAttr(A->clone(Context));
+  continue;
+}
+
 assert(!TmplAttr->isPackExpansion());
 if (TmplAttr->isLateParsed() && LateAttrs) {
   // Late parsed attributes must be instantiated and attached after the
@@ -711,6 +723,9 @@
 
   SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
 
+  if (D->getUnderlyingType()->getAs())
+SemaRef.inferGslPointerAttribute(Typedef);
+
   Typedef->setAccess(D->getAccess());
 
   return Typedef;
Index: clang/lib/Sema/SemaAttr.cpp
===
--- clang/lib/Sema/SemaAttr.cpp
+++ clang/lib/Sema/SemaAttr.cpp
@@ -88,13 +88,20 @@
 template 
 static void addGslOwnerPointerAttributeIfNotExisting(ASTContext &Context,
  CXXRecordDecl *Record) {
-  CXXRecordDecl *Canonical = Record->getCanonicalDecl();
-  if (Canonical->hasAttr() || Canonical->hasAttr())
+  if (Record->hasAttr() || Record->hasAttr())
 return;
 
-  Canonical->addAttr(::new (Context) Attribute(SourceRange{}, Context,
-   /*DerefType*/ nullptr,
-   /*Spelling=*/0));
+  Record->addAttr(::new (Context) 

[PATCH] D66164: [LifetimeAnalysis] Support std::stack::top() and std::optional::value()

2019-08-13 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 214950.
mgehre marked 2 inline comments as done.
mgehre added a comment.

Fix commit


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66164/new/

https://reviews.llvm.org/D66164

Files:
  clang/lib/Sema/SemaInit.cpp
  clang/test/Sema/warn-lifetime-analysis-nocfg.cpp


Index: clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
===
--- clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -168,7 +168,14 @@
 struct optional {
   optional();
   optional(const T&);
-  T &operator*();
+  T &operator*() &;
+  T &&operator*() &&;
+  T &value() &;
+};
+
+template
+struct stack {
+  T &top();
 };
 }
 
@@ -186,6 +193,16 @@
   return s.c_str(); // expected-warning {{address of stack memory associated 
with local variable 's' returned}}
 }
 
+int &danglingRawPtrFromLocal2() {
+  std::optional o;
+  return o.value(); // expected-warning {{reference to stack memory associated 
with local variable 'o' returned}}
+}
+
+int &danglingRawPtrFromLocal3() {
+  std::optional o;
+  return *o; // expected-warning {{reference to stack memory associated with 
local variable 'o' returned}}
+}
+
 const char *danglingRawPtrFromTemp() {
   return std::basic_string().c_str(); // expected-warning {{returning 
address of local temporary object}}
 }
@@ -201,9 +218,8 @@
 }
 
 void danglingReferenceFromTempOwner() {
-  int &r = *std::optional(); // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}}
-  int &r2 = *std::optional(5); // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}}
-  int &r3 = std::vector().at(3); // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}}
+  int &r1 = std::vector().at(3); // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}}
+  int &r2 = std::stack().top();  // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}}
 }
 
 std::vector getTempVec();
Index: clang/lib/Sema/SemaInit.cpp
===
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -6591,7 +6591,7 @@
  OO == OverloadedOperatorKind::OO_Star;
 }
 return llvm::StringSwitch(Callee->getName())
-.Cases("front", "back", "at", true)
+.Cases("front", "back", "at", "top", "value", true)
 .Default(false);
   }
   return false;


Index: clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
===
--- clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -168,7 +168,14 @@
 struct optional {
   optional();
   optional(const T&);
-  T &operator*();
+  T &operator*() &;
+  T &&operator*() &&;
+  T &value() &;
+};
+
+template
+struct stack {
+  T &top();
 };
 }
 
@@ -186,6 +193,16 @@
   return s.c_str(); // expected-warning {{address of stack memory associated with local variable 's' returned}}
 }
 
+int &danglingRawPtrFromLocal2() {
+  std::optional o;
+  return o.value(); // expected-warning {{reference to stack memory associated with local variable 'o' returned}}
+}
+
+int &danglingRawPtrFromLocal3() {
+  std::optional o;
+  return *o; // expected-warning {{reference to stack memory associated with local variable 'o' returned}}
+}
+
 const char *danglingRawPtrFromTemp() {
   return std::basic_string().c_str(); // expected-warning {{returning address of local temporary object}}
 }
@@ -201,9 +218,8 @@
 }
 
 void danglingReferenceFromTempOwner() {
-  int &r = *std::optional(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
-  int &r2 = *std::optional(5); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
-  int &r3 = std::vector().at(3); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
+  int &r1 = std::vector().at(3); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
+  int &r2 = std::stack().top();  // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
 }
 
 std::vector getTempVec();
Index: clang/lib/Sema/SemaInit.cpp
===
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -6591,7 +6591,7 @@
  OO == OverloadedOperatorKind::OO_Star;
 }
 return llvm::StringSwitch(Callee->getName())
-.Cases("front", "back", "at", true)
+.Cases("front", "back", "at", "top", "value", true)
 .Default(false);
   }
   return false;

[PATCH] D66164: [LifetimeAnalysis] Support std::stack::top() and std::optional::value()

2019-08-13 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked 3 inline comments as done.
mgehre added inline comments.



Comment at: clang/lib/Sema/SemaInit.cpp:6583
 .Cases("end", "rend", "cend", "crend", true)
-.Cases("c_str", "data", "get", true)
+.Cases("c_str", "data", "get", "value", true)
 // Map and set types.

xazax.hun wrote:
> Oh, this one needs to be updated, as `value` returns a reference not a 
> pointer. 
Yes, I noticed the same.



Comment at: clang/test/Sema/warn-lifetime-analysis-nocfg.cpp:172
   T &operator*();
+  T &value();
+};

xazax.hun wrote:
> mgehre wrote:
> > xazax.hun wrote:
> > > I actually was a bit lazy when I added these tests. Both `value` and 
> > > `operator*` is overloaded on `&&`. But if you do not feel like adjusting 
> > > the tests this is fine, I can do it myself later :)
> > I'll change it to use the `&` variant in the test - the `&&` cannot dangle 
> > as far as I understand.
> It can!
> 
> Consider the following code:
> 
> ```
> int &&r = *std::optional(5);
> // r dangles here.
> ```
Oh, sure!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66164/new/

https://reviews.llvm.org/D66164



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


[PATCH] D66164: [LifetimeAnalysis] Support std::stack::top() and std::optional::value()

2019-08-13 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 214954.
mgehre marked an inline comment as done.
mgehre added a comment.

Add tests for rvalue-ref overloads


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66164/new/

https://reviews.llvm.org/D66164

Files:
  clang/lib/Sema/SemaInit.cpp
  clang/test/Sema/warn-lifetime-analysis-nocfg.cpp


Index: clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
===
--- clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -168,7 +168,15 @@
 struct optional {
   optional();
   optional(const T&);
-  T &operator*();
+  T &operator*() &;
+  T &&operator*() &&;
+  T &value() &;
+  T &&value() &&;
+};
+
+template
+struct stack {
+  T &top();
 };
 }
 
@@ -186,6 +194,16 @@
   return s.c_str(); // expected-warning {{address of stack memory associated 
with local variable 's' returned}}
 }
 
+int &danglingRawPtrFromLocal2() {
+  std::optional o;
+  return o.value(); // expected-warning {{reference to stack memory associated 
with local variable 'o' returned}}
+}
+
+int &danglingRawPtrFromLocal3() {
+  std::optional o;
+  return *o; // expected-warning {{reference to stack memory associated with 
local variable 'o' returned}}
+}
+
 const char *danglingRawPtrFromTemp() {
   return std::basic_string().c_str(); // expected-warning {{returning 
address of local temporary object}}
 }
@@ -201,9 +219,10 @@
 }
 
 void danglingReferenceFromTempOwner() {
-  int &r = *std::optional(); // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}}
-  int &r2 = *std::optional(5); // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}}
-  int &r3 = std::vector().at(3); // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}}
+  int &&r = *std::optional();  // expected-warning {{object 
backing the pointer will be destroyed at the end of the full-expression}}
+  int &&r2 = *std::optional(5);// expected-warning {{object 
backing the pointer will be destroyed at the end of the full-expression}}
+  int &&r3 = std::optional(5).value(); // expected-warning {{object 
backing the pointer will be destroyed at the end of the full-expression}}
+  int &r4 = std::vector().at(3);   // expected-warning {{object 
backing the pointer will be destroyed at the end of the full-expression}}
 }
 
 std::vector getTempVec();
Index: clang/lib/Sema/SemaInit.cpp
===
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -6591,7 +6591,7 @@
  OO == OverloadedOperatorKind::OO_Star;
 }
 return llvm::StringSwitch(Callee->getName())
-.Cases("front", "back", "at", true)
+.Cases("front", "back", "at", "top", "value", true)
 .Default(false);
   }
   return false;


Index: clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
===
--- clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -168,7 +168,15 @@
 struct optional {
   optional();
   optional(const T&);
-  T &operator*();
+  T &operator*() &;
+  T &&operator*() &&;
+  T &value() &;
+  T &&value() &&;
+};
+
+template
+struct stack {
+  T &top();
 };
 }
 
@@ -186,6 +194,16 @@
   return s.c_str(); // expected-warning {{address of stack memory associated with local variable 's' returned}}
 }
 
+int &danglingRawPtrFromLocal2() {
+  std::optional o;
+  return o.value(); // expected-warning {{reference to stack memory associated with local variable 'o' returned}}
+}
+
+int &danglingRawPtrFromLocal3() {
+  std::optional o;
+  return *o; // expected-warning {{reference to stack memory associated with local variable 'o' returned}}
+}
+
 const char *danglingRawPtrFromTemp() {
   return std::basic_string().c_str(); // expected-warning {{returning address of local temporary object}}
 }
@@ -201,9 +219,10 @@
 }
 
 void danglingReferenceFromTempOwner() {
-  int &r = *std::optional(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
-  int &r2 = *std::optional(5); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
-  int &r3 = std::vector().at(3); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
+  int &&r = *std::optional();  // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
+  int &&r2 = *std::optional(5);// expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
+  int &&r3 = std::optional(5).value(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-express

[PATCH] D66164: [LifetimeAnalysis] Support std::stack::top() and std::optional::value()

2019-08-14 Thread Matthias Gehre via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL368929: [LifetimeAnalysis] Support std::stack::top() and 
std::optional::value() (authored by mgehre, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D66164?vs=214954&id=215259#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66164/new/

https://reviews.llvm.org/D66164

Files:
  cfe/trunk/lib/Sema/SemaInit.cpp
  cfe/trunk/test/Sema/warn-lifetime-analysis-nocfg.cpp


Index: cfe/trunk/lib/Sema/SemaInit.cpp
===
--- cfe/trunk/lib/Sema/SemaInit.cpp
+++ cfe/trunk/lib/Sema/SemaInit.cpp
@@ -6610,7 +6610,7 @@
  OO == OverloadedOperatorKind::OO_Star;
 }
 return llvm::StringSwitch(Callee->getName())
-.Cases("front", "back", "at", true)
+.Cases("front", "back", "at", "top", "value", true)
 .Default(false);
   }
   return false;
Index: cfe/trunk/test/Sema/warn-lifetime-analysis-nocfg.cpp
===
--- cfe/trunk/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ cfe/trunk/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -170,7 +170,15 @@
 struct optional {
   optional();
   optional(const T&);
-  T &operator*();
+  T &operator*() &;
+  T &&operator*() &&;
+  T &value() &;
+  T &&value() &&;
+};
+
+template
+struct stack {
+  T &top();
 };
 }
 
@@ -188,6 +196,16 @@
   return s.c_str(); // expected-warning {{address of stack memory associated 
with local variable 's' returned}}
 }
 
+int &danglingRawPtrFromLocal2() {
+  std::optional o;
+  return o.value(); // expected-warning {{reference to stack memory associated 
with local variable 'o' returned}}
+}
+
+int &danglingRawPtrFromLocal3() {
+  std::optional o;
+  return *o; // expected-warning {{reference to stack memory associated with 
local variable 'o' returned}}
+}
+
 const char *danglingRawPtrFromTemp() {
   return std::basic_string().c_str(); // expected-warning {{returning 
address of local temporary object}}
 }
@@ -203,9 +221,10 @@
 }
 
 void danglingReferenceFromTempOwner() {
-  int &r = *std::optional(); // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}}
-  int &r2 = *std::optional(5); // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}}
-  int &r3 = std::vector().at(3); // expected-warning {{object backing the 
pointer will be destroyed at the end of the full-expression}}
+  int &&r = *std::optional();  // expected-warning {{object 
backing the pointer will be destroyed at the end of the full-expression}}
+  int &&r2 = *std::optional(5);// expected-warning {{object 
backing the pointer will be destroyed at the end of the full-expression}}
+  int &&r3 = std::optional(5).value(); // expected-warning {{object 
backing the pointer will be destroyed at the end of the full-expression}}
+  int &r4 = std::vector().at(3);   // expected-warning {{object 
backing the pointer will be destroyed at the end of the full-expression}}
 }
 
 std::vector getTempVec();


Index: cfe/trunk/lib/Sema/SemaInit.cpp
===
--- cfe/trunk/lib/Sema/SemaInit.cpp
+++ cfe/trunk/lib/Sema/SemaInit.cpp
@@ -6610,7 +6610,7 @@
  OO == OverloadedOperatorKind::OO_Star;
 }
 return llvm::StringSwitch(Callee->getName())
-.Cases("front", "back", "at", true)
+.Cases("front", "back", "at", "top", "value", true)
 .Default(false);
   }
   return false;
Index: cfe/trunk/test/Sema/warn-lifetime-analysis-nocfg.cpp
===
--- cfe/trunk/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ cfe/trunk/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -170,7 +170,15 @@
 struct optional {
   optional();
   optional(const T&);
-  T &operator*();
+  T &operator*() &;
+  T &&operator*() &&;
+  T &value() &;
+  T &&value() &&;
+};
+
+template
+struct stack {
+  T &top();
 };
 }
 
@@ -188,6 +196,16 @@
   return s.c_str(); // expected-warning {{address of stack memory associated with local variable 's' returned}}
 }
 
+int &danglingRawPtrFromLocal2() {
+  std::optional o;
+  return o.value(); // expected-warning {{reference to stack memory associated with local variable 'o' returned}}
+}
+
+int &danglingRawPtrFromLocal3() {
+  std::optional o;
+  return *o; // expected-warning {{reference to stack memory associated with local variable 'o' returned}}
+}
+
 const char *danglingRawPtrFromTemp() {
   return std::basic_string().c_str(); // expected-warning {{returning address of local temporary object}}
 }
@@ -203,9 +221,10 @@
 }
 
 void danglingReferenceFromTempOwner() {
-  int &r = *std::optional(); // expected-warning {{object backing the pointer will be destroyed at the end of the f

[PATCH] D66179: [LifetimeAnalysis] Support more STL idioms (template forward declaration and DependentNameType)

2019-08-14 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked 6 inline comments as done.
mgehre added inline comments.



Comment at: clang/lib/Sema/SemaAttr.cpp:102
+  dyn_cast_or_null(Record->getDescribedTemplate())) 
{
+if (auto *Def = Record->getDefinition())
+  addGslOwnerPointerAttributeIfNotExisting(Context, Def);

gribozavr wrote:
> I wonder why this is necessary. Sema should call inference on every 
> CXXRecordDecl. Is it because of incorrect short-circuiting in 
> `inferGslPointerAttribute` that I'm pointing out below?
The contract is: A CXXRecordDecl is a Pointer/Owner if and only if its 
canonical declaration has the Pointer/Owner attribute.

The analysis only checks this on concrete classes (excuse me if I'm using the 
wrong term here), i.e. non-template classes or instantiation of template 
classes.

During the inference, we might also put the attributes onto the templated 
declaration of a ClassTemplateDecl. The Pointer/Owner attributes here will not 
be used by the analysis.
We just put them there so clang will copy them to each instantiation, where 
they will be used by the analysis.

From what I understand, clang copies the attributes of the definition of the 
templated declaration to the instantiation.
In addition, when clang sees a redeclaration (e.g. of a template), it will also 
copy the attributes from the previous/canonical (?) declaration.

In the problematic case
```
// The canonical declaration of the iterator template is not its definition.
template 
class __unordered_multiset_iterator;

template 
class __unordered_multiset_iterator {
};

template 
class unordered_multiset {
public:
  using iterator = __unordered_multiset_iterator;
};

static_assert(sizeof(unordered_multiset::iterator), ""); // Force 
instantiation.
```
clang would (before this PR):
1. Create a `ClassTemplateDecl` with an `CXXRecordDecl` for 
`__unordered_multiset_iterator` (this is the canonical declaration, but not a 
definition)
2. Create a `ClassTemplateDecl` with an `CXXRecordDecl` for 
`__unordered_multiset_iterator` (this is not the canonical declaration, but its 
definition)
3. While processing the `using iterator` line, add a PointerAttr to the 
canonical declaration (from point 1)
4. While instantiating `__unordered_multiset_iterator`, copy attributes 
from the template definition (from point 2), which are none
Result: The `ClassTemplateSpecializationDecl` for 
`__unordered_multiset_iterator` would not have the `PointerAttr`.

On the other hand, a swapped example
```
template 
class __unordered_multiset_iterator;

template 
class unordered_multiset {
public:
  using iterator = __unordered_multiset_iterator;
};

template 
class __unordered_multiset_iterator {
};

static_assert(sizeof(unordered_multiset::iterator), ""); // Force 
instantiation.
```
would work because clang would (before this PR):
1. Create a `ClassTemplateDecl` with an `CXXRecordDecl` for 
`__unordered_multiset_iterator` (this is the canonical declaration, but not a 
definition)
2. While processing the `using iterator` line, add a PointerAttr to the 
canonical declaration (from point 1)
3. Create a `ClassTemplateDecl` with an `CXXRecordDecl` for 
`__unordered_multiset_iterator` (this is not the canonical declaration, but its 
definition); copy all attributes from a previous declaration, i.e. the 
PointerAttr from point 1
4. While instantiating `__unordered_multiset_iterator`, copy PointerAttr 
from the template definition (from point 3)

So we cannot just put the PointerAttr on the definition of the class template 
because there might be none yet (like in the second example). We need to put it 
on the definition in case
it was already parsed.



Comment at: clang/lib/Sema/SemaAttr.cpp:200
 CXXRecordDecl *Canonical = Record->getCanonicalDecl();
 if (Canonical->hasAttr() || Canonical->hasAttr())
   return;

gribozavr wrote:
> Should this code not do this short-circuit check? It is prone to going out of 
> sync with the code in `addGslOwnerPointerAttributeIfNotExisting`, like it did 
> just now.
> 
> If you want to check for attribute before doing the string search, you could 
> pass the string set into `addGslOwnerPointerAttributeIfNotExisting`, and let 
> that decide if it should infer the attribute or not.
Yes, the `hasAttr` check here is an optimization to avoid the string search. I 
don't think I can move the string search into 
`addGslOwnerPointerAttributeIfNotExisting`, because that function is called 
from other call sites that don't care about a set of names.



Comment at: clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp:95
 
+// The iterator typedef is a DependentNameType.
+template 

gribozavr wrote:
> This test file is getting pretty long and subtle, with lots of things are 
> being mixed into one file without isolation.
> 
> WDYT about refactoring it into a unit test that uses AST matchers to verify 
> attribute presence?
> 
> See clang/unittests/ASTM

[PATCH] D66303: [LifetimeAnalysis] Add support for free functions

2019-08-15 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added inline comments.



Comment at: clang/lib/Sema/SemaInit.cpp:6622
+return false;
+  const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl();
+  if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace())

Maybe move the `Callee->getNumParams() == 1` check from the caller into this 
function so it's obvious that `getParamDecl(0)` is allowed?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66303/new/

https://reviews.llvm.org/D66303



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


[PATCH] D66365: [clang-tidy] [readability-convert-member-functions-to-static] ignore functions that hide base class methods

2019-08-16 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre created this revision.
mgehre added reviewers: aaron.ballman, Eugene.Zelenko.
Herald added a subscriber: xazax.hun.
Herald added a project: clang.

Fixes bug https://bugs.llvm.org/show_bug.cgi?id=43002


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D66365

Files:
  clang-tools-extra/clang-tidy/readability/ConvertMemberFunctionsToStatic.cpp
  
clang-tools-extra/test/clang-tidy/readability-convert-member-functions-to-static.cpp


Index: 
clang-tools-extra/test/clang-tidy/readability-convert-member-functions-to-static.cpp
===
--- 
clang-tools-extra/test/clang-tidy/readability-convert-member-functions-to-static.cpp
+++ 
clang-tools-extra/test/clang-tidy/readability-convert-member-functions-to-static.cpp
@@ -216,3 +216,21 @@
 return;
   }
 };
+
+class HiddingBase {
+  int f();
+
+  static int g();
+};
+
+class HiddingDerived : public HiddingBase {
+  int f() {
+return 0;
+  }
+
+  int g() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'g' can be made static
+// CHECK-FIXES: {{^}}  static int g() {
+return 0;
+  }
+};
Index: 
clang-tools-extra/clang-tidy/readability/ConvertMemberFunctionsToStatic.cpp
===
--- clang-tools-extra/clang-tidy/readability/ConvertMemberFunctionsToStatic.cpp
+++ clang-tools-extra/clang-tidy/readability/ConvertMemberFunctionsToStatic.cpp
@@ -71,6 +71,31 @@
   return UsageOfThis.Used;
 }
 
+/// Does any base class have a non-static method with the same name?
+AST_MATCHER(CXXMethodDecl, isHiding) {
+  const IdentifierInfo *ThisIdentifier = Node.getIdentifier();
+  if (!ThisIdentifier)
+return false;
+
+  const CXXRecordDecl *Record = Node.getParent();
+
+  auto StaticOrDifferentName = [ThisIdentifier](const CXXMethodDecl *Method) {
+  if (Method->isStatic())
+return true;
+
+  const IdentifierInfo *Ident = 
Method->getIdentifier();
+  if (!Ident)
+return true;
+
+  return Ident->getName() != ThisIdentifier->getName();
+};
+
+  return !Record->forallBases([StaticOrDifferentName](const CXXRecordDecl 
*Base) {
+return llvm::all_of(Base->methods(),
+StaticOrDifferentName);
+  });
+}
+
 void ConvertMemberFunctionsToStatic::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
   cxxMethodDecl(
@@ -86,7 +111,8 @@
   // depending on template base class.
   ),
   isInsideMacroDefinition(),
-  hasCanonicalDecl(isInsideMacroDefinition()), usesThis(
+  hasCanonicalDecl(isInsideMacroDefinition()), isHiding(),
+  usesThis(
   .bind("x"),
   this);
 }


Index: clang-tools-extra/test/clang-tidy/readability-convert-member-functions-to-static.cpp
===
--- clang-tools-extra/test/clang-tidy/readability-convert-member-functions-to-static.cpp
+++ clang-tools-extra/test/clang-tidy/readability-convert-member-functions-to-static.cpp
@@ -216,3 +216,21 @@
 return;
   }
 };
+
+class HiddingBase {
+  int f();
+
+  static int g();
+};
+
+class HiddingDerived : public HiddingBase {
+  int f() {
+return 0;
+  }
+
+  int g() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'g' can be made static
+// CHECK-FIXES: {{^}}  static int g() {
+return 0;
+  }
+};
Index: clang-tools-extra/clang-tidy/readability/ConvertMemberFunctionsToStatic.cpp
===
--- clang-tools-extra/clang-tidy/readability/ConvertMemberFunctionsToStatic.cpp
+++ clang-tools-extra/clang-tidy/readability/ConvertMemberFunctionsToStatic.cpp
@@ -71,6 +71,31 @@
   return UsageOfThis.Used;
 }
 
+/// Does any base class have a non-static method with the same name?
+AST_MATCHER(CXXMethodDecl, isHiding) {
+  const IdentifierInfo *ThisIdentifier = Node.getIdentifier();
+  if (!ThisIdentifier)
+return false;
+
+  const CXXRecordDecl *Record = Node.getParent();
+
+  auto StaticOrDifferentName = [ThisIdentifier](const CXXMethodDecl *Method) {
+  if (Method->isStatic())
+return true;
+
+  const IdentifierInfo *Ident = Method->getIdentifier();
+  if (!Ident)
+return true;
+
+  return Ident->getName() != ThisIdentifier->getName();
+};
+
+  return !Record->forallBases([StaticOrDifferentName](const CXXRecordDecl *Base) {
+return llvm::all_of(Base->methods(),
+StaticOrDifferentName);
+  });
+}
+
 void ConvertMemberFunctionsToStatic::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
   cxxMet

[PATCH] D66179: [LifetimeAnalysis] Support more STL idioms (template forward declaration and DependentNameType)

2019-08-16 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked 4 inline comments as done.
mgehre added a comment.

I now start to wonder if we should instead put the attribute on all 
declarations (instead of just the canonical). Later redeclarations 
automatically inherit the attributes.
This would make both the checking easier (just check any declaration, no need 
to obtain the canonical first), and remove the special
case for adding to the definition of templated record for ClassTemplateDecls.




Comment at: clang/lib/Sema/SemaAttr.cpp:200
 CXXRecordDecl *Canonical = Record->getCanonicalDecl();
 if (Canonical->hasAttr() || Canonical->hasAttr())
   return;

gribozavr wrote:
> mgehre wrote:
> > gribozavr wrote:
> > > Should this code not do this short-circuit check? It is prone to going 
> > > out of sync with the code in `addGslOwnerPointerAttributeIfNotExisting`, 
> > > like it did just now.
> > > 
> > > If you want to check for attribute before doing the string search, you 
> > > could pass the string set into 
> > > `addGslOwnerPointerAttributeIfNotExisting`, and let that decide if it 
> > > should infer the attribute or not.
> > Yes, the `hasAttr` check here is an optimization to avoid the string 
> > search. I don't think I can move the string search into 
> > `addGslOwnerPointerAttributeIfNotExisting`, because that function is called 
> > from other call sites that don't care about a set of names.
> Sorry I wasn't clear enough -- the issue that I noticed is that this check 
> looks at the canonical decl, while `addGslOwnerPointerAttributeIfNotExisting` 
> attaches the attribute to the decl itself -- that's what I meant by "out of 
> sync".
I make sure that `addGslOwnerPointerAttributeIfNotExisting` is only called with 
the canonical decl as argument, which the caller usually has around. The only 
exception to this is when addGslOwnerPointerAttributeIfNotExisting calls itself 
to attach an attribute to the definition of templated class.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66179/new/

https://reviews.llvm.org/D66179



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


[PATCH] D66365: [clang-tidy] [readability-convert-member-functions-to-static] ignore functions that hide base class methods

2019-08-19 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

I struggle myself to fully understand the motivation behind the bug report. 
This is certainly not code that I would write.
So I don't really care about that kind of code and I didn't want to be in the 
way of other people's way of writing C++.

Alternatively, we could ask the bug reporter to use `// NOLINT` to support his 
specific case. I will try to get some clarification
from the reporter.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66365/new/

https://reviews.llvm.org/D66365



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


[PATCH] D63088: [clang-tidy] misc-unused-parameters: don't comment out parameter name for C code

2019-06-21 Thread Matthias Gehre via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL364106: [clang-tidy] misc-unused-parameters: don't 
comment out parameter name for C code (authored by mgehre, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D63088?vs=203873&id=206081#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63088/new/

https://reviews.llvm.org/D63088

Files:
  clang-tools-extra/trunk/clang-tidy/misc/UnusedParametersCheck.cpp
  clang-tools-extra/trunk/test/clang-tidy/misc-unused-parameters.c


Index: clang-tools-extra/trunk/clang-tidy/misc/UnusedParametersCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/misc/UnusedParametersCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/misc/UnusedParametersCheck.cpp
@@ -138,14 +138,19 @@
 Indexer = llvm::make_unique(*Result.Context);
   }
 
-  // Comment out parameter name for non-local functions.
+  // Cannot remove parameter for non-local functions.
   if (Function->isExternallyVisible() ||
   !Result.SourceManager->isInMainFile(Function->getLocation()) ||
   !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function)) {
+
+// It is illegal to omit parameter name here in C code, so early-out.
+if (!Result.Context->getLangOpts().CPlusPlus)
+  return;
+
 SourceRange RemovalRange(Param->getLocation());
-// Note: We always add a space before the '/*' to not accidentally create a
-// '*/*' for pointer types, which doesn't start a comment. clang-format 
will
-// clean this up afterwards.
+// Note: We always add a space before the '/*' to not accidentally create
+// a '*/*' for pointer types, which doesn't start a comment. clang-format
+// will clean this up afterwards.
 MyDiag << FixItHint::CreateReplacement(
 RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
 return;
Index: clang-tools-extra/trunk/test/clang-tidy/misc-unused-parameters.c
===
--- clang-tools-extra/trunk/test/clang-tidy/misc-unused-parameters.c
+++ clang-tools-extra/trunk/test/clang-tidy/misc-unused-parameters.c
@@ -4,7 +4,7 @@
 // =
 void a(int i) {;}
 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused 
[misc-unused-parameters]
-// CHECK-FIXES: {{^}}void a(int  /*i*/) {;}{{$}}
+// CHECK-FIXES: {{^}}void a(int i) {;}{{$}}
 
 static void b(); // In C, forward declarations can leave out parameters.
 static void b(int i) {;}


Index: clang-tools-extra/trunk/clang-tidy/misc/UnusedParametersCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/misc/UnusedParametersCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/misc/UnusedParametersCheck.cpp
@@ -138,14 +138,19 @@
 Indexer = llvm::make_unique(*Result.Context);
   }
 
-  // Comment out parameter name for non-local functions.
+  // Cannot remove parameter for non-local functions.
   if (Function->isExternallyVisible() ||
   !Result.SourceManager->isInMainFile(Function->getLocation()) ||
   !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function)) {
+
+// It is illegal to omit parameter name here in C code, so early-out.
+if (!Result.Context->getLangOpts().CPlusPlus)
+  return;
+
 SourceRange RemovalRange(Param->getLocation());
-// Note: We always add a space before the '/*' to not accidentally create a
-// '*/*' for pointer types, which doesn't start a comment. clang-format will
-// clean this up afterwards.
+// Note: We always add a space before the '/*' to not accidentally create
+// a '*/*' for pointer types, which doesn't start a comment. clang-format
+// will clean this up afterwards.
 MyDiag << FixItHint::CreateReplacement(
 RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
 return;
Index: clang-tools-extra/trunk/test/clang-tidy/misc-unused-parameters.c
===
--- clang-tools-extra/trunk/test/clang-tidy/misc-unused-parameters.c
+++ clang-tools-extra/trunk/test/clang-tidy/misc-unused-parameters.c
@@ -4,7 +4,7 @@
 // =
 void a(int i) {;}
 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
-// CHECK-FIXES: {{^}}void a(int  /*i*/) {;}{{$}}
+// CHECK-FIXES: {{^}}void a(int i) {;}{{$}}
 
 static void b(); // In C, forward declarations can leave out parameters.
 static void b(int i) {;}
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D63954: Add lifetime categories attributes

2019-06-28 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre created this revision.
mgehre added a reviewer: gribozavr.
Herald added a project: clang.

This is the first part of work announced in 
"[RFC] Adding lifetime analysis to clang" [0],
i.e. the addition of the [[gsl::Owner(T)]] and
[[gsl::Pointer(T)]] attributes, which
will enable user-defined types to participate in
the lifetime analysis (which will be part of the
next PR).
The type `T` here is called "DerefType" in the paper,
and denotes the type that an Owner owns and a Pointer
points to. E.g. `std::vector` should be annotated
with `[[gsl::Owner(int)]]` and 
a `std::vector::iterator` with `[[gsl::Pointer(int)]]`.

We explicitly allow to add an annotation after
the definition of the class to allow adding annotations
to external source from by the user, e.g.

  #include 
  
  namespace std {
  template
  class [[gsl::Owner(T)]] vector;
  }

until we can ship a standard library with annotations.

[0] http://lists.llvm.org/pipermail/cfe-dev/2018-November/060355.html


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D63954

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/AST/ast-dump-attr.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/SemaCXX/attr-gsl-owner-pointer.cpp

Index: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int [[gsl::Owner]] i;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+void [[gsl::Owner]] f();
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+[[gsl::Owner]] void f();
+ // expected-warning@-1 {{'Owner' attribute only applies to classes}}
+
+struct S {
+};
+
+S [[gsl::Owner]] Instance;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+class [[gsl::Owner]] OwnerMissingParameter {};
+// expected-error@-1 {{'Owner' attribute takes one argument}}
+class [[gsl::Pointer]] PointerMissingParameter {};
+// expected-error@-1 {{'Pointer' attribute takes one argument}}
+
+class [[gsl::Owner(7)]] OwnerDerefNoType {};
+// expected-error@-1 {{expected a type}} expected-error@-1 {{expected ')'}}
+// expected-note@-2 {{to match this '('}}
+
+class [[gsl::Pointer("int")]] PointerDerefNoType {};
+// expected-error@-1 {{expected a type}} expected-error@-1 {{expected ')'}}
+// expected-note@-2 {{to match this '('}}
+
+class [[gsl::Owner(int)]] [[gsl::Pointer(int)]] BothOwnerPointer {};
+// expected-error@-1 {{'Pointer' and 'Owner' attributes are not compatible}}
+// expected-note@-2 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] [[gsl::Owner(int)]] DuplicateOwner {};
+// expected-error@-1 {{'Owner' and 'Owner' attributes are not compatible}}
+// expected-note@-2 {{conflicting attribute is here}}
+
+class [[gsl::Pointer(int)]] [[gsl::Pointer(int)]] DuplicatePointer {};
+// expected-error@-1 {{'Pointer' and 'Pointer' attributes are not compatible}}
+// expected-note@-2 {{conflicting attribute is here}}
+
+class [[gsl::Owner(void)]] OwnerVoidDerefType {};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Owner'}}
+class [[gsl::Pointer(void)]] PointerVoidDerefType {};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Pointer'}}
+
+class [[gsl::Owner(int)]] AnOwner {};
+class [[gsl::Pointer(S)]] APointer {};
+
+class AddOwnerLater {};
+class [[gsl::Owner(int)]] AddOwnerLater;
+
+class [[gsl::Pointer(int)]] AddConflictLater {};
+class [[gsl::Owner(int)]] AddConflictLater;
+// expected-error@-1 {{'Owner' and 'Pointer' attributes are not compatible}}
+// expected-note@-3 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] AddConflictLater2 {};
+class [[gsl::Owner(float)]] AddConflictLater2;
+// expected-error@-1 {{'Owner' and 'Owner' attributes are not compatible}}
+// expected-note@-3 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] AddTheSameLater {};
+class [[gsl::Owner(int)]] AddTheSameLater;
\ No newline at end of file
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -116,8 +116,10 @@
 // CHECK-NEXT: OpenCLNoSVM (SubjectMatchRule_variable)
 // CHECK-NEXT: OptimizeNone (SubjectMatchRule_function, SubjectMatchRule_objc_method)
 // CHECK-NEXT: Overloadable (SubjectMatchRule_function)
+// CHECK-NEXT: Owner (SubjectMatchRule_record)
 // CHECK-NEXT: ParamTypestate (SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: Pointer (Subject

[PATCH] D63954: Add lifetime categories attributes

2019-06-28 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 207138.
mgehre added a comment.

Fix typo


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/AST/ast-dump-attr.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/SemaCXX/attr-gsl-owner-pointer.cpp

Index: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int [[gsl::Owner]] i;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+void [[gsl::Owner]] f();
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+[[gsl::Owner]] void f();
+ // expected-warning@-1 {{'Owner' attribute only applies to classes}}
+
+struct S {
+};
+
+S [[gsl::Owner]] Instance;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+class [[gsl::Owner]] OwnerMissingParameter {};
+// expected-error@-1 {{'Owner' attribute takes one argument}}
+class [[gsl::Pointer]] PointerMissingParameter {};
+// expected-error@-1 {{'Pointer' attribute takes one argument}}
+
+class [[gsl::Owner(7)]] OwnerDerefNoType {};
+// expected-error@-1 {{expected a type}} expected-error@-1 {{expected ')'}}
+// expected-note@-2 {{to match this '('}}
+
+class [[gsl::Pointer("int")]] PointerDerefNoType {};
+// expected-error@-1 {{expected a type}} expected-error@-1 {{expected ')'}}
+// expected-note@-2 {{to match this '('}}
+
+class [[gsl::Owner(int)]] [[gsl::Pointer(int)]] BothOwnerPointer {};
+// expected-error@-1 {{'Pointer' and 'Owner' attributes are not compatible}}
+// expected-note@-2 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] [[gsl::Owner(int)]] DuplicateOwner {};
+// expected-error@-1 {{'Owner' and 'Owner' attributes are not compatible}}
+// expected-note@-2 {{conflicting attribute is here}}
+
+class [[gsl::Pointer(int)]] [[gsl::Pointer(int)]] DuplicatePointer {};
+// expected-error@-1 {{'Pointer' and 'Pointer' attributes are not compatible}}
+// expected-note@-2 {{conflicting attribute is here}}
+
+class [[gsl::Owner(void)]] OwnerVoidDerefType {};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Owner'}}
+class [[gsl::Pointer(void)]] PointerVoidDerefType {};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Pointer'}}
+
+class [[gsl::Owner(int)]] AnOwner {};
+class [[gsl::Pointer(S)]] APointer {};
+
+class AddOwnerLater {};
+class [[gsl::Owner(int)]] AddOwnerLater;
+
+class [[gsl::Pointer(int)]] AddConflictLater {};
+class [[gsl::Owner(int)]] AddConflictLater;
+// expected-error@-1 {{'Owner' and 'Pointer' attributes are not compatible}}
+// expected-note@-3 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] AddConflictLater2 {};
+class [[gsl::Owner(float)]] AddConflictLater2;
+// expected-error@-1 {{'Owner' and 'Owner' attributes are not compatible}}
+// expected-note@-3 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] AddTheSameLater {};
+class [[gsl::Owner(int)]] AddTheSameLater;
\ No newline at end of file
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -116,8 +116,10 @@
 // CHECK-NEXT: OpenCLNoSVM (SubjectMatchRule_variable)
 // CHECK-NEXT: OptimizeNone (SubjectMatchRule_function, SubjectMatchRule_objc_method)
 // CHECK-NEXT: Overloadable (SubjectMatchRule_function)
+// CHECK-NEXT: Owner (SubjectMatchRule_record)
 // CHECK-NEXT: ParamTypestate (SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: Pointer (SubjectMatchRule_record)
 // CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function)
 // CHECK-NEXT: ReqdWorkGroupSize (SubjectMatchRule_function)
 // CHECK-NEXT: RequireConstantInit (SubjectMatchRule_variable_is_global)
Index: clang/test/AST/ast-dump-attr.cpp
===
--- clang/test/AST/ast-dump-attr.cpp
+++ clang/test/AST/ast-dump-attr.cpp
@@ -211,6 +211,15 @@
 }
 }
 
+namespace TestLifetimeCategories {
+  class [[gsl::Owner(int)]] AOwner {};
+  // CHECK: CXXRecordDecl{{.*}} class AOwner
+  // CHECK: OwnerAttr {{.*}} int
+  class [[gsl::Pointer(int)]] APointer {};
+  // CHECK: CXXRecordDecl{{.*}} class APointer
+  // CHECK: PointerAttr {{.*}} int
+}
+
 // Verify the order of attributes in the Ast. It must reflect the order
 // in the parsed source.
 int mergeAttrTest()

[PATCH] D63954: Add lifetime categories attributes

2019-06-28 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

We can try to add the annotations to libcxx (which will still take time),
but there are also other standard libraries (libstdc++, MSVC) that
can be used with clang.
Eventually everybody will have lifetime annotations (of course ;-) ),
but in the meantime there seems to be no other way to enable
the analysis on unmodified STL.

My idea would be to maintain a `lifetime-annotations` headers (outside of clang 
repo?)
with #ifdef magic to add lifetime annotations for major STL variants/versions 
as a drop-in
to enable lifetime analysis. It's not nice, but only temporary and at least 
better than requiring
to change your STL to get lifetime analysis.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954



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


[PATCH] D63954: Add lifetime categories attributes

2019-06-30 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

We can and should explore both options and see what works best.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954



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


[PATCH] D63954: Add lifetime categories attributes

2019-06-30 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 207235.
mgehre added a comment.

Address some review comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/AST/ast-dump-attr.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/SemaCXX/attr-gsl-owner-pointer.cpp

Index: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int [[gsl::Owner]] i;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+void [[gsl::Owner]] f();
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+[[gsl::Owner]] void f();
+ // expected-warning@-1 {{'Owner' attribute only applies to classes}}
+
+struct S {
+};
+
+S [[gsl::Owner]] Instance;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+class [[gsl::Owner]] OwnerMissingParameter {};
+// expected-error@-1 {{'Owner' attribute takes one argument}}
+class [[gsl::Pointer]] PointerMissingParameter {};
+// expected-error@-1 {{'Pointer' attribute takes one argument}}
+
+class [[gsl::Owner(7)]] OwnerDerefNoType {};
+// expected-error@-1 {{expected a type}} expected-error@-1 {{expected ')'}}
+// expected-note@-2 {{to match this '('}}
+
+class [[gsl::Pointer("int")]] PointerDerefNoType {};
+// expected-error@-1 {{expected a type}} expected-error@-1 {{expected ')'}}
+// expected-note@-2 {{to match this '('}}
+
+class [[gsl::Owner(int)]] [[gsl::Pointer(int)]] BothOwnerPointer {};
+// expected-error@-1 {{'Pointer' and 'Owner' attributes are not compatible}}
+// expected-note@-2 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] [[gsl::Owner(int)]] DuplicateOwner {};
+
+class [[gsl::Pointer(int)]] [[gsl::Pointer(int)]] DuplicatePointer {};
+
+class [[gsl::Owner(void)]] OwnerVoidDerefType {};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Owner'}}
+class [[gsl::Pointer(void)]] PointerVoidDerefType {};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Pointer'}}
+
+class [[gsl::Owner(int)]] AnOwner {};
+class [[gsl::Pointer(S)]] APointer {};
+
+class AddOwnerLater {};
+class [[gsl::Owner(int)]] AddOwnerLater;
+
+class [[gsl::Pointer(int)]] AddConflictLater {};
+class [[gsl::Owner(int)]] AddConflictLater;
+// expected-error@-1 {{'Owner' and 'Pointer' attributes are not compatible}}
+// expected-note@-3 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] AddConflictLater2 {};
+class [[gsl::Owner(float)]] AddConflictLater2;
+// expected-error@-1 {{'Owner' and 'Owner' attributes are not compatible}}
+// expected-note@-3 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] AddTheSameLater {};
+class [[gsl::Owner(int)]] AddTheSameLater;
\ No newline at end of file
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -116,8 +116,10 @@
 // CHECK-NEXT: OpenCLNoSVM (SubjectMatchRule_variable)
 // CHECK-NEXT: OptimizeNone (SubjectMatchRule_function, SubjectMatchRule_objc_method)
 // CHECK-NEXT: Overloadable (SubjectMatchRule_function)
+// CHECK-NEXT: Owner (SubjectMatchRule_record)
 // CHECK-NEXT: ParamTypestate (SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: Pointer (SubjectMatchRule_record)
 // CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function)
 // CHECK-NEXT: ReqdWorkGroupSize (SubjectMatchRule_function)
 // CHECK-NEXT: RequireConstantInit (SubjectMatchRule_variable_is_global)
Index: clang/test/AST/ast-dump-attr.cpp
===
--- clang/test/AST/ast-dump-attr.cpp
+++ clang/test/AST/ast-dump-attr.cpp
@@ -211,6 +211,15 @@
 }
 }
 
+namespace TestLifetimeCategories {
+  class [[gsl::Owner(int)]] AOwner {};
+  // CHECK: CXXRecordDecl{{.*}} class AOwner
+  // CHECK: OwnerAttr {{.*}} int
+  class [[gsl::Pointer(int)]] APointer {};
+  // CHECK: CXXRecordDecl{{.*}} class APointer
+  // CHECK: PointerAttr {{.*}} int
+}
+
 // Verify the order of attributes in the Ast. It must reflect the order
 // in the parsed source.
 int mergeAttrTest() __attribute__((deprecated)) __attribute__((warn_unused_result));
Index: clang/lib/Sema/SemaDeclAttr.cpp
===
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp

[PATCH] D63954: Add lifetime categories attributes

2019-06-30 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked 2 inline comments as done.
mgehre added inline comments.



Comment at: clang/lib/Sema/SemaDeclAttr.cpp:4560-4561
+  if(AL.getKind() ==  ParsedAttr::AT_Owner) {
+if (checkAttrMutualExclusion(S, D, AL))
+  return;
+if (const auto *Attr = D->getAttr()) {

erik.pilkington wrote:
> This is duplicated with the first line in the function.
Removed the first line, which only checked for duplicate attributes on the same 
declaration, but we must check (here) that all matching
declaration are consistent - by performing all checks on the canonical 
declaration.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954



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


[PATCH] D63954: Add lifetime categories attributes

2019-07-01 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 207381.
mgehre marked 5 inline comments as done.
mgehre added a comment.

- Address more review comments.
- git-clang-format


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/AST/ast-dump-attr.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/SemaCXX/attr-gsl-owner-pointer.cpp

Index: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int [[gsl::Owner]] i;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+void [[gsl::Owner]] f();
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+[[gsl::Owner]] void f();
+// expected-warning@-1 {{'Owner' attribute only applies to classes}}
+
+struct S {
+};
+
+S [[gsl::Owner]] Instance;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+class [[gsl::Owner]] OwnerMissingParameter{};
+// expected-error@-1 {{'Owner' attribute takes one argument}}
+class [[gsl::Pointer]] PointerMissingParameter{};
+// expected-error@-1 {{'Pointer' attribute takes one argument}}
+
+class [[gsl::Owner(7)]] OwnerDerefNoType{};
+// expected-error@-1 {{expected a type}} expected-error@-1 {{expected ')'}}
+// expected-note@-2 {{to match this '('}}
+
+class [[gsl::Pointer("int")]] PointerDerefNoType{};
+// expected-error@-1 {{expected a type}} expected-error@-1 {{expected ')'}}
+// expected-note@-2 {{to match this '('}}
+
+class [[gsl::Owner(int)]] [[gsl::Pointer(int)]] BothOwnerPointer{};
+// expected-error@-1 {{'Pointer' and 'Owner' attributes are not compatible}}
+// expected-note@-2 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] [[gsl::Owner(int)]] DuplicateOwner{};
+
+class [[gsl::Pointer(int)]] [[gsl::Pointer(int)]] DuplicatePointer{};
+
+class [[gsl::Owner(void)]] OwnerVoidDerefType{};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Owner'}}
+class [[gsl::Pointer(void)]] PointerVoidDerefType{};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Pointer'}}
+
+class [[gsl::Owner(int)]] AnOwner{};
+class [[gsl::Pointer(S)]] APointer{};
+
+class AddOwnerLater {};
+class [[gsl::Owner(int)]] AddOwnerLater;
+
+class [[gsl::Pointer(int)]] AddConflictLater{};
+class [[gsl::Owner(int)]] AddConflictLater;
+// expected-error@-1 {{'Owner' and 'Pointer' attributes are not compatible}}
+// expected-note@-3 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] AddConflictLater2{};
+class [[gsl::Owner(float)]] AddConflictLater2;
+// expected-error@-1 {{'Owner' and 'Owner' attributes are not compatible}}
+// expected-note@-3 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] AddTheSameLater{};
+class [[gsl::Owner(int)]] AddTheSameLater;
\ No newline at end of file
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -116,8 +116,10 @@
 // CHECK-NEXT: OpenCLNoSVM (SubjectMatchRule_variable)
 // CHECK-NEXT: OptimizeNone (SubjectMatchRule_function, SubjectMatchRule_objc_method)
 // CHECK-NEXT: Overloadable (SubjectMatchRule_function)
+// CHECK-NEXT: Owner (SubjectMatchRule_record)
 // CHECK-NEXT: ParamTypestate (SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: Pointer (SubjectMatchRule_record)
 // CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function)
 // CHECK-NEXT: ReqdWorkGroupSize (SubjectMatchRule_function)
 // CHECK-NEXT: RequireConstantInit (SubjectMatchRule_variable_is_global)
Index: clang/test/AST/ast-dump-attr.cpp
===
--- clang/test/AST/ast-dump-attr.cpp
+++ clang/test/AST/ast-dump-attr.cpp
@@ -211,6 +211,15 @@
 }
 }
 
+namespace TestLifetimeCategories {
+class [[gsl::Owner(int)]] AOwner{};
+// CHECK: CXXRecordDecl{{.*}} class AOwner
+// CHECK: OwnerAttr {{.*}} int
+class [[gsl::Pointer(int)]] APointer{};
+// CHECK: CXXRecordDecl{{.*}} class APointer
+// CHECK: PointerAttr {{.*}} int
+} // namespace TestLifetimeCategories
+
 // Verify the order of attributes in the Ast. It must reflect the order
 // in the parsed source.
 int mergeAttrTest() __attribute__((deprecated)) __attribute__((warn_unused_result));
Index: clang/lib/Sema/SemaDeclAttr.cpp
===
---

[PATCH] D63954: Add lifetime categories attributes

2019-07-01 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

I understand that putting types on forward declared header (standard libraries 
/ third party libraries) is not a approach we should favor. 
Thank you for your good arguments.
API notes seems like a really good approach for this (I would like to help with 
the upstreaming), and in the meanwhile
I will work on hard-coding attributes for standard library types in clang for a 
follow-up PR. I think we could have them always attached (I will measure 
performance),
so that -Wlifetime will not change the AST.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954



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


[PATCH] D63954: Add lifetime categories attributes

2019-07-01 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 207400.
mgehre added a comment.

- Add newline at end of file


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/AST/ast-dump-attr.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/SemaCXX/attr-gsl-owner-pointer.cpp

Index: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int [[gsl::Owner]] i;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+void [[gsl::Owner]] f();
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+[[gsl::Owner]] void f();
+// expected-warning@-1 {{'Owner' attribute only applies to classes}}
+
+struct S {
+};
+
+S [[gsl::Owner]] Instance;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+class [[gsl::Owner]] OwnerMissingParameter{};
+// expected-error@-1 {{'Owner' attribute takes one argument}}
+class [[gsl::Pointer]] PointerMissingParameter{};
+// expected-error@-1 {{'Pointer' attribute takes one argument}}
+
+class [[gsl::Owner(7)]] OwnerDerefNoType{};
+// expected-error@-1 {{expected a type}} expected-error@-1 {{expected ')'}}
+// expected-note@-2 {{to match this '('}}
+
+class [[gsl::Pointer("int")]] PointerDerefNoType{};
+// expected-error@-1 {{expected a type}} expected-error@-1 {{expected ')'}}
+// expected-note@-2 {{to match this '('}}
+
+class [[gsl::Owner(int)]] [[gsl::Pointer(int)]] BothOwnerPointer{};
+// expected-error@-1 {{'Pointer' and 'Owner' attributes are not compatible}}
+// expected-note@-2 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] [[gsl::Owner(int)]] DuplicateOwner{};
+
+class [[gsl::Pointer(int)]] [[gsl::Pointer(int)]] DuplicatePointer{};
+
+class [[gsl::Owner(void)]] OwnerVoidDerefType{};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Owner'}}
+class [[gsl::Pointer(void)]] PointerVoidDerefType{};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Pointer'}}
+
+class [[gsl::Owner(int)]] AnOwner{};
+class [[gsl::Pointer(S)]] APointer{};
+
+class AddOwnerLater {};
+class [[gsl::Owner(int)]] AddOwnerLater;
+
+class [[gsl::Pointer(int)]] AddConflictLater{};
+class [[gsl::Owner(int)]] AddConflictLater;
+// expected-error@-1 {{'Owner' and 'Pointer' attributes are not compatible}}
+// expected-note@-3 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] AddConflictLater2{};
+class [[gsl::Owner(float)]] AddConflictLater2;
+// expected-error@-1 {{'Owner' and 'Owner' attributes are not compatible}}
+// expected-note@-3 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] AddTheSameLater{};
+class [[gsl::Owner(int)]] AddTheSameLater;
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -116,8 +116,10 @@
 // CHECK-NEXT: OpenCLNoSVM (SubjectMatchRule_variable)
 // CHECK-NEXT: OptimizeNone (SubjectMatchRule_function, SubjectMatchRule_objc_method)
 // CHECK-NEXT: Overloadable (SubjectMatchRule_function)
+// CHECK-NEXT: Owner (SubjectMatchRule_record)
 // CHECK-NEXT: ParamTypestate (SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: Pointer (SubjectMatchRule_record)
 // CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function)
 // CHECK-NEXT: ReqdWorkGroupSize (SubjectMatchRule_function)
 // CHECK-NEXT: RequireConstantInit (SubjectMatchRule_variable_is_global)
Index: clang/test/AST/ast-dump-attr.cpp
===
--- clang/test/AST/ast-dump-attr.cpp
+++ clang/test/AST/ast-dump-attr.cpp
@@ -211,6 +211,15 @@
 }
 }
 
+namespace TestLifetimeCategories {
+class [[gsl::Owner(int)]] AOwner{};
+// CHECK: CXXRecordDecl{{.*}} class AOwner
+// CHECK: OwnerAttr {{.*}} int
+class [[gsl::Pointer(int)]] APointer{};
+// CHECK: CXXRecordDecl{{.*}} class APointer
+// CHECK: PointerAttr {{.*}} int
+} // namespace TestLifetimeCategories
+
 // Verify the order of attributes in the Ast. It must reflect the order
 // in the parsed source.
 int mergeAttrTest() __attribute__((deprecated)) __attribute__((warn_unused_result));
Index: clang/lib/Sema/SemaDeclAttr.cpp
===
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -4533,6 +4533,48 @@

[PATCH] D63954: Add lifetime categories attributes

2019-07-02 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 207613.
mgehre added a comment.

- Make the list of attribute properties more consistent.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63954/new/

https://reviews.llvm.org/D63954

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/AST/ast-dump-attr.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/SemaCXX/attr-gsl-owner-pointer.cpp

Index: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int [[gsl::Owner]] i;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+void [[gsl::Owner]] f();
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+[[gsl::Owner]] void f();
+// expected-warning@-1 {{'Owner' attribute only applies to classes}}
+
+struct S {
+};
+
+S [[gsl::Owner]] Instance;
+// expected-error@-1 {{'Owner' attribute cannot be applied to types}}
+
+class [[gsl::Owner]] OwnerMissingParameter{};
+// expected-error@-1 {{'Owner' attribute takes one argument}}
+class [[gsl::Pointer]] PointerMissingParameter{};
+// expected-error@-1 {{'Pointer' attribute takes one argument}}
+
+class [[gsl::Owner(7)]] OwnerDerefNoType{};
+// expected-error@-1 {{expected a type}} expected-error@-1 {{expected ')'}}
+// expected-note@-2 {{to match this '('}}
+
+class [[gsl::Pointer("int")]] PointerDerefNoType{};
+// expected-error@-1 {{expected a type}} expected-error@-1 {{expected ')'}}
+// expected-note@-2 {{to match this '('}}
+
+class [[gsl::Owner(int)]] [[gsl::Pointer(int)]] BothOwnerPointer{};
+// expected-error@-1 {{'Pointer' and 'Owner' attributes are not compatible}}
+// expected-note@-2 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] [[gsl::Owner(int)]] DuplicateOwner{};
+
+class [[gsl::Pointer(int)]] [[gsl::Pointer(int)]] DuplicatePointer{};
+
+class [[gsl::Owner(void)]] OwnerVoidDerefType{};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Owner'}}
+class [[gsl::Pointer(void)]] PointerVoidDerefType{};
+// expected-error@-1 {{'void' is an invalid argument to attribute 'Pointer'}}
+
+class [[gsl::Owner(int)]] AnOwner{};
+class [[gsl::Pointer(S)]] APointer{};
+
+class AddOwnerLater {};
+class [[gsl::Owner(int)]] AddOwnerLater;
+
+class [[gsl::Pointer(int)]] AddConflictLater{};
+class [[gsl::Owner(int)]] AddConflictLater;
+// expected-error@-1 {{'Owner' and 'Pointer' attributes are not compatible}}
+// expected-note@-3 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] AddConflictLater2{};
+class [[gsl::Owner(float)]] AddConflictLater2;
+// expected-error@-1 {{'Owner' and 'Owner' attributes are not compatible}}
+// expected-note@-3 {{conflicting attribute is here}}
+
+class [[gsl::Owner(int)]] AddTheSameLater{};
+class [[gsl::Owner(int)]] AddTheSameLater;
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -116,8 +116,10 @@
 // CHECK-NEXT: OpenCLNoSVM (SubjectMatchRule_variable)
 // CHECK-NEXT: OptimizeNone (SubjectMatchRule_function, SubjectMatchRule_objc_method)
 // CHECK-NEXT: Overloadable (SubjectMatchRule_function)
+// CHECK-NEXT: Owner (SubjectMatchRule_record)
 // CHECK-NEXT: ParamTypestate (SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: Pointer (SubjectMatchRule_record)
 // CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function)
 // CHECK-NEXT: ReqdWorkGroupSize (SubjectMatchRule_function)
 // CHECK-NEXT: RequireConstantInit (SubjectMatchRule_variable_is_global)
Index: clang/test/AST/ast-dump-attr.cpp
===
--- clang/test/AST/ast-dump-attr.cpp
+++ clang/test/AST/ast-dump-attr.cpp
@@ -211,6 +211,15 @@
 }
 }
 
+namespace TestLifetimeCategories {
+class [[gsl::Owner(int)]] AOwner{};
+// CHECK: CXXRecordDecl{{.*}} class AOwner
+// CHECK: OwnerAttr {{.*}} int
+class [[gsl::Pointer(int)]] APointer{};
+// CHECK: CXXRecordDecl{{.*}} class APointer
+// CHECK: PointerAttr {{.*}} int
+} // namespace TestLifetimeCategories
+
 // Verify the order of attributes in the Ast. It must reflect the order
 // in the parsed source.
 int mergeAttrTest() __attribute__((deprecated)) __attribute__((warn_unused_result));
Index: clang/lib/Sema/SemaDeclAttr.cpp
===
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAtt

[PATCH] D61749: [clang-tidy] initial version of readability-static-const-method

2019-07-02 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

Friendly ping. Are there outstanding concerns that I could address?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61749/new/

https://reviews.llvm.org/D61749



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


[PATCH] D61749: [clang-tidy] initial version of readability-static-const-method

2019-07-08 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 208505.
mgehre marked 11 inline comments as done.
mgehre added a comment.

- Address review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61749/new/

https://reviews.llvm.org/D61749

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/StaticMethodCheck.cpp
  clang-tools-extra/clang-tidy/readability/StaticMethodCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability-static-method.rst
  clang-tools-extra/test/clang-tidy/readability-static-method.cpp

Index: clang-tools-extra/test/clang-tidy/readability-static-method.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/readability-static-method.cpp
@@ -0,0 +1,195 @@
+// RUN: %check_clang_tidy %s readability-static-method %t
+
+class DoNotMakeEmptyStatic {
+  void emptyMethod() {}
+  void empty_method_out_of_line();
+};
+
+void DoNotMakeEmptyStatic::empty_method_out_of_line() {}
+
+class A {
+  int field;
+  const int const_field;
+  static int static_field;
+
+  void no_use() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'no_use' can be made static
+// CHECK-FIXES: {{^}}  static void no_use() {
+int i = 1;
+  }
+
+  int read_field() {
+return field;
+  }
+
+  void write_field() {
+field = 1;
+  }
+
+  int call_non_const_member() { return read_field(); }
+
+  int call_static_member() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'call_static_member' can be made static
+// CHECK-FIXES: {{^}}  static int call_static_member() {
+already_static();
+  }
+
+  int read_static() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_static' can be made static
+// CHECK-FIXES: {{^}}  static int read_static() {
+return static_field;
+  }
+  void write_static() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'write_static' can be made static
+// CHECK-FIXES: {{^}}  static void write_static() {
+static_field = 1;
+  }
+
+  static int already_static() { return static_field; }
+
+  int already_const() const { return field; }
+
+  int already_const_convert_to_static() const {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'already_const_convert_to_static' can be made static
+// CHECK-FIXES: {{^}}  static int already_const_convert_to_static() {
+return static_field;
+  }
+
+  static int out_of_line_already_static();
+
+  void out_of_line_call_static();
+  // CHECK-FIXES: {{^}}  static void out_of_line_call_static();
+  int out_of_line_const_to_static() const;
+  // CHECK-FIXES: {{^}}  static int out_of_line_const_to_static() ;
+};
+
+int A::out_of_line_already_static() { return 0; }
+
+void A::out_of_line_call_static() {
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: method 'out_of_line_call_static' can be made static
+  // CHECK-FIXES: {{^}}void A::out_of_line_call_static() {
+  already_static();
+}
+
+int A::out_of_line_const_to_static() const {
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'out_of_line_const_to_static' can be made static
+  // CHECK-FIXES: {{^}}int A::out_of_line_const_to_static() {
+  return 0;
+}
+
+struct KeepVirtual {
+  virtual int f() { return 0; }
+  virtual int h() const { return 0; }
+};
+
+struct KeepVirtualDerived : public KeepVirtual {
+  int f() { return 0; }
+  int h() const override { return 0; }
+};
+
+// Don't add 'static' to special member functions and operators.
+struct KeepSpecial {
+  KeepSpecial() { int L = 0; }
+  ~KeepSpecial() { int L = 0; }
+  int operator+() { return 0; }
+  operator int() { return 0; }
+};
+
+void KeepLambdas() {
+  using FT = int (*)();
+  auto F = static_cast([]() { return 0; });
+  auto F2 = []() { return 0; };
+}
+
+template 
+struct KeepWithTemplateBase : public Base {
+  int i;
+  // We cannot make these methods static because they might need to override
+  // a function from Base.
+  int static_f() { return 0; }
+};
+
+template 
+struct KeepTemplateClass {
+  int i;
+  // We cannot make these methods static because a specialization
+  // might use *this differently.
+  int static_f() { return 0; }
+};
+
+struct KeepTemplateMethod {
+  int i;
+  // We cannot make these methods static because a specialization
+  // might use *this differently.
+  template 
+  static int static_f() { return 0; }
+};
+
+void instantiate() {
+  struct S {};
+  KeepWithTemplateBase I1;
+  I1.static_f();
+
+  KeepTemplateClass I2;
+  I2.static_f();
+
+  KeepTemplateMethod I3;
+  I3.static_f();
+}
+
+struct Trailing {
+  auto g() const -> int {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'g' can be made static
+// CHECK-FIXES: {{^}}  static auto g() -> int {
+return 0;
+  }
+
+  void vol() volatile {
+// CHECK-MESS

[PATCH] D61749: [clang-tidy] initial version of readability-static-const-method

2019-07-08 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked 2 inline comments as done.
mgehre added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp:96
+CheckFactories.registerCheck(
+"readability-static-method");
 CheckFactories.registerCheck(

aaron.ballman wrote:
> I'm not super keen on the check name. It's not very descriptive -- does this 
> operate on static methods, does it make methods static, does it turn global 
> dynamic initialization into static method initialization?
> 
> How about: `readability-convert-functions-to-static` or something more 
> descriptive of the functionality?
I agree that we should find a better name. With 
`readability-convert-functions-to-static`, I miss the difference between adding 
`static` linkage to a free function versus making a member function static.
How about `readability-convert-member-functions-to-static` or 
`readability-convert-method-to-static`?



Comment at: clang-tools-extra/clang-tidy/readability/StaticMethodCheck.cpp:25
+public:
+  FindUsageOfThis() {}
+  bool Used = false;

aaron.ballman wrote:
> Do you need this constructor at all? If so, `= default;` it.
Removed



Comment at: clang-tools-extra/clang-tidy/readability/StaticMethodCheck.cpp:28-31
+  bool VisitCXXThisExpr(const CXXThisExpr *E) {
+Used = true;
+return false; // Stop traversal.
+  }

aaron.ballman wrote:
> Does this find a usage of `this` in unevaluated contexts? e.g.,
> ```
> struct S {
>   size_t derp() { return sizeof(this); }
> };
> ```
> I am hoping the answer is yes, because we wouldn't want to convert that into 
> a static function. Probably worth a test.
I added a test



Comment at: clang-tools-extra/clang-tidy/readability/StaticMethodCheck.cpp:56-57
+  const LangOptions &LangOpts) {
+  if (!TSI)
+return {};
+  FunctionTypeLoc FTL =

aaron.ballman wrote:
> Under what circumstances can this happen?
I will check



Comment at: 
clang-tools-extra/clang-tidy/readability/StaticMethodCheck.cpp:136-149
+  if (Definition->isConst()) {
+// Make sure that we either remove 'const' on both declaration and
+// definition or emit no fix-it at all.
+SourceRange DefConst = getLocationOfConst(Definition->getTypeSourceInfo(),
+   *Result.SourceManager,
+   Result.Context->getLangOpts());
+

aaron.ballman wrote:
> `const` isn't the only thing to worry about though, no? You need to handle 
> things like:
> ```
> struct S {
>   void f() volatile;
>   void g() &;
>   void h() &&;
> };
> ```
> Another one I am curious about are computed noexcept specifications and 
> whether those are handled properly. e.g.,
> ```
> struct S {
>   int i;
>   void foo(SomeClass C) noexcept(noexcept(C + i));
> };
> ```
I added tests for those cases and disabled fix-it generation for them to keep 
the code simple (for now).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61749/new/

https://reviews.llvm.org/D61749



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


[PATCH] D61749: [clang-tidy] initial version of readability-static-const-method

2019-07-09 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 208785.
mgehre added a comment.

Move checks into AST matchers


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61749/new/

https://reviews.llvm.org/D61749

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/StaticMethodCheck.cpp
  clang-tools-extra/clang-tidy/readability/StaticMethodCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability-static-method.rst
  clang-tools-extra/test/clang-tidy/readability-static-method.cpp

Index: clang-tools-extra/test/clang-tidy/readability-static-method.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/readability-static-method.cpp
@@ -0,0 +1,195 @@
+// RUN: %check_clang_tidy %s readability-static-method %t
+
+class DoNotMakeEmptyStatic {
+  void emptyMethod() {}
+  void empty_method_out_of_line();
+};
+
+void DoNotMakeEmptyStatic::empty_method_out_of_line() {}
+
+class A {
+  int field;
+  const int const_field;
+  static int static_field;
+
+  void no_use() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'no_use' can be made static
+// CHECK-FIXES: {{^}}  static void no_use() {
+int i = 1;
+  }
+
+  int read_field() {
+return field;
+  }
+
+  void write_field() {
+field = 1;
+  }
+
+  int call_non_const_member() { return read_field(); }
+
+  int call_static_member() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'call_static_member' can be made static
+// CHECK-FIXES: {{^}}  static int call_static_member() {
+already_static();
+  }
+
+  int read_static() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_static' can be made static
+// CHECK-FIXES: {{^}}  static int read_static() {
+return static_field;
+  }
+  void write_static() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'write_static' can be made static
+// CHECK-FIXES: {{^}}  static void write_static() {
+static_field = 1;
+  }
+
+  static int already_static() { return static_field; }
+
+  int already_const() const { return field; }
+
+  int already_const_convert_to_static() const {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'already_const_convert_to_static' can be made static
+// CHECK-FIXES: {{^}}  static int already_const_convert_to_static() {
+return static_field;
+  }
+
+  static int out_of_line_already_static();
+
+  void out_of_line_call_static();
+  // CHECK-FIXES: {{^}}  static void out_of_line_call_static();
+  int out_of_line_const_to_static() const;
+  // CHECK-FIXES: {{^}}  static int out_of_line_const_to_static() ;
+};
+
+int A::out_of_line_already_static() { return 0; }
+
+void A::out_of_line_call_static() {
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: method 'out_of_line_call_static' can be made static
+  // CHECK-FIXES: {{^}}void A::out_of_line_call_static() {
+  already_static();
+}
+
+int A::out_of_line_const_to_static() const {
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'out_of_line_const_to_static' can be made static
+  // CHECK-FIXES: {{^}}int A::out_of_line_const_to_static() {
+  return 0;
+}
+
+struct KeepVirtual {
+  virtual int f() { return 0; }
+  virtual int h() const { return 0; }
+};
+
+struct KeepVirtualDerived : public KeepVirtual {
+  int f() { return 0; }
+  int h() const override { return 0; }
+};
+
+// Don't add 'static' to special member functions and operators.
+struct KeepSpecial {
+  KeepSpecial() { int L = 0; }
+  ~KeepSpecial() { int L = 0; }
+  int operator+() { return 0; }
+  operator int() { return 0; }
+};
+
+void KeepLambdas() {
+  using FT = int (*)();
+  auto F = static_cast([]() { return 0; });
+  auto F2 = []() { return 0; };
+}
+
+template 
+struct KeepWithTemplateBase : public Base {
+  int i;
+  // We cannot make these methods static because they might need to override
+  // a function from Base.
+  int static_f() { return 0; }
+};
+
+template 
+struct KeepTemplateClass {
+  int i;
+  // We cannot make these methods static because a specialization
+  // might use *this differently.
+  int static_f() { return 0; }
+};
+
+struct KeepTemplateMethod {
+  int i;
+  // We cannot make these methods static because a specialization
+  // might use *this differently.
+  template 
+  static int static_f() { return 0; }
+};
+
+void instantiate() {
+  struct S {};
+  KeepWithTemplateBase I1;
+  I1.static_f();
+
+  KeepTemplateClass I2;
+  I2.static_f();
+
+  KeepTemplateMethod I3;
+  I3.static_f();
+}
+
+struct Trailing {
+  auto g() const -> int {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'g' can be made static
+// CHECK-FIXES: {{^}}  static auto g() -> int {
+return 0;
+  }
+
+  void vol() volatile {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 

[PATCH] D64448: gsl::Owner/gsl::Pointer: Add implicit annotations for some std types

2019-07-09 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre created this revision.
mgehre added reviewers: gribozavr, xazax.hun.
Herald added a subscriber: rnkovacs.
Herald added a project: clang.

Make the DerefType, i.e. the argument of gsl::Owner/gsl::Pointer optional for 
now.

The DerefType is used when infering lifetime annotations of functions, e.g.
how a return value can relate to the arguments. Our initial checks should
work without that kind of inference and instead use explicit annotations,
so we don't need the DerefType right now.
And having it optional makes the implicit/default annotations for std:: types
easier to implement. I think the DerefType is also optional in the current MSVC
implementation.

This seems to be the first attribute that has an optional Type argument,
so I needed to fix two thinks in tablegen:

- Don't crash AST dump when Owner/Pointer has no Type argument
- Don't crash when pretty-printing an Attribute with optional type argument

Add __is_gsl_owner/__is_gsl_pointer builtins. They are very useful to test
if the annotations have been attached correctly.

Hard code gsl::Owner/gsl::Pointer for std types. The paper mentions
some types explicitly. Generally, all containers and their iterators are
covered. For iterators, we cover both the case that they are defined
as an nested class or as an typedef/using. I have started to test this
implementation against some real standard library implementations, namely
libc++ 7.1.0, libc++ 8.0.1rc2, libstdc++ 4.6.4, libstdc++ 4.8.5,
libstdc++ 4.9.4, libstdc++ 5.4.0, libstdc++ 6.5.0, libstdc++ 7.3.0,
libstdc++ 8.3.0 and libstdc++ 9.1.0.

The tests are currently here

  https://github.com/mgehre/llvm-project/blob/lifetime-ci/lifetime-attr-test.sh
  https://github.com/mgehre/llvm-project/blob/lifetime-ci/lifetime-attr-test.cpp

I think due to their dependency on a standard library, they are not a good fit
for clang/test/. Where else could I put them?


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D64448

Files:
  clang/docs/LanguageExtensions.rst
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/TokenKinds.def
  clang/include/clang/Basic/TypeTraits.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaAttr.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/test/AST/ast-dump-attr.cpp
  clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
  clang/utils/TableGen/ClangAttrEmitter.cpp

Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -303,6 +303,8 @@
 std::string getIsOmitted() const override {
   if (type == "IdentifierInfo *")
 return "!get" + getUpperName().str() + "()";
+  if (type == "TypeSourceInfo *")
+return "!get" + getUpperName().str() + "Loc()";
   if (type == "ParamIdx")
 return "!get" + getUpperName().str() + "().isValid()";
   return "false";
@@ -336,6 +338,8 @@
<< "  OS << \" \" << SA->get" << getUpperName()
<< "()->getName();\n";
   } else if (type == "TypeSourceInfo *") {
+if (isOptional())
+  OS << "if (SA->get" << getUpperName() << "Loc())";
 OS << "OS << \" \" << SA->get" << getUpperName()
<< "().getAsString();\n";
   } else if (type == "bool") {
Index: clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
===
--- clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
+++ clang/test/SemaCXX/attr-gsl-owner-pointer.cpp
@@ -10,14 +10,15 @@
 
 struct S {
 };
+static_assert(!__is_gsl_owner(S), "");
+static_assert(!__is_gsl_pointer(S), "");
 
 S [[gsl::Owner]] Instance;
 // expected-error@-1 {{'Owner' attribute cannot be applied to types}}
 
 class [[gsl::Owner]] OwnerMissingParameter{};
-// expected-error@-1 {{'Owner' attribute takes one argument}}
+
 class [[gsl::Pointer]] PointerMissingParameter{};
-// expected-error@-1 {{'Pointer' attribute takes one argument}}
 
 class [[gsl::Owner(7)]] OwnerDerefNoType{};
 // expected-error@-1 {{expected a type}} expected-error@-1 {{expected ')'}}
@@ -32,8 +33,12 @@
 // expected-note@-2 {{conflicting attribute is here}}
 
 class [[gsl::Owner(int)]] [[gsl::Owner(int)]] DuplicateOwner{};
+static_assert(__is_gsl_owner(DuplicateOwner), "");
+static_assert(!__is_gsl_pointer(DuplicateOwner), "");
 
 class [[gsl::Pointer(int)]] [[gsl::Pointer(int)]] DuplicatePointer{};
+static_assert(!__is_gsl_owner(DuplicatePointer), "");
+static_assert(__is_gsl_pointer(DuplicatePointer), "");
 
 class [[gsl::Owner(void)]] OwnerVoidDerefType{};
 // expected-error@-1 {{'void' is an invalid argument to attribute 'Owner'}}
@@ -41,7 +46,12 @@
 // expected-error@-1 {{'void' is an invalid argument to attribute 'Pointer'}}
 
 class [[gsl::Ow

[PATCH] D61749: [clang-tidy] initial version of readability-static-const-method

2019-05-10 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

I have thought about splitting the check into separate `static` & `const`, but 
kept it together because
the analysis for both cases is very similar, i.e. finding the usage of `this`.

Also, both checks share many preconditions, e.g. not applying them to virtual 
methods or methods
on class with a template base class, not applying them to constructor, not 
applying them to operators, etc
(and those preconditons are not shared with D54943 
).

I had a look at D54943 . Nice change! It will 
be very valuable to have the `const` analysis for variables!
Note, though, that the hard part of of making methods
`const` is not the detailed usage analysis as its done by the 
`ExprMutationAnalyzer`. Instead, the hard part
is to avoid false-positives that make the check unusable.
I had a version of this check that made a very detailed analysis just like 
`ExprMutationAnalyzer`
(restricted to `this`). But then most of the functions it flagged as `const`
(technically correct) on the LLVM code base we would not want to make const 
(logically). Examples:

  class S {
// Technically const (the pointer Pimp itself is not modified), but 
logically should not be const
//  because we want to consider *Pimp as part of the data.
void setFlag() {
  *Pimp = 4;
}
  
int* Pimp;
  };



  class S {
void modify() {
   // Technically const because we call a const method
  // "pointer unique_ptr::operator->() const;"
  // but logically not const.
  U->modify();
}
  
std::unique_ptr U;
  };



  // Real-world code, see clang::ObjCInterfaceDecl.
  class DataPattern {
int& data() const;
  public:
  
int& get() { // Must not be const, even though it only calls const methods
  return data();
}
  
const int& get() const {
  return const_cast(this)->get();
}
  
void set() { // Must not be const, even though it only calls const methods
  data() = 42;
}
  };

and many more.

So the hard thing for the `const` check was to actually remove the 
sophisticated analysis I had, and come up with
something much simpler that would have no false positive (otherwise users will 
just disable the check) while
still finding something. I fear that the same could happen when we apply D54943 
 to `this` directly. It might
be easier to keep those two cases separate.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61749/new/

https://reviews.llvm.org/D61749



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


[PATCH] D61749: [clang-tidy] initial version of readability-static-const-method

2019-05-12 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked 2 inline comments as done.
mgehre added inline comments.



Comment at: 
clang-tools-extra/test/clang-tidy/readability-static-const-method.cpp:209
+void KeepLambdas() {
+  auto F = +[]() { return 0; };
+  auto F2 = []() { return 0; };

JonasToth wrote:
> Does it pass here?
> I looks a bit weird, shouldnt the lambda be called for this to work (this is 
> the unary + right?)?
https://stackoverflow.com/questions/18889028/a-positive-lambda-what-sorcery-is-this



Comment at: 
clang-tools-extra/test/clang-tidy/readability-static-const-method.cpp:312
+return const_cast(this)->get();
+  }
+

JonasToth wrote:
> I think more template tests wouldn't hurt. From the other checks experience I 
> can safely say we got burned a few times :)
> Instantiating the templates with builtin arrays, pointers, references and 
> different qualifiers usually produces interesting test cases as well, that 
> need to be handled properly.
> 
> Another thing that comes to mind with templates are overloaded operators.
> ```
> template 
> void bar() {
>  Foo x1, x2;
>  Foo y = x1 + x2;
> }
> ```
> Builtins are not changed by `operator+` but that can not be said about other 
> types in general (maybe with concepts used properly).
The check only checks templates instantiations (so we will see no template 
parameters, just ordinary types). The plus here will be be function call in the 
AST of the instantiation when Foo has an overloaded operator+.
The current version will never propose to make bar() const when a method on 
`this` is called.
I can add the test to show this.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61749/new/

https://reviews.llvm.org/D61749



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


[PATCH] D61700: [clang-tidy] readability-redundant-declaration: fix false positive with C "extern inline"

2019-05-13 Thread Matthias Gehre via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
mgehre marked 2 inline comments as done.
Closed by commit rL360613: [clang-tidy] readability-redundant-declaration: fix 
false positive with C… (authored by mgehre, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D61700?vs=198724&id=199306#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61700/new/

https://reviews.llvm.org/D61700

Files:
  clang-tools-extra/trunk/clang-tidy/readability/RedundantDeclarationCheck.cpp
  clang-tools-extra/trunk/test/clang-tidy/readability-redundant-declaration.c
  clang-tools-extra/trunk/test/clang-tidy/readability-redundant-declaration.cpp


Index: 
clang-tools-extra/trunk/clang-tidy/readability/RedundantDeclarationCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/readability/RedundantDeclarationCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/readability/RedundantDeclarationCheck.cpp
@@ -17,6 +17,10 @@
 namespace tidy {
 namespace readability {
 
+AST_MATCHER(FunctionDecl, doesDeclarationForceExternallyVisibleDefinition) {
+  return Node.doesDeclarationForceExternallyVisibleDefinition();
+}
+
 RedundantDeclarationCheck::RedundantDeclarationCheck(StringRef Name,
  ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context),
@@ -25,8 +29,10 @@
 void RedundantDeclarationCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
   namedDecl(anyOf(varDecl(unless(isDefinition())),
-  functionDecl(unless(anyOf(isDefinition(), isDefaulted(),
-hasParent(friendDecl()))
+  functionDecl(unless(anyOf(
+  isDefinition(), isDefaulted(),
+  doesDeclarationForceExternallyVisibleDefinition(),
+  hasParent(friendDecl()))
   .bind("Decl"),
   this);
 }
Index: 
clang-tools-extra/trunk/test/clang-tidy/readability-redundant-declaration.c
===
--- clang-tools-extra/trunk/test/clang-tidy/readability-redundant-declaration.c
+++ clang-tools-extra/trunk/test/clang-tidy/readability-redundant-declaration.c
@@ -0,0 +1,31 @@
+// RUN: %check_clang_tidy %s readability-redundant-declaration %t
+
+extern int Xyz;
+extern int Xyz; // Xyz
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant 'Xyz' declaration 
[readability-redundant-declaration]
+// CHECK-FIXES: {{^}}// Xyz{{$}}
+int Xyz = 123;
+
+extern int A;
+extern int A, B;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant 'A' declaration
+// CHECK-FIXES: {{^}}extern int A, B;{{$}}
+
+extern int Buf[10];
+extern int Buf[10]; // Buf[10]
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant 'Buf' declaration
+// CHECK-FIXES: {{^}}// Buf[10]{{$}}
+
+static int f();
+static int f(); // f
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant 'f' declaration
+// CHECK-FIXES: {{^}}// f{{$}}
+static int f() {}
+
+inline void g() {}
+
+inline void g();
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant 'g' declaration
+
+// OK: Needed to emit an external definition.
+extern inline void g();
Index: 
clang-tools-extra/trunk/test/clang-tidy/readability-redundant-declaration.cpp
===
--- 
clang-tools-extra/trunk/test/clang-tidy/readability-redundant-declaration.cpp
+++ 
clang-tools-extra/trunk/test/clang-tidy/readability-redundant-declaration.cpp
@@ -68,3 +68,13 @@
 // CHECK-FIXES: {{^}}DEFINE(test);{{$}}
 
 } // namespace macros
+
+inline void g() {}
+
+inline void g(); // g
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant 'g' declaration
+// CHECK-FIXES: {{^}}// g{{$}}
+
+extern inline void g(); // extern g
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: redundant 'g' declaration
+// CHECK-FIXES: {{^}}// extern g{{$}}


Index: clang-tools-extra/trunk/clang-tidy/readability/RedundantDeclarationCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/readability/RedundantDeclarationCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/readability/RedundantDeclarationCheck.cpp
@@ -17,6 +17,10 @@
 namespace tidy {
 namespace readability {
 
+AST_MATCHER(FunctionDecl, doesDeclarationForceExternallyVisibleDefinition) {
+  return Node.doesDeclarationForceExternallyVisibleDefinition();
+}
+
 RedundantDeclarationCheck::RedundantDeclarationCheck(StringRef Name,
  ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context),
@@ -25,8 +29,10 @@
 void RedundantDeclarationCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
   namedDecl(anyOf(varDecl(unless(isDefinition())),
-  f

[PATCH] D24892: [clang-tidy] Add option "LiteralInitializers" to cppcoreguidelines-pro-type-member-init

2019-05-13 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

Do I wait for @alexfh to turn his red into a green, too?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D24892/new/

https://reviews.llvm.org/D24892



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


[PATCH] D61749: [clang-tidy] initial version of readability-static-const-method

2019-05-13 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked 17 inline comments as done.
mgehre added inline comments.



Comment at: 
clang-tools-extra/test/clang-tidy/readability-static-const-method.cpp:312
+return const_cast(this)->get();
+  }
+

JonasToth wrote:
> mgehre wrote:
> > JonasToth wrote:
> > > I think more template tests wouldn't hurt. From the other checks 
> > > experience I can safely say we got burned a few times :)
> > > Instantiating the templates with builtin arrays, pointers, references and 
> > > different qualifiers usually produces interesting test cases as well, 
> > > that need to be handled properly.
> > > 
> > > Another thing that comes to mind with templates are overloaded operators.
> > > ```
> > > template 
> > > void bar() {
> > >  Foo x1, x2;
> > >  Foo y = x1 + x2;
> > > }
> > > ```
> > > Builtins are not changed by `operator+` but that can not be said about 
> > > other types in general (maybe with concepts used properly).
> > The check only checks templates instantiations (so we will see no template 
> > parameters, just ordinary types). The plus here will be be function call in 
> > the AST of the instantiation when Foo has an overloaded operator+.
> > The current version will never propose to make bar() const when a method on 
> > `this` is called.
> > I can add the test to show this.
> Yes please add a test to show they are not analyzed.
I will now restrict this PR to the `static` part of the check, and I fail to 
come up with an example where operators could make a static looking function 
non-static.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61749/new/

https://reviews.llvm.org/D61749



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


[PATCH] D61749: [clang-tidy] initial version of readability-static-const-method

2019-05-13 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 199329.
mgehre marked an inline comment as done.
mgehre added a comment.

Remove ``const`` part from this PR. Address comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61749/new/

https://reviews.llvm.org/D61749

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/StaticMethodCheck.cpp
  clang-tools-extra/clang-tidy/readability/StaticMethodCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability-static-method.rst
  clang-tools-extra/test/clang-tidy/readability-static-method.cpp

Index: clang-tools-extra/test/clang-tidy/readability-static-method.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/readability-static-method.cpp
@@ -0,0 +1,174 @@
+// RUN: %check_clang_tidy %s readability-static-method %t
+
+class DoNotMakeEmptyStatic {
+  void emptyMethod() {}
+  void empty_method_out_of_line();
+};
+
+void DoNotMakeEmptyStatic::empty_method_out_of_line() {}
+
+class A {
+  int field;
+  const int const_field;
+  static int static_field;
+
+  void no_use() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'no_use' can be made static
+// CHECK-FIXES: {{^}}  static void no_use() {
+int i = 1;
+  }
+
+  int read_field() {
+return field;
+  }
+
+  void write_field() {
+field = 1;
+  }
+
+  int call_non_const_member() { return read_field(); }
+
+  int call_static_member() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'call_static_member' can be made static
+// CHECK-FIXES: {{^}}  static int call_static_member() {
+already_static();
+  }
+
+  int read_static() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_static' can be made static
+// CHECK-FIXES: {{^}}  static int read_static() {
+return static_field;
+  }
+  void write_static() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'write_static' can be made static
+// CHECK-FIXES: {{^}}  static void write_static() {
+static_field = 1;
+  }
+
+  static int already_static() { return static_field; }
+
+  int already_const() const { return field; }
+
+  int already_const_convert_to_static() const {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'already_const_convert_to_static' can be made static
+// CHECK-FIXES: {{^}}  static int already_const_convert_to_static() {
+return static_field;
+  }
+
+  static int out_of_line_already_static();
+
+  void out_of_line_call_static();
+  // CHECK-FIXES: {{^}}  static void out_of_line_call_static();
+  int out_of_line_const_to_static() const;
+  // CHECK-FIXES: {{^}}  static int out_of_line_const_to_static() ;
+};
+
+int A::out_of_line_already_static() { return 0; }
+
+void A::out_of_line_call_static() {
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: method 'out_of_line_call_static' can be made static
+  // CHECK-FIXES: {{^}}void A::out_of_line_call_static() {
+  already_static();
+}
+
+int A::out_of_line_const_to_static() const {
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'out_of_line_const_to_static' can be made static
+  // CHECK-FIXES: {{^}}int A::out_of_line_const_to_static() {
+  return 0;
+}
+
+struct KeepVirtual {
+  virtual int f() { return 0; }
+  virtual int h() const { return 0; }
+};
+
+struct KeepVirtualDerived : public KeepVirtual {
+  int f() { return 0; }
+  int h() const override { return 0; }
+};
+
+// Don't add 'static' to special member functions and operators.
+struct KeepSpecial {
+  KeepSpecial() { int L = 0; }
+  ~KeepSpecial() { int L = 0; }
+  int operator+() { return 0; }
+  operator int() { return 0; }
+};
+
+void KeepLambdas() {
+  auto F = +[]() { return 0; };
+  auto F2 = []() { return 0; };
+}
+
+template 
+struct KeepWithTemplateBase : public Base {
+  int i;
+  // We cannot make these methods static because they might need to override
+  // a function from Base.
+  int static_f() { return 0; }
+};
+
+template 
+struct KeepTemplateClass {
+  int i;
+  // We cannot make these methods static because a specialization
+  // might use *this differently.
+  int static_f() { return 0; }
+};
+
+struct KeepTemplateMethod {
+  int i;
+  // We cannot make these methods static because a specialization
+  // might use *this differently.
+  template 
+  static int static_f() { return 0; }
+};
+
+void instantiate() {
+  struct S {};
+  KeepWithTemplateBase I1;
+  I1.static_f();
+
+  KeepTemplateClass I2;
+  I2.static_f();
+
+  KeepTemplateMethod I3;
+  I3.static_f();
+}
+
+struct TrailingReturn {
+  auto g() const -> int {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'g' can be made static
+// CHECK-FIXES: {{^}}  static auto g() -> int {
+return 0;
+  }
+};
+
+struct NoFixitInMacro {
+#define CONST con

[PATCH] D24892: [clang-tidy] Add option "LiteralInitializers" to cppcoreguidelines-pro-type-member-init

2019-05-13 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 199330.
mgehre added a comment.

Fix wrong merge of ReleaseNotes


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D24892/new/

https://reviews.llvm.org/D24892

Files:
  clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
  clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst
  
clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-use-assignment.cpp

Index: clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-use-assignment.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-use-assignment.cpp
@@ -0,0 +1,40 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -config="{CheckOptions: [{key: "cppcoreguidelines-pro-type-member-init.UseAssignment", value: 1}]}" -- -std=c++11
+
+struct T {
+  int i;
+};
+
+struct S {
+  bool b;
+  // CHECK-FIXES: bool b = false;
+  char c;
+  // CHECK-FIXES: char c = 0;
+  signed char sc;
+  // CHECK-FIXES: signed char sc = 0;
+  unsigned char uc;
+  // CHECK-FIXES: unsigned char uc = 0U;
+  int i;
+  // CHECK-FIXES: int i = 0;
+  unsigned u;
+  // CHECK-FIXES: unsigned u = 0U;
+  long l;
+  // CHECK-FIXES: long l = 0L;
+  unsigned long ul;
+  // CHECK-FIXES: unsigned long ul = 0UL;
+  long long ll;
+  // CHECK-FIXES: long long ll = 0LL;
+  unsigned long long ull;
+  // CHECK-FIXES: unsigned long long ull = 0ULL;
+  float f;
+  // CHECK-FIXES: float f = 0.0F;
+  double d;
+  // CHECK-FIXES: double d = 0.0;
+  long double ld;
+  // CHECK-FIXES: double ld = 0.0L;
+  int *ptr;
+  // CHECK-FIXES: int *ptr = nullptr;
+  T t;
+  // CHECK-FIXES: T t{};
+  S() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields:
+};
Index: clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst
===
--- clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst
+++ clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst
@@ -33,6 +33,10 @@
zero-initialized during construction. For performance critical code, it may
be important to not initialize fixed-size array members. Default is `0`.
 
+.. option:: UseAssignment
+   If set to non-zero, the check will provide fix-its with literal initializers
+   (``int i = 0;``) instead of curly braces (``int i{};``).
+
 This rule is part of the "Type safety" profile of the C++ Core
 Guidelines, corresponding to rule Type.6. See
 https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-type-memberinit.
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -163,6 +163,11 @@
 
   Rewrites function signatures to use a trailing return type.
 
+- Added `UseAssignment` option to :doc:`cppcoreguidelines-pro-type-member-init`
+
+  If set to true, the check will provide fix-its with literal initializers
+  (``int i = 0;``) instead of curly braces (``int i{};``).
+
 Improvements to include-fixer
 -
 
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
===
--- clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
@@ -64,6 +64,11 @@
 
   // Whether arrays need to be initialized or not. Default is false.
   bool IgnoreArrays;
+
+  // Whether fix-its for initialization of fundamental type use assignment
+  // instead of brace initalization. Only effective in C++11 mode. Default is
+  // false.
+  bool UseAssignment;
 };
 
 } // namespace cppcoreguidelines
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
===
--- clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
@@ -250,7 +250,8 @@
 ProTypeMemberInitCheck::ProTypeMemberInitCheck(StringRef Name,
ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context),
-  IgnoreArrays(Options.get("IgnoreArrays", false)) {}
+  IgnoreArrays(Options.get("IgnoreArrays", false)),
+  UseAssignment(Options.getLocalOrGlobal("UseAssignment", false)) {}
 
 void ProTypeMemberInitCheck::registerMatchers(MatchFinder *Finder) {
   if (!getLangOpts().CPlusPlus)
@@ -314,6 +315,7 @@
 
 void ProTypeMemberInitCheck::st

[PATCH] D61874: [clang-tidy] Fix invalid fixit for readability-static-accessed-through-instance (bug 40544)

2019-05-13 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre created this revision.
mgehre added reviewers: aaron.ballman, alexfh, xazax.hun.
mgehre added projects: clang, clang-tools-extra.
Herald added a subscriber: rnkovacs.

Fixed https://bugs.llvm.org/show_bug.cgi?id=40544
Before, we would generate a fixit like `(anonymous namespace)::Foo::fun();` for
the added test case.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D61874

Files:
  
clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
  
clang-tools-extra/test/clang-tidy/readability-static-accessed-through-instance.cpp


Index: 
clang-tools-extra/test/clang-tidy/readability-static-accessed-through-instance.cpp
===
--- 
clang-tools-extra/test/clang-tidy/readability-static-accessed-through-instance.cpp
+++ 
clang-tools-extra/test/clang-tidy/readability-static-accessed-through-instance.cpp
@@ -220,3 +220,31 @@
   qp->y = 10; // OK, the overloaded operator might have side-effects.
   qp->K = 10; //
 }
+
+namespace {
+  struct Anonymous {
+static int I;
+  };
+}
+
+void use_anonymous() {
+  Anonymous Anon;
+  Anon.I;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+  // CHECK-FIXES: {{^}}  Anonymous::I;{{$}}
+}
+
+namespace Outer {
+  inline namespace Inline {
+struct S {
+  static int I;
+};
+  }
+}
+
+void use_inline() {
+  Outer::S V;
+  V.I;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+  // CHECK-FIXES: {{^}}  Outer::S::I;{{$}}
+}
Index: 
clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
===
--- 
clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
+++ 
clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
@@ -67,6 +67,7 @@
   const ASTContext *AstContext = Result.Context;
   PrintingPolicy PrintingPolicyWithSupressedTag(AstContext->getLangOpts());
   PrintingPolicyWithSupressedTag.SuppressTagKeyword = true;
+  PrintingPolicyWithSupressedTag.SuppressUnwrittenScope = true;
   std::string BaseTypeName =
   BaseType.getAsString(PrintingPolicyWithSupressedTag);
 


Index: clang-tools-extra/test/clang-tidy/readability-static-accessed-through-instance.cpp
===
--- clang-tools-extra/test/clang-tidy/readability-static-accessed-through-instance.cpp
+++ clang-tools-extra/test/clang-tidy/readability-static-accessed-through-instance.cpp
@@ -220,3 +220,31 @@
   qp->y = 10; // OK, the overloaded operator might have side-effects.
   qp->K = 10; //
 }
+
+namespace {
+  struct Anonymous {
+static int I;
+  };
+}
+
+void use_anonymous() {
+  Anonymous Anon;
+  Anon.I;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+  // CHECK-FIXES: {{^}}  Anonymous::I;{{$}}
+}
+
+namespace Outer {
+  inline namespace Inline {
+struct S {
+  static int I;
+};
+  }
+}
+
+void use_inline() {
+  Outer::S V;
+  V.I;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+  // CHECK-FIXES: {{^}}  Outer::S::I;{{$}}
+}
Index: clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
@@ -67,6 +67,7 @@
   const ASTContext *AstContext = Result.Context;
   PrintingPolicy PrintingPolicyWithSupressedTag(AstContext->getLangOpts());
   PrintingPolicyWithSupressedTag.SuppressTagKeyword = true;
+  PrintingPolicyWithSupressedTag.SuppressUnwrittenScope = true;
   std::string BaseTypeName =
   BaseType.getAsString(PrintingPolicyWithSupressedTag);
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D61874: [clang-tidy] Fix invalid fixit for readability-static-accessed-through-instance (bug 40544)

2019-05-14 Thread Matthias Gehre via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL360698: [clang-tidy] Fix invalid fixit for 
readability-static-accessed-through-instance… (authored by mgehre, committed by 
).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D61874?vs=199333&id=199484#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61874/new/

https://reviews.llvm.org/D61874

Files:
  
clang-tools-extra/trunk/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
  
clang-tools-extra/trunk/test/clang-tidy/readability-static-accessed-through-instance.cpp


Index: 
clang-tools-extra/trunk/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
===
--- 
clang-tools-extra/trunk/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
+++ 
clang-tools-extra/trunk/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
@@ -67,6 +67,7 @@
   const ASTContext *AstContext = Result.Context;
   PrintingPolicy PrintingPolicyWithSupressedTag(AstContext->getLangOpts());
   PrintingPolicyWithSupressedTag.SuppressTagKeyword = true;
+  PrintingPolicyWithSupressedTag.SuppressUnwrittenScope = true;
   std::string BaseTypeName =
   BaseType.getAsString(PrintingPolicyWithSupressedTag);
 
Index: 
clang-tools-extra/trunk/test/clang-tidy/readability-static-accessed-through-instance.cpp
===
--- 
clang-tools-extra/trunk/test/clang-tidy/readability-static-accessed-through-instance.cpp
+++ 
clang-tools-extra/trunk/test/clang-tidy/readability-static-accessed-through-instance.cpp
@@ -220,3 +220,31 @@
   qp->y = 10; // OK, the overloaded operator might have side-effects.
   qp->K = 10; //
 }
+
+namespace {
+  struct Anonymous {
+static int I;
+  };
+}
+
+void use_anonymous() {
+  Anonymous Anon;
+  Anon.I;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+  // CHECK-FIXES: {{^}}  Anonymous::I;{{$}}
+}
+
+namespace Outer {
+  inline namespace Inline {
+struct S {
+  static int I;
+};
+  }
+}
+
+void use_inline() {
+  Outer::S V;
+  V.I;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+  // CHECK-FIXES: {{^}}  Outer::S::I;{{$}}
+}


Index: clang-tools-extra/trunk/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
@@ -67,6 +67,7 @@
   const ASTContext *AstContext = Result.Context;
   PrintingPolicy PrintingPolicyWithSupressedTag(AstContext->getLangOpts());
   PrintingPolicyWithSupressedTag.SuppressTagKeyword = true;
+  PrintingPolicyWithSupressedTag.SuppressUnwrittenScope = true;
   std::string BaseTypeName =
   BaseType.getAsString(PrintingPolicyWithSupressedTag);
 
Index: clang-tools-extra/trunk/test/clang-tidy/readability-static-accessed-through-instance.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/readability-static-accessed-through-instance.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/readability-static-accessed-through-instance.cpp
@@ -220,3 +220,31 @@
   qp->y = 10; // OK, the overloaded operator might have side-effects.
   qp->K = 10; //
 }
+
+namespace {
+  struct Anonymous {
+static int I;
+  };
+}
+
+void use_anonymous() {
+  Anonymous Anon;
+  Anon.I;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+  // CHECK-FIXES: {{^}}  Anonymous::I;{{$}}
+}
+
+namespace Outer {
+  inline namespace Inline {
+struct S {
+  static int I;
+};
+  }
+}
+
+void use_inline() {
+  Outer::S V;
+  V.I;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+  // CHECK-FIXES: {{^}}  Outer::S::I;{{$}}
+}
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D24892: [clang-tidy] Add option "LiteralInitializers" to cppcoreguidelines-pro-type-member-init

2019-05-23 Thread Matthias Gehre via Phabricator via cfe-commits
This revision was not accepted when it landed; it landed in state "Needs 
Review".
This revision was automatically updated to reflect the committed changes.
Closed by commit rL361601: [clang-tidy] Add option 
"LiteralInitializers" to cppcoreguidelines-pro-type… (authored by 
mgehre, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D24892?vs=199330&id=201127#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D24892/new/

https://reviews.llvm.org/D24892

Files:
  
clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
  clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
  clang-tools-extra/trunk/docs/ReleaseNotes.rst
  
clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst
  
clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-use-assignment.cpp

Index: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
@@ -250,7 +250,8 @@
 ProTypeMemberInitCheck::ProTypeMemberInitCheck(StringRef Name,
ClangTidyContext *Context)
 : ClangTidyCheck(Name, Context),
-  IgnoreArrays(Options.get("IgnoreArrays", false)) {}
+  IgnoreArrays(Options.get("IgnoreArrays", false)),
+  UseAssignment(Options.getLocalOrGlobal("UseAssignment", false)) {}
 
 void ProTypeMemberInitCheck::registerMatchers(MatchFinder *Finder) {
   if (!getLangOpts().CPlusPlus)
@@ -314,6 +315,7 @@
 
 void ProTypeMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IgnoreArrays", IgnoreArrays);
+  Options.store(Opts, "UseAssignment", UseAssignment);
 }
 
 // FIXME: Copied from clang/lib/Sema/SemaDeclCXX.cpp.
@@ -338,6 +340,56 @@
   return isIncompleteOrZeroLengthArrayType(Context, Type);
 }
 
+static const char *getInitializer(QualType QT, bool UseAssignment) {
+  const char *DefaultInitializer = "{}";
+  if (!UseAssignment)
+return DefaultInitializer;
+
+  if (QT->isPointerType())
+return " = nullptr";
+
+  const BuiltinType *BT =
+  dyn_cast(QT.getCanonicalType().getTypePtr());
+  if (!BT)
+return DefaultInitializer;
+
+  switch (BT->getKind()) {
+  case BuiltinType::Bool:
+return " = false";
+  case BuiltinType::Float:
+return " = 0.0F";
+  case BuiltinType::Double:
+return " = 0.0";
+  case BuiltinType::LongDouble:
+return " = 0.0L";
+  case BuiltinType::SChar:
+  case BuiltinType::Char_S:
+  case BuiltinType::WChar_S:
+  case BuiltinType::Char16:
+  case BuiltinType::Char32:
+  case BuiltinType::Short:
+  case BuiltinType::Int:
+return " = 0";
+  case BuiltinType::UChar:
+  case BuiltinType::Char_U:
+  case BuiltinType::WChar_U:
+  case BuiltinType::UShort:
+  case BuiltinType::UInt:
+return " = 0U";
+  case BuiltinType::Long:
+return " = 0L";
+  case BuiltinType::ULong:
+return " = 0UL";
+  case BuiltinType::LongLong:
+return " = 0LL";
+  case BuiltinType::ULongLong:
+return " = 0ULL";
+
+  default:
+return DefaultInitializer;
+  }
+}
+
 void ProTypeMemberInitCheck::checkMissingMemberInitializer(
 ASTContext &Context, const CXXRecordDecl &ClassDecl,
 const CXXConstructorDecl *Ctor) {
@@ -420,7 +472,7 @@
 for (const FieldDecl *Field : FieldsToFix) {
   Diag << FixItHint::CreateInsertion(
   getLocationForEndOfToken(Context, Field->getSourceRange().getEnd()),
-  "{}");
+  getInitializer(Field->getType(), UseAssignment));
 }
   } else if (Ctor) {
 // Otherwise, rewrite the constructor's initializer list.
Index: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
===
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
@@ -64,6 +64,11 @@
 
   // Whether arrays need to be initialized or not. Default is false.
   bool IgnoreArrays;
+
+  // Whether fix-its for initialization of fundamental type use assignment
+  // instead of brace initalization. Only effective in C++11 mode. Default is
+  // false.
+  bool UseAssignment;
 };
 
 } // namespace cppcoreguidelines
Index: clang-tools-extra/trunk/docs/ReleaseNotes.rst
===
--- clang-tools-extra/trunk/docs/ReleaseNotes.rst
+++ clang-tools-extra/trunk/docs/ReleaseNotes.rst
@@ -186,6 +186,11 @@
   `WarnOnLargeObject` and `MaxSize` options to warn on any large trivial
   object caught by value.
 
+- Added `UseAssignment` option to :doc:`cppcoreguidelines-pro-type-memb

[PATCH] D68074: [clang-tidy] Add readability-make-member-function-const

2019-09-26 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre created this revision.
mgehre added reviewers: aaron.ballman, gribozavr, hokein, alexfh.
mgehre added a project: clang.
Herald added subscribers: xazax.hun, mgorny.

Finds non-static member functions that can be made ``const``
because the functions don't use ``this`` in a non-const way.

The check conservatively tries to preserve logical costness in favor of
physical costness. See readability-make-member-function-const.rst for more
details.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D68074

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
  clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.h
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/docs/clang-tidy/checks/readability-make-member-function-const.rst
  clang-tools-extra/test/clang-tidy/readability-make-member-function-const.cpp

Index: clang-tools-extra/test/clang-tidy/readability-make-member-function-const.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/readability-make-member-function-const.cpp
@@ -0,0 +1,321 @@
+// RUN: %check_clang_tidy %s readability-make-member-function-const %t
+
+struct Str {
+  void const_method() const;
+  void non_const_method();
+};
+
+namespace Diagnose {
+struct A;
+
+void free_const_use(const A *);
+void free_const_use(const A &);
+
+struct A {
+  int M;
+  const int ConstM;
+  struct {
+int M;
+  } Struct;
+  Str S;
+  Str Sref;
+
+  void already_const() const;
+
+  int read_field() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_field' can be made const
+// CHECK-FIXES: {{^}}  int read_field() const {
+return M;
+  }
+
+  int read_struct_field() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_struct_field' can be made const
+// CHECK-FIXES: {{^}}  int read_struct_field() const {
+return Struct.M;
+  }
+
+  int read_const_field() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_const_field' can be made const
+// CHECK-FIXES: {{^}}  int read_const_field() const {
+return ConstM;
+  }
+
+  void call_const_member() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member' can be made const
+// CHECK-FIXES: {{^}}  void call_const_member() const {
+already_const();
+  }
+
+  void call_const_member_on_public_field() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field' can be made const
+// CHECK-FIXES: {{^}}  void call_const_member_on_public_field() const {
+S.const_method();
+  }
+
+  void call_const_member_on_public_field_ref() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field_ref' can be made const
+// CHECK-FIXES: {{^}}  void call_const_member_on_public_field_ref() const {
+Sref.const_method();
+  }
+
+  const Str &return_public_field_ref() {
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: method 'return_public_field_ref' can be made const
+// CHECK-FIXES: {{^}}  const Str &return_public_field_ref() const {
+return S;
+  }
+
+  const A *return_this_const() {
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const' can be made const
+// CHECK-FIXES: {{^}}  const A *return_this_const() const {
+return this;
+  }
+
+  const A &return_this_const_ref() {
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const_ref' can be made const
+// CHECK-FIXES: {{^}}  const A &return_this_const_ref() const {
+return *this;
+  }
+
+  void const_use() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use' can be made const
+// CHECK-FIXES: {{^}}  void const_use() const {
+free_const_use(this);
+  }
+
+  void const_use_ref() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use_ref' can be made const
+// CHECK-FIXES: {{^}}  void const_use_ref() const {
+free_const_use(*this);
+  }
+
+  auto trailingReturn() -> int {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'trailingReturn' can be made const
+// CHECK-FIXES: {{^}}  auto trailingReturn() const -> int {
+return M;
+  }
+
+  int volatileFunction() volatile {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'volatileFunction' can be made const
+// CHECK-FIXES: {{^}}  int volatileFunction() const volatile {
+return M;
+  }
+
+  int restrictFunction() __restrict {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'restrictFunction' can be made const
+// CHECK-FIXES: {{^}}  int restrictFunction() const __restrict {
+return M;
+  }
+
+  int refFunction() & {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'refFunction' can be made const
+// CHECK-FIXES: {{^}}  int refFunction() const

[PATCH] D68074: [clang-tidy] Add readability-make-member-function-const

2019-09-29 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 222331.
mgehre marked 6 inline comments as done.
mgehre added a comment.

- Implement review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68074/new/

https://reviews.llvm.org/D68074

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
  clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.h
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/docs/clang-tidy/checks/readability-make-member-function-const.rst
  clang-tools-extra/test/clang-tidy/readability-make-member-function-const.cpp

Index: clang-tools-extra/test/clang-tidy/readability-make-member-function-const.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/readability-make-member-function-const.cpp
@@ -0,0 +1,321 @@
+// RUN: %check_clang_tidy %s readability-make-member-function-const %t
+
+struct Str {
+  void const_method() const;
+  void non_const_method();
+};
+
+namespace Diagnose {
+struct A;
+
+void free_const_use(const A *);
+void free_const_use(const A &);
+
+struct A {
+  int M;
+  const int ConstM;
+  struct {
+int M;
+  } Struct;
+  Str S;
+  Str Sref;
+
+  void already_const() const;
+
+  int read_field() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_field' can be made const
+// CHECK-FIXES: {{^}}  int read_field() const {
+return M;
+  }
+
+  int read_struct_field() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_struct_field' can be made const
+// CHECK-FIXES: {{^}}  int read_struct_field() const {
+return Struct.M;
+  }
+
+  int read_const_field() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_const_field' can be made const
+// CHECK-FIXES: {{^}}  int read_const_field() const {
+return ConstM;
+  }
+
+  void call_const_member() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member' can be made const
+// CHECK-FIXES: {{^}}  void call_const_member() const {
+already_const();
+  }
+
+  void call_const_member_on_public_field() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field' can be made const
+// CHECK-FIXES: {{^}}  void call_const_member_on_public_field() const {
+S.const_method();
+  }
+
+  void call_const_member_on_public_field_ref() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field_ref' can be made const
+// CHECK-FIXES: {{^}}  void call_const_member_on_public_field_ref() const {
+Sref.const_method();
+  }
+
+  const Str &return_public_field_ref() {
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: method 'return_public_field_ref' can be made const
+// CHECK-FIXES: {{^}}  const Str &return_public_field_ref() const {
+return S;
+  }
+
+  const A *return_this_const() {
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const' can be made const
+// CHECK-FIXES: {{^}}  const A *return_this_const() const {
+return this;
+  }
+
+  const A &return_this_const_ref() {
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const_ref' can be made const
+// CHECK-FIXES: {{^}}  const A &return_this_const_ref() const {
+return *this;
+  }
+
+  void const_use() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use' can be made const
+// CHECK-FIXES: {{^}}  void const_use() const {
+free_const_use(this);
+  }
+
+  void const_use_ref() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use_ref' can be made const
+// CHECK-FIXES: {{^}}  void const_use_ref() const {
+free_const_use(*this);
+  }
+
+  auto trailingReturn() -> int {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'trailingReturn' can be made const
+// CHECK-FIXES: {{^}}  auto trailingReturn() const -> int {
+return M;
+  }
+
+  int volatileFunction() volatile {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'volatileFunction' can be made const
+// CHECK-FIXES: {{^}}  int volatileFunction() const volatile {
+return M;
+  }
+
+  int restrictFunction() __restrict {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'restrictFunction' can be made const
+// CHECK-FIXES: {{^}}  int restrictFunction() const __restrict {
+return M;
+  }
+
+  int refFunction() & {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'refFunction' can be made const
+// CHECK-FIXES: {{^}}  int refFunction() const & {
+return M;
+  }
+
+  void out_of_line_call_const();
+  // CHECK-FIXES: {{^}}  void out_of_line_call_const() const;
+};
+
+void A::out_of_line_call_const() {
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: method 'out_of_line_call_const' ca

[PATCH] D68074: [clang-tidy] Add readability-make-member-function-const

2019-09-29 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

In D68074#1683770 , @lebedev.ri wrote:

> Awesome!
>  I believe i have asked this question in the convert-to-static diff - can 
> ExprMutAnalyzer be used here?


I believe in this case, we can get away with a simpler analysis. Because `this` 
is an prvalue,
there are less operations that can be done to it, and it seems easy to just 
list those here. Also, we want
to conservatively disallow "const" access to non-public member 
variables/functions, and I don't see
how this would elegantly integrate with using the ExprMutationAnalyzer.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68074/new/

https://reviews.llvm.org/D68074



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


[PATCH] D68074: [clang-tidy] Add readability-make-member-function-const

2019-10-09 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked an inline comment as done.
mgehre added inline comments.



Comment at: 
clang-tools-extra/test/clang-tidy/readability-make-member-function-const.cpp:311
+  // This member function must stay non-const, even though
+  // it only calls other private const member functions.
+  int &get() {

gribozavr wrote:
> Is it because the const version already exists? Then that should be the rule 
> (not calling a private helper function).
Let me try to explain. If it make senses what I say, I'll then update the 
documentation.
The terms logical const and physical const are from here: 
https://isocpp.org/wiki/faq/const-correctness#logical-vs-physical-const

The const version is just here to illustrate how this pattern works. The 
important fact is that a private member function is not part of the public 
interface of the class. 
I.e. users of the class were not able to call `data()` with a const object 
before (even though data() is declared as const) because `data()` is at the 
same time `private`.
We thus cannot assume that the `constness` of `data()` reflects the interface 
contract the the author of the class had in mind.

Here, e.g. the author clearly wanted to only give access to a non-const `int&` 
to users that possses a non-const version of *this.

The rule "don't make the method const if it already has a const overload" seems 
appealing, but its neither sufficient (we still need the rule we currently have 
about private data)
nor is is necessary once we have all other rules. I have successfully run this 
check on the LLVM code base, and there were not issues with clashing overloads 
after fix-its. (It found multiple hundred of valid fixits)

The second example how to see the issue with private data members is the Pimpl 
idiom:
```
class S {
  struct Impl {
   int d;
  };
  Impl *I;
public:
  void set(int v) {
I->d = v;
  }
};
```
A human would not make the `set()` function const because we consider the value 
of `Impl->d` to be part of the value of the instance. Technically, we can make 
`set()` const because
it does not modify `I`. But that is not the author's intention. I try to have 
no false-positives in this check,
so I conservatively assume that an access to a private member that is not of 
builtin type does not preserve logical constness.
Note that the same happens when the type of I is changed to `unique_ptr`. 
`unique_ptr::operator->` is a const member function but returns a reference to 
non-const `Impl`,
and so does not preserve logical constness

We might be able to extend the check by tracking pointer use, but that's pretty 
difficult.
The only extension I did is for builtin types, i.e.`int`. When we read an int 
(in the AST that's an LvalueToRvalue conversion), then there is no way that 
this can eventually lead to a modification
of the state of the int, so it preserves logical constness.

Const use of public members is also ok because the user of the class already 
has access to them. We are not widening the contract by making a member 
function const that
(only) contains const use of public members.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68074/new/

https://reviews.llvm.org/D68074



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


[PATCH] D68074: [clang-tidy] Add readability-make-member-function-const

2019-10-09 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked 2 inline comments as done.
mgehre added inline comments.



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/readability-make-member-function-const.rst:10
+The check conservatively tries to preserve logical costness in favor of
+physical costness. The only operations on ``this`` that this check considers
+to preserve logical constness are

gribozavr wrote:
> Sorry, it is unclear to me what it means: "the check [...] tries to do X in 
> favor of Y"
> 
> Also unclear what logical/physical constness mean.
I guess it should read `tries to preserve logical constness instead of physical 
constness.`

logical/physical constness is from here: 
https://isocpp.org/wiki/faq/const-correctness#logical-vs-physical-state
Are there more common terms for this or should I link or copy the explanation?



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/readability-make-member-function-const.rst:17
+* returning const-qualified ``this``
+* passing const-qualified ``this`` as a parameter.
+

gribozavr wrote:
> These rules need a justification; if not for the users, but for future 
> maintainers.
> 
> For example, why isn't reading a private member variable OK? Why isn't 
> calling a private member function OK?
> 
Sure! Let's first see if you agree to the rules based on the explanation in my 
other comment.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68074/new/

https://reviews.llvm.org/D68074



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


[PATCH] D69145: Give readability-redundant-member-init an option IgnoreBaseInCopyConstructors to avoid breaking code with gcc -Werror=extra

2019-10-19 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp:55
   const auto *Construct = 
Result.Nodes.getNodeAs("construct");
+  const auto* ConstructorDecl = Result.Nodes.getNodeAs( 
"constructor" );
+

Extra space around string literal - did you run clang-format on your changes?



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst:30
+within copy constructors. Some compilers issue warnings requiring copy
+constructors to explicitly initialize their base classes.
+

I'd might be helpful to mention `gcc` and `-Wextra` here so users can easily 
identify whether this case applies to them.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69145/new/

https://reviews.llvm.org/D69145



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


[PATCH] D69145: Give readability-redundant-member-init an option IgnoreBaseInCopyConstructors to avoid breaking code with gcc -Werror=extra

2019-10-19 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

Exactly due to the issue you are fixing here, we ended up disabling the 
complete check because we didn't want to live with the warnings it produced on 
-Wextra.
Therefore, I'm actually strongly in favor to enable the option by default.

When others see that clang-tidy fixits introduce warnings (with -Wextra) or 
even break their build (with -Werror), they might not look into check options, 
but just disable the check directly.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69145/new/

https://reviews.llvm.org/D69145



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


[PATCH] D68074: [clang-tidy] Add readability-make-member-function-const

2019-10-20 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 225804.
mgehre marked 6 inline comments as done.
mgehre added a comment.

- Update documentation


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68074/new/

https://reviews.llvm.org/D68074

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
  clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.h
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/docs/clang-tidy/checks/readability-make-member-function-const.rst
  clang-tools-extra/test/clang-tidy/readability-make-member-function-const.cpp

Index: clang-tools-extra/test/clang-tidy/readability-make-member-function-const.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/readability-make-member-function-const.cpp
@@ -0,0 +1,321 @@
+// RUN: %check_clang_tidy %s readability-make-member-function-const %t
+
+struct Str {
+  void const_method() const;
+  void non_const_method();
+};
+
+namespace Diagnose {
+struct A;
+
+void free_const_use(const A *);
+void free_const_use(const A &);
+
+struct A {
+  int M;
+  const int ConstM;
+  struct {
+int M;
+  } Struct;
+  Str S;
+  Str Sref;
+
+  void already_const() const;
+
+  int read_field() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_field' can be made const
+// CHECK-FIXES: {{^}}  int read_field() const {
+return M;
+  }
+
+  int read_struct_field() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_struct_field' can be made const
+// CHECK-FIXES: {{^}}  int read_struct_field() const {
+return Struct.M;
+  }
+
+  int read_const_field() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_const_field' can be made const
+// CHECK-FIXES: {{^}}  int read_const_field() const {
+return ConstM;
+  }
+
+  void call_const_member() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member' can be made const
+// CHECK-FIXES: {{^}}  void call_const_member() const {
+already_const();
+  }
+
+  void call_const_member_on_public_field() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field' can be made const
+// CHECK-FIXES: {{^}}  void call_const_member_on_public_field() const {
+S.const_method();
+  }
+
+  void call_const_member_on_public_field_ref() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field_ref' can be made const
+// CHECK-FIXES: {{^}}  void call_const_member_on_public_field_ref() const {
+Sref.const_method();
+  }
+
+  const Str &return_public_field_ref() {
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: method 'return_public_field_ref' can be made const
+// CHECK-FIXES: {{^}}  const Str &return_public_field_ref() const {
+return S;
+  }
+
+  const A *return_this_const() {
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const' can be made const
+// CHECK-FIXES: {{^}}  const A *return_this_const() const {
+return this;
+  }
+
+  const A &return_this_const_ref() {
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const_ref' can be made const
+// CHECK-FIXES: {{^}}  const A &return_this_const_ref() const {
+return *this;
+  }
+
+  void const_use() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use' can be made const
+// CHECK-FIXES: {{^}}  void const_use() const {
+free_const_use(this);
+  }
+
+  void const_use_ref() {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use_ref' can be made const
+// CHECK-FIXES: {{^}}  void const_use_ref() const {
+free_const_use(*this);
+  }
+
+  auto trailingReturn() -> int {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'trailingReturn' can be made const
+// CHECK-FIXES: {{^}}  auto trailingReturn() const -> int {
+return M;
+  }
+
+  int volatileFunction() volatile {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'volatileFunction' can be made const
+// CHECK-FIXES: {{^}}  int volatileFunction() const volatile {
+return M;
+  }
+
+  int restrictFunction() __restrict {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'restrictFunction' can be made const
+// CHECK-FIXES: {{^}}  int restrictFunction() const __restrict {
+return M;
+  }
+
+  int refFunction() & {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'refFunction' can be made const
+// CHECK-FIXES: {{^}}  int refFunction() const & {
+return M;
+  }
+
+  void out_of_line_call_const();
+  // CHECK-FIXES: {{^}}  void out_of_line_call_const() const;
+};
+
+void A::out_of_line_call_const() {
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: method 'out_of_line_call_const' can be 

[PATCH] D80301: [yaml][clang-tidy] Fix new line YAML serialization

2020-05-21 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

Thanks for doing this! I didn't work on the YAML parser before, so I cannot 
give formal approval.




Comment at: llvm/lib/Support/YAMLTraits.cpp:904
+   std::string &Val) {
+  Val.clear();
+  size_t CurrentPos = 0;

I wonder whether using StringRef::split() would lead to an easier 
implementation 
(https://llvm.org/doxygen/classllvm_1_1StringRef.html#af0284e4c41c0e09c0bc4767bc77a899d)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D80301/new/

https://reviews.llvm.org/D80301



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


[PATCH] D77572: [clang-tidy] add new check readability-use-anyofallof

2020-05-25 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 266083.
mgehre marked an inline comment as done.
mgehre added a comment.

Fix comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77572/new/

https://reviews.llvm.org/D77572

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability-use-anyofallof.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp
@@ -0,0 +1,183 @@
+// RUN: %check_clang_tidy -std=c++14,c++17 %s readability-use-anyofallof %t
+
+bool good_any_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::any_of()' [readability-use-anyofallof]
+  for (int i : v)
+if (i)
+  return true;
+  return false;
+}
+
+bool cond(int i);
+
+bool good_any_of2() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+int k = i / 2;
+if (cond(k))
+  return true;
+  }
+  return false;
+}
+
+bool good_any_of3() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+if (i == 3)
+  continue;
+if (i)
+  return true;
+  }
+
+  return false;
+}
+
+bool good_any_of_use_external(int comp) {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+if (i == comp)
+  return true;
+  }
+
+  return false;
+}
+
+bool good_any_of_no_cond() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+return true; // Not a real loop, but technically can become any_of.
+  }
+
+  return false;
+}
+
+bool good_any_of_local_modification() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+int j = i;
+j++; // FIXME: Any non-const use disables check.
+if (j > 3)
+  return true;
+  }
+
+  return false;
+}
+
+bool good_any_of_throw() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+if (i > 3)
+  return true;
+if (i == 42)
+  throw 0;
+  }
+
+  return false;
+}
+
+bool bad_any_of1() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return false; // bad constant
+  }
+  return false;
+}
+
+bool bad_any_of2() {
+  int v[] = {1, 2, 3};
+  for (int i : v)
+if (i)
+  return true;
+
+  return true; // bad return
+}
+
+bool bad_any_of3() {
+  int v[] = {1, 2, 3};
+  for (int i : v)
+if (i)
+  return true;
+else
+  return i / 2; // bad return
+
+  return false;
+}
+
+bool bad_any_of_control_flow1() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+break; // bad control flow
+if (i)
+  return true;
+  }
+
+  return false;
+}
+
+bool bad_any_of_control_flow2() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+goto end; // bad control flow
+if (i)
+  return true;
+  }
+
+  end:
+  return false;
+}
+
+bool bad_any_of4() {
+  return false; // wrong order
+
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return true;
+  }
+}
+
+bool bad_any_of5() {
+  int v[] = {1, 2, 3};
+  int j = 0;
+  for (int i : v) {
+j++; // modifications
+if (i)
+  return true;
+  }
+  return false;
+}
+
+bool bad_any_of6() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return true;
+  }
+  int j = 0; // Statements between loop and return
+  j++;
+  return false;
+}
+
+bool bad_any_of7() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+i; // No 'return true' in body.
+  }
+  return false;
+}
+
+bool good_all_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::all_of()' [readability-use-anyofallof]
+  for (int i : v)
+if (i)
+  return false;
+  return true;
+}
Index: clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy -std=c++2a-or-later %s readability-use-anyofallof %t
+
+bool good_any_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop

[PATCH] D77572: [clang-tidy] add new check readability-use-anyofallof

2020-05-25 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked 5 inline comments as done.
mgehre added a comment.

Aaron, thank you very much for taking the time to review this PR.




Comment at: clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp:61
+  hasBody(allOf(hasDescendant(returns(true)),
+unless(anyOf(hasDescendant(breakStmt()),
+ hasDescendant(returnsButNotTrue))

aaron.ballman wrote:
> Should we reject other ways to break out of the loop, like `goto` or `throw`?
I think throw statements still can be transformed. We cannot transform `break` 
because the loop is gone and we cannot transform `goto` because we cannot jump 
from the lambda into its caller.
But we can keep `throw` statements because exceptions can propagate from the 
lambda through the algorithm back into the original caller. If we could not 
allow `throw` statements, we would also have to disallow any other kind of call 
statements.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77572/new/

https://reviews.llvm.org/D77572



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


[PATCH] D80301: [yaml][clang-tidy] Fix new line YAML serialization

2020-06-02 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added inline comments.



Comment at: llvm/lib/Support/YAMLTraits.cpp:904
+   std::string &Val) {
+  Val.clear();
+  size_t CurrentPos = 0;

DmitryPolukhin wrote:
> mgehre wrote:
> > I wonder whether using StringRef::split() would lead to an easier 
> > implementation 
> > (https://llvm.org/doxygen/classllvm_1_1StringRef.html#af0284e4c41c0e09c0bc4767bc77a899d)
> I'm not sure that it will be easier to read or more efficient 
> (`StringRef::split` will require additional vector).
I don't expect the difference in efficiency to be noticable, but the code would 
look like
```
SmallVector Lines;
StringRef(Val).split(Lines, '\n');
bool First = true;
for (StringRef Line: Lines) {
  if (First)
First = false;
  else
Out << '\n';
  Out << Line;
}
```
which I personally find easier to follow than `CurrentPos`, `LineBreakPos` and 
their arithmetic.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D80301/new/

https://reviews.llvm.org/D80301



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


[PATCH] D77572: [clang-tidy] add new check readability-use-anyofallof

2020-06-03 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 268120.
mgehre added a comment.

Implemented njames93's comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77572/new/

https://reviews.llvm.org/D77572

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability-use-anyofallof.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp
@@ -0,0 +1,183 @@
+// RUN: %check_clang_tidy -std=c++14,c++17 %s readability-use-anyofallof %t
+
+bool good_any_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::any_of()' [readability-use-anyofallof]
+  for (int i : v)
+if (i)
+  return true;
+  return false;
+}
+
+bool cond(int i);
+
+bool good_any_of2() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+int k = i / 2;
+if (cond(k))
+  return true;
+  }
+  return false;
+}
+
+bool good_any_of3() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+if (i == 3)
+  continue;
+if (i)
+  return true;
+  }
+
+  return false;
+}
+
+bool good_any_of_use_external(int comp) {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+if (i == comp)
+  return true;
+  }
+
+  return false;
+}
+
+bool good_any_of_no_cond() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+return true; // Not a real loop, but technically can become any_of.
+  }
+
+  return false;
+}
+
+bool good_any_of_local_modification() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+int j = i;
+j++; // FIXME: Any non-const use disables check.
+if (j > 3)
+  return true;
+  }
+
+  return false;
+}
+
+bool good_any_of_throw() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+if (i > 3)
+  return true;
+if (i == 42)
+  throw 0;
+  }
+
+  return false;
+}
+
+bool bad_any_of1() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return false; // bad constant
+  }
+  return false;
+}
+
+bool bad_any_of2() {
+  int v[] = {1, 2, 3};
+  for (int i : v)
+if (i)
+  return true;
+
+  return true; // bad return
+}
+
+bool bad_any_of3() {
+  int v[] = {1, 2, 3};
+  for (int i : v)
+if (i)
+  return true;
+else
+  return i / 2; // bad return
+
+  return false;
+}
+
+bool bad_any_of_control_flow1() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+break; // bad control flow
+if (i)
+  return true;
+  }
+
+  return false;
+}
+
+bool bad_any_of_control_flow2() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+goto end; // bad control flow
+if (i)
+  return true;
+  }
+
+  end:
+  return false;
+}
+
+bool bad_any_of4() {
+  return false; // wrong order
+
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return true;
+  }
+}
+
+bool bad_any_of5() {
+  int v[] = {1, 2, 3};
+  int j = 0;
+  for (int i : v) {
+j++; // modifications
+if (i)
+  return true;
+  }
+  return false;
+}
+
+bool bad_any_of6() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return true;
+  }
+  int j = 0; // Statements between loop and return
+  j++;
+  return false;
+}
+
+bool bad_any_of7() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+i; // No 'return true' in body.
+  }
+  return false;
+}
+
+bool good_all_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::all_of()' [readability-use-anyofallof]
+  for (int i : v)
+if (i)
+  return false;
+  return true;
+}
Index: clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy -std=c++2a-or-later %s readability-use-anyofallof %t
+
+bool good_any_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::ranges::any_

[PATCH] D77572: [clang-tidy] add new check readability-use-anyofallof

2020-06-03 Thread Matthias Gehre via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGadd51e152aa6: [clang-tidy] add new check 
readability-use-anyofallof (authored by mgehre).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77572/new/

https://reviews.llvm.org/D77572

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability-use-anyofallof.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp
@@ -0,0 +1,183 @@
+// RUN: %check_clang_tidy -std=c++14,c++17 %s readability-use-anyofallof %t
+
+bool good_any_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::any_of()' [readability-use-anyofallof]
+  for (int i : v)
+if (i)
+  return true;
+  return false;
+}
+
+bool cond(int i);
+
+bool good_any_of2() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+int k = i / 2;
+if (cond(k))
+  return true;
+  }
+  return false;
+}
+
+bool good_any_of3() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+if (i == 3)
+  continue;
+if (i)
+  return true;
+  }
+
+  return false;
+}
+
+bool good_any_of_use_external(int comp) {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+if (i == comp)
+  return true;
+  }
+
+  return false;
+}
+
+bool good_any_of_no_cond() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+return true; // Not a real loop, but technically can become any_of.
+  }
+
+  return false;
+}
+
+bool good_any_of_local_modification() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+int j = i;
+j++; // FIXME: Any non-const use disables check.
+if (j > 3)
+  return true;
+  }
+
+  return false;
+}
+
+bool good_any_of_throw() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: replace loop by 'std::any_of()'
+if (i > 3)
+  return true;
+if (i == 42)
+  throw 0;
+  }
+
+  return false;
+}
+
+bool bad_any_of1() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return false; // bad constant
+  }
+  return false;
+}
+
+bool bad_any_of2() {
+  int v[] = {1, 2, 3};
+  for (int i : v)
+if (i)
+  return true;
+
+  return true; // bad return
+}
+
+bool bad_any_of3() {
+  int v[] = {1, 2, 3};
+  for (int i : v)
+if (i)
+  return true;
+else
+  return i / 2; // bad return
+
+  return false;
+}
+
+bool bad_any_of_control_flow1() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+break; // bad control flow
+if (i)
+  return true;
+  }
+
+  return false;
+}
+
+bool bad_any_of_control_flow2() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+goto end; // bad control flow
+if (i)
+  return true;
+  }
+
+  end:
+  return false;
+}
+
+bool bad_any_of4() {
+  return false; // wrong order
+
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return true;
+  }
+}
+
+bool bad_any_of5() {
+  int v[] = {1, 2, 3};
+  int j = 0;
+  for (int i : v) {
+j++; // modifications
+if (i)
+  return true;
+  }
+  return false;
+}
+
+bool bad_any_of6() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return true;
+  }
+  int j = 0; // Statements between loop and return
+  j++;
+  return false;
+}
+
+bool bad_any_of7() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+i; // No 'return true' in body.
+  }
+  return false;
+}
+
+bool good_all_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::all_of()' [readability-use-anyofallof]
+  for (int i : v)
+if (i)
+  return false;
+  return true;
+}
Index: clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy -std=c++2a-or-later %s readability-use-anyofallof %t
+
+bool good_any_of() {
+  int v[] = {1, 2, 3};

[PATCH] D77572: [clang-tidy] add new check readability-use-anyofallof

2020-04-06 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre created this revision.
mgehre added reviewers: aaron.ballman, alexfh, hokein.
Herald added subscribers: xazax.hun, mgorny.
Herald added a project: clang.

Finds range-based for loops that can be replaced by a call to ``std::any_of`` or
``std::all_of``. In C++ 20 mode, suggests ``std::ranges::any_of`` or
``std::ranges::all_of``.
For now, no fixits are produced.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D77572

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability-use-anyofallof.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp
@@ -0,0 +1,158 @@
+// RUN: %check_clang_tidy -std=c++14,c++17 %s readability-use-anyofallof %t
+
+bool good_any_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: Replace loop by std::any_of() from  [readability-use-anyofallof]
+  for (int i : v)
+if (i)
+  return true;
+  return false;
+}
+
+bool cond(int i);
+
+bool good_any_of2() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Replace loop by std::any_of()
+int k = i / 2;
+if (cond(k))
+  return true;
+  }
+  return false;
+}
+
+bool good_any_of3() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Replace loop by std::any_of()
+if (i == 3)
+  continue;
+if (i)
+  return true;
+  }
+
+  return false;
+}
+
+bool good_any_of_use_external(int comp) {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Replace loop by std::any_of()
+if (i == comp)
+  return true;
+  }
+
+  return false;
+}
+
+bool good_any_of_no_cond() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Replace loop by std::any_of()
+return true; // Not a real loop, but technically can become any_of.
+  }
+
+  return false;
+}
+
+bool good_any_of_local_modification() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+int j = i;
+j++; // FIXME: Any non-const use disables check.
+if (j > 3)
+  return true;
+  }
+
+  return false;
+}
+
+bool bad_any_of1() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return false; // bad constant
+  }
+  return false;
+}
+
+bool bad_any_of2() {
+  int v[] = {1, 2, 3};
+  for (int i : v)
+if (i)
+  return true;
+
+  return true; // bad return
+}
+
+bool bad_any_of3() {
+  int v[] = {1, 2, 3};
+  for (int i : v)
+if (i)
+  return true;
+else
+  return i / 2; // bad return
+
+  return false;
+}
+
+bool bad_any_of_control_flow1() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+break; // bad control flow
+if (i)
+  return true;
+  }
+
+  return false;
+}
+
+bool bad_any_of4() {
+  return false; // wrong order
+
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return true;
+  }
+}
+
+bool bad_any_of5() {
+  int v[] = {1, 2, 3};
+  int j = 0;
+  for (int i : v) {
+j++; // modifications
+if (i)
+  return true;
+  }
+  return false;
+}
+
+bool bad_any_of6() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return true;
+  }
+  int j = 0; // Statements between loop and return
+  j++;
+  return false;
+}
+
+bool bad_any_of7() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+i; // No 'return true' in body.
+  }
+  return false;
+}
+
+bool good_all_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: Replace loop by std::all_of() from  [readability-use-anyofallof]
+  for (int i : v)
+if (i)
+  return false;
+  return true;
+}
Index: clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy -std=c++2a-or-later %s readability-use-anyofallof %t
+
+bool good_any_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: Replace loop by std::ranges::any_of() from 
+  for (int i : v)
+if (i)
+  return true;
+  return false;
+}
+
+bool good_all_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: Replace loop by std::ranges::all_of() from 
+  for (int i :

[PATCH] D77572: [clang-tidy] add new check readability-use-anyofallof

2020-04-07 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre marked 6 inline comments as done.
mgehre added a comment.

In D77572#1965143 , @njames93 wrote:

> I'm struggling to see the value of this check though. If it was reworked to 
> check for loop in the middle of a function it would have a lot more value.


This is (just) a first step. The next step is to detect the local variable case 
as you also described it. Note that this also catches functions
that do some preprocessing and end with a any_of-style loop.
I also have a local branch that generates fixits, but they add quite some code, 
so I wanted to put them in a separate PR.

In LLVM & clang, the check in this PR already emits 370 unique warnings. 
F11685854: readability-use-anyofallof.log 


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77572/new/

https://reviews.llvm.org/D77572



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


[PATCH] D77572: [clang-tidy] add new check readability-use-anyofallof

2020-04-07 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 255812.
mgehre added a comment.

Review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77572/new/

https://reviews.llvm.org/D77572

Files:
  clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst

Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -132,8 +132,8 @@
 - New :doc:`readability-use-anyofallof
   ` check.
 
-  Finds range-based for loops that can be replaced by a call to std::any_of or
-  std::all_of.
+  Finds range-based for loops that can be replaced by a call to ``std::any_of``
+  or ``std::all_of``.
 
 New check aliases
 ^
Index: clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.h
===
--- clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.h
+++ clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.h
@@ -24,19 +24,14 @@
 /// http://clang.llvm.org/extra/clang-tidy/checks/readability-use-anyofallof.html
 class UseAnyOfAllOfCheck : public ClangTidyCheck {
 public:
-  UseAnyOfAllOfCheck(StringRef Name, ClangTidyContext *Context)
-  : ClangTidyCheck(Name, Context),
-IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
-Options.getLocalOrGlobal("IncludeStyle", "llvm"))) {}
+  using ClangTidyCheck::ClangTidyCheck;
+
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+return LangOpts.CPlusPlus;
+  }
 
-  void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
-   Preprocessor *ModuleExpanderPP) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
-
-private:
-  std::unique_ptr IncludeInserter;
-  const utils::IncludeSorter::IncludeStyle IncludeStyle;
 };
 
 } // namespace readability
Index: clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
@@ -18,12 +18,13 @@
 using namespace clang::ast_matchers;
 
 namespace clang {
-namespace ast_matchers {
+namespace {
 /// Matches a Stmt whose parent is a CompoundStmt,
 /// and which is directly followed by
 /// a Stmt matching the inner matcher.
-AST_MATCHER_P(Stmt, nextStmt, internal::Matcher, InnerMatcher) {
-  const auto &Parents = Finder->getASTContext().getParents(Node);
+AST_MATCHER_P(Stmt, nextStmt, ast_matchers::internal::Matcher,
+  InnerMatcher) {
+  DynTypedNodeList Parents = Finder->getASTContext().getParents(Node);
   if (Parents.size() != 1)
 return false;
 
@@ -31,30 +32,19 @@
   if (!C)
 return false;
 
-  const auto *I = std::find(C->body_begin(), C->body_end(), &Node);
+  const auto *I = llvm::find(C->body(), &Node);
   assert(I != C->body_end()); // C is parent of Node.
   if (++I == C->body_end())
 return false; // Node is last statement.
 
   return InnerMatcher.matches(**I, Finder, Builder);
 }
-} // namespace ast_matchers
+} // namespace
 
 namespace tidy {
 namespace readability {
 
-void UseAnyOfAllOfCheck::registerPPCallbacks(const SourceManager &SM,
- Preprocessor *PP,
- Preprocessor *ModuleExpanderPP) {
-  IncludeInserter =
-  std::make_unique(SM, getLangOpts(), IncludeStyle);
-  PP->addPPCallbacks(IncludeInserter->CreatePPCallbacks());
-}
-
 void UseAnyOfAllOfCheck::registerMatchers(MatchFinder *Finder) {
-  if (!getLangOpts().CPlusPlus)
-return;
-
   auto returns = [](bool V) {
 return returnStmt(hasReturnValue(cxxBoolLiteral(equals(V;
   };
@@ -107,7 +97,6 @@
 
 diag(S->getForLoc(), "Replace loop by std%0::any_of() from ")
 << Ranges;
-
   } else if (const auto *S =
  Result.Nodes.getNodeAs("all_of_loop")) {
 if (!isViableLoop(*S, *Result.Context))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D77572: [clang-tidy] add new check readability-use-anyofallof

2020-04-07 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre updated this revision to Diff 255814.
mgehre added a comment.

Review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77572/new/

https://reviews.llvm.org/D77572

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability-use-anyofallof.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof.cpp
@@ -0,0 +1,158 @@
+// RUN: %check_clang_tidy -std=c++14,c++17 %s readability-use-anyofallof %t
+
+bool good_any_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: Replace loop by std::any_of() from  [readability-use-anyofallof]
+  for (int i : v)
+if (i)
+  return true;
+  return false;
+}
+
+bool cond(int i);
+
+bool good_any_of2() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Replace loop by std::any_of()
+int k = i / 2;
+if (cond(k))
+  return true;
+  }
+  return false;
+}
+
+bool good_any_of3() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Replace loop by std::any_of()
+if (i == 3)
+  continue;
+if (i)
+  return true;
+  }
+
+  return false;
+}
+
+bool good_any_of_use_external(int comp) {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Replace loop by std::any_of()
+if (i == comp)
+  return true;
+  }
+
+  return false;
+}
+
+bool good_any_of_no_cond() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Replace loop by std::any_of()
+return true; // Not a real loop, but technically can become any_of.
+  }
+
+  return false;
+}
+
+bool good_any_of_local_modification() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+int j = i;
+j++; // FIXME: Any non-const use disables check.
+if (j > 3)
+  return true;
+  }
+
+  return false;
+}
+
+bool bad_any_of1() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return false; // bad constant
+  }
+  return false;
+}
+
+bool bad_any_of2() {
+  int v[] = {1, 2, 3};
+  for (int i : v)
+if (i)
+  return true;
+
+  return true; // bad return
+}
+
+bool bad_any_of3() {
+  int v[] = {1, 2, 3};
+  for (int i : v)
+if (i)
+  return true;
+else
+  return i / 2; // bad return
+
+  return false;
+}
+
+bool bad_any_of_control_flow1() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+break; // bad control flow
+if (i)
+  return true;
+  }
+
+  return false;
+}
+
+bool bad_any_of4() {
+  return false; // wrong order
+
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return true;
+  }
+}
+
+bool bad_any_of5() {
+  int v[] = {1, 2, 3};
+  int j = 0;
+  for (int i : v) {
+j++; // modifications
+if (i)
+  return true;
+  }
+  return false;
+}
+
+bool bad_any_of6() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+if (i)
+  return true;
+  }
+  int j = 0; // Statements between loop and return
+  j++;
+  return false;
+}
+
+bool bad_any_of7() {
+  int v[] = {1, 2, 3};
+  for (int i : v) {
+i; // No 'return true' in body.
+  }
+  return false;
+}
+
+bool good_all_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: Replace loop by std::all_of() from  [readability-use-anyofallof]
+  for (int i : v)
+if (i)
+  return false;
+  return true;
+}
Index: clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-use-anyofallof-cpp20.cpp
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy -std=c++2a-or-later %s readability-use-anyofallof %t
+
+bool good_any_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: Replace loop by std::ranges::any_of() from 
+  for (int i : v)
+if (i)
+  return true;
+  return false;
+}
+
+bool good_all_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: Replace loop by std::ranges::all_of() from 
+  for (int i : v)
+if (i)
+  return false;
+  return true;
+}
Index: clang-tools-extra/docs/clang-tidy/checks/readability-use-anyofallof.rst
===
--- /dev/null
+

[PATCH] D77680: [clang-tidy] misc-unused-parameters: Don't remove parameter from lambda

2020-04-07 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre created this revision.
mgehre added reviewers: aaron.ballman, alexfh, hokein, njames93.
Herald added a subscriber: xazax.hun.
Herald added a project: clang.
mgehre added a project: clang-tools-extra.
mgehre edited the summary of this revision.

Previously, the check would fix

  using fn = void(int);
  void f(fn *);
  void test() {
// CHECK-MESSAGES: :[[@LINE+2]]:12: warning: parameter 'I' is unused
// CHECK-FIXES: {{^}}  f([](int  /*I*/) {
f([](int I) { return; });
  }

into
`f([]() { return; });` which breaks compilation. Now the check is disabled for 
lambdas.

The AST is not so easy to use. For

  auto l = [](int) {  return;  };
  f(l);

one gets

  `-CallExpr  'void'
   |-ImplicitCastExpr  'void (*)(fn *)' 
   | `-DeclRefExpr  'void (fn *)' lvalue Function 0x55a91a545e28 'f' 
'void (fn *)'
   `-ImplicitCastExpr  'void (*)(int)' 
 `-CXXMemberCallExpr  'void (*)(int)'
   `-MemberExpr  '' .operator void 
(*)(int) 0x55a91a546850
 `-ImplicitCastExpr  'const (lambda at line:6:14)' lvalue 

   `-DeclRefExpr  '(lambda at line:6:14)':'(lambda at 
line:6:14)' lvalue Var 0x55a91a5461c0 'l' '(lambda at line:6:14)':'(lambda at 
line:6:14)'

There is no direct use of the `operator()(int I)` of the lambda, so the 
`!Indexer->getOtherRefs(Function).empty()`
does not fire. In the future, we might be able to use the conversion operator 
`operator void (*)(int)` to mark
the call operator as having an "other ref".


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D77680

Files:
  clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/misc-unused-parameters.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/misc-unused-parameters.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-unused-parameters.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-unused-parameters.cpp
@@ -276,3 +276,13 @@
 // CHECK-FIXES: {{^}}  B(int  /*i*/) : A() {}{{$}}
 };
 } // namespace strict_mode_off
+
+namespace lambda {
+using fn = void(int);
+void f(fn *);
+void test() {
+  // CHECK-MESSAGES: :[[@LINE+2]]:12: warning: parameter 'I' is unused
+  // CHECK-FIXES: {{^}}  f([](int  /*I*/) {
+  f([](int I) { return; });
+}
+} // namespace lambda
Index: clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
@@ -8,6 +8,7 @@
 
 #include "UnusedParametersCheck.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Lex/Lexer.h"
@@ -141,7 +142,8 @@
   // Cannot remove parameter for non-local functions.
   if (Function->isExternallyVisible() ||
   !Result.SourceManager->isInMainFile(Function->getLocation()) ||
-  !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function)) {
+  !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function) ||
+  isLambdaCallOperator(Function)) {
 
 // It is illegal to omit parameter name here in C code, so early-out.
 if (!Result.Context->getLangOpts().CPlusPlus)


Index: clang-tools-extra/test/clang-tidy/checkers/misc-unused-parameters.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-unused-parameters.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-unused-parameters.cpp
@@ -276,3 +276,13 @@
 // CHECK-FIXES: {{^}}  B(int  /*i*/) : A() {}{{$}}
 };
 } // namespace strict_mode_off
+
+namespace lambda {
+using fn = void(int);
+void f(fn *);
+void test() {
+  // CHECK-MESSAGES: :[[@LINE+2]]:12: warning: parameter 'I' is unused
+  // CHECK-FIXES: {{^}}  f([](int  /*I*/) {
+  f([](int I) { return; });
+}
+} // namespace lambda
Index: clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
@@ -8,6 +8,7 @@
 
 #include "UnusedParametersCheck.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Lex/Lexer.h"
@@ -141,7 +142,8 @@
   // Cannot remove parameter for non-local functions.
   if (Function->isExternallyVisible() ||
   !Result.SourceManager->isInMainFile(Function->getLocation()) ||
-  !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function)) {
+  !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function) ||
+  isLambdaCallOperator(Function)) {
 
 // It is illegal to omit parameter name here in C code, s

[PATCH] D77680: [clang-tidy] misc-unused-parameters: Don't remove parameter from lambda

2020-04-08 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

In D77680#1968860 , @njames93 wrote:

> Outright disabling for lambdas probably isn't the ideal solution, however 
> it's at least a good stepping stone til a better solution can be found.


I fully agree!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77680/new/

https://reviews.llvm.org/D77680



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


[PATCH] D77680: [clang-tidy] misc-unused-parameters: Don't remove parameter from lambda

2020-04-09 Thread Matthias Gehre via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGeaa55590945a: [clang-tidy] misc-unused-parameters: 
Don't remove parameter from lambda (authored by mgehre).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77680/new/

https://reviews.llvm.org/D77680

Files:
  clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/misc-unused-parameters.cpp


Index: clang-tools-extra/test/clang-tidy/checkers/misc-unused-parameters.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-unused-parameters.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-unused-parameters.cpp
@@ -276,3 +276,13 @@
 // CHECK-FIXES: {{^}}  B(int  /*i*/) : A() {}{{$}}
 };
 } // namespace strict_mode_off
+
+namespace lambda {
+using fn = void(int);
+void f(fn *);
+void test() {
+  // CHECK-MESSAGES: :[[@LINE+2]]:12: warning: parameter 'I' is unused
+  // CHECK-FIXES: {{^}}  f([](int  /*I*/) {
+  f([](int I) { return; });
+}
+} // namespace lambda
Index: clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
@@ -8,6 +8,7 @@
 
 #include "UnusedParametersCheck.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Lex/Lexer.h"
@@ -141,7 +142,8 @@
   // Cannot remove parameter for non-local functions.
   if (Function->isExternallyVisible() ||
   !Result.SourceManager->isInMainFile(Function->getLocation()) ||
-  !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function)) {
+  !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function) ||
+  isLambdaCallOperator(Function)) {
 
 // It is illegal to omit parameter name here in C code, so early-out.
 if (!Result.Context->getLangOpts().CPlusPlus)


Index: clang-tools-extra/test/clang-tidy/checkers/misc-unused-parameters.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-unused-parameters.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-unused-parameters.cpp
@@ -276,3 +276,13 @@
 // CHECK-FIXES: {{^}}  B(int  /*i*/) : A() {}{{$}}
 };
 } // namespace strict_mode_off
+
+namespace lambda {
+using fn = void(int);
+void f(fn *);
+void test() {
+  // CHECK-MESSAGES: :[[@LINE+2]]:12: warning: parameter 'I' is unused
+  // CHECK-FIXES: {{^}}  f([](int  /*I*/) {
+  f([](int I) { return; });
+}
+} // namespace lambda
Index: clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
@@ -8,6 +8,7 @@
 
 #include "UnusedParametersCheck.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Lex/Lexer.h"
@@ -141,7 +142,8 @@
   // Cannot remove parameter for non-local functions.
   if (Function->isExternallyVisible() ||
   !Result.SourceManager->isInMainFile(Function->getLocation()) ||
-  !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function)) {
+  !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function) ||
+  isLambdaCallOperator(Function)) {
 
 // It is illegal to omit parameter name here in C code, so early-out.
 if (!Result.Context->getLangOpts().CPlusPlus)
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D77572: [clang-tidy] add new check readability-use-anyofallof

2020-04-10 Thread Matthias Gehre via Phabricator via cfe-commits
mgehre added a comment.

Thanks @njames93, this is a good examples which I did not consider yet. I agree 
that only transforming
the second loop would make the code worse.

I would argue that a human seeing a warning on the second loop might also 
realize
that the first loop can be transformed in a similar way, and possibly combine 
them into

  return llvm::all_of(getConds(), [](const Init *Cond) { return Val->Cond(); }) 
&& llvm::all_of(getVals(), [](const Init *Val) { return Val->isConcrete(); });

(I was wondering whether the check should have an option to suggest 
`llvm::all_of` (or `boost::algorithm::all_of`, ...) instead of `std::all_of`, 
but
I thought that this could go into another PR.)

I have the feeling that extracting code into algorithms is generally a hard 
topic,
and automatic fixits would possible give a false sense of automatism (at least 
at the current point).
Your example is a good reminder of that.

Personally, clang-tidy has been a good source of learning C++ best practices. 
And I hope that this clang-tidy check would help
me and my coworkers to remember using those algorithms.

Are you saying that this check should not land unless its scope is extended? 
What would be the minimal scope making this check
worth-while to land?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77572/new/

https://reviews.llvm.org/D77572



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


  1   2   >