r332576 - Fix rL332458: [AST] Added a helper to extract a user-friendly text of a comment.

2018-05-16 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Wed May 16 23:46:15 2018
New Revision: 332576

URL: http://llvm.org/viewvc/llvm-project?rev=332576&view=rev
Log:
Fix rL332458: [AST] Added a helper to extract a user-friendly text of a comment.

Older gcc versions do not support raw string literals within macros.

Modified:
cfe/trunk/unittests/AST/CommentTextTest.cpp

Modified: cfe/trunk/unittests/AST/CommentTextTest.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/CommentTextTest.cpp?rev=332576&r1=332575&r2=332576&view=diff
==
--- cfe/trunk/unittests/AST/CommentTextTest.cpp (original)
+++ cfe/trunk/unittests/AST/CommentTextTest.cpp Wed May 16 23:46:15 2018
@@ -58,49 +58,54 @@ For example,
this result.
 That's about it.)";
   // Two-slash comments.
-  EXPECT_EQ(ExpectedOutput, formatComment(
+  auto Formatted = formatComment(
 R"cpp(
 // This function does this and that.
 // For example,
 //Runnning it in that case will give you
 //this result.
-// That's about it.)cpp"));
+// That's about it.)cpp");
+  EXPECT_EQ(ExpectedOutput, Formatted);
 
   // Three-slash comments.
-  EXPECT_EQ(ExpectedOutput, formatComment(
+  Formatted = formatComment(
 R"cpp(
 /// This function does this and that.
 /// For example,
 ///Runnning it in that case will give you
 ///this result.
-/// That's about it.)cpp"));
+/// That's about it.)cpp");
+  EXPECT_EQ(ExpectedOutput, Formatted);
 
   // Block comments.
-  EXPECT_EQ(ExpectedOutput, formatComment(
+  Formatted = formatComment(
 R"cpp(
 /* This function does this and that.
  * For example,
  *Runnning it in that case will give you
  *this result.
- * That's about it.*/)cpp"));
+ * That's about it.*/)cpp");
+  EXPECT_EQ(ExpectedOutput, Formatted);
 
   // Doxygen-style block comments.
-  EXPECT_EQ(ExpectedOutput, formatComment(
+  Formatted = formatComment(
 R"cpp(
 /** This function does this and that.
   * For example,
   *Runnning it in that case will give you
   *this result.
-  * That's about it.*/)cpp"));
+  * That's about it.*/)cpp");
+  EXPECT_EQ(ExpectedOutput, Formatted);
 
   // Weird indentation.
-  EXPECT_EQ(ExpectedOutput, formatComment(
+  Formatted = formatComment(
 R"cpp(
// This function does this and that.
   //  For example,
   // Runnning it in that case will give you
 //   this result.
-   // That's about it.)cpp"));
+   // That's about it.)cpp");
+  EXPECT_EQ(ExpectedOutput, Formatted);
   // clang-format on
 }
 
@@ -111,11 +116,12 @@ R"(\brief This is the brief part of the
 \param a something about a.
 @param b something about b.)";
 
-  EXPECT_EQ(ExpectedOutput, formatComment(
+  auto Formatted = formatComment(
 R"cpp(
 /// \brief This is the brief part of the comment.
 /// \param a something about a.
-/// @param b something about b.)cpp"));
+/// @param b something about b.)cpp");
+  EXPECT_EQ(ExpectedOutput, Formatted);
   // clang-format on
 }
 


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


Re: r332458 - [AST] Added a helper to extract a user-friendly text of a comment.

2018-05-17 Thread Clement Courbet via cfe-commits
I should have fixed it in r332576.

On Wed, May 16, 2018 at 11:49 PM, Galina Kistanova via cfe-commits <
cfe-commits@lists.llvm.org> wrote:

> Also few other builders are affected:
>
> http://lab.llvm.org:8011/builders/clang-x86_64-linux-abi-test
> http://lab.llvm.org:8011/builders/clang-lld-x86_64-2stage
> http://lab.llvm.org:8011/builders/clang-with-lto-ubuntu
>
>
> Thanks
>
> Galina
>
> On Wed, May 16, 2018 at 12:58 PM, Galina Kistanova 
> wrote:
>
>> Hello Ilya,
>>
>> This commit broke build step for couple of our builders:
>>
>> http://lab.llvm.org:8011/builders/clang-with-lto-ubuntu/builds/8541
>> http://lab.llvm.org:8011/builders/clang-with-thin-lto-ubuntu
>>
>> . . .
>> FAILED: 
>> tools/clang/unittests/AST/CMakeFiles/ASTTests.dir/CommentTextTest.cpp.o
>>
>> /usr/bin/c++   -DGTEST_HAS_RTTI=0 -DGTEST_HAS_TR1_TUPLE=0
>> -DGTEST_LANG_CXX11=1 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS
>> -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Itools/clang/unittests/AST
>> -I/home/buildslave/buildslave1a/clang-with-lto-ubuntu/llvm.src/tools/clang/unittests/AST
>> -I/home/buildslave/buildslave1a/clang-with-lto-ubuntu/llvm.src/tools/clang/include
>> -Itools/clang/include -Iinclude -I/home/buildslave/buildslave1
>> a/clang-with-lto-ubuntu/llvm.src/include -I/home/buildslave/buildslave1
>> a/clang-with-lto-ubuntu/llvm.src/utils/unittest/googletest/include
>> -I/home/buildslave/buildslave1a/clang-with-lto-ubuntu/llvm.
>> src/utils/unittest/googlemock/include -fPIC -fvisibility-inlines-hidden
>> -std=c++11 -Wall -W -Wno-unused-parameter -Wwrite-strings -Wcast-qual
>> -Wno-missing-field-initializers -pedantic -Wno-long-long
>> -Wno-maybe-uninitialized -Wdelete-non-virtual-dtor -Wno-comment
>> -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual
>> -fno-strict-aliasing -O3 -DNDEBUG-Wno-variadic-macros -fno-exceptions
>> -fno-rtti -MD -MT tools/clang/unittests/AST/CMak
>> eFiles/ASTTests.dir/CommentTextTest.cpp.o -MF
>> tools/clang/unittests/AST/CMakeFiles/ASTTests.dir/CommentTextTest.cpp.o.d
>> -o tools/clang/unittests/AST/CMakeFiles/ASTTests.dir/CommentTextTest.cpp.o
>> -c /home/buildslave/buildslave1a/clang-with-lto-ubuntu/llvm.src
>> /tools/clang/unittests/AST/CommentTextTest.cpp
>> /home/buildslave/buildslave1a/clang-with-lto-ubuntu/llvm.src
>> /tools/clang/unittests/AST/CommentTextTest.cpp:62:1: error: unterminated
>> raw string
>>  R"cpp(
>>  ^
>> . . .
>>
>> Please have a look?
>>
>> The builder was already red and did not send notifications.
>>
>> Thanks
>>
>> Galina
>>
>>
>>
>> On Wed, May 16, 2018 at 5:30 AM, Ilya Biryukov via cfe-commits <
>> cfe-commits@lists.llvm.org> wrote:
>>
>>> Author: ibiryukov
>>> Date: Wed May 16 05:30:09 2018
>>> New Revision: 332458
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=332458&view=rev
>>> Log:
>>> [AST] Added a helper to extract a user-friendly text of a comment.
>>>
>>> Summary:
>>> The helper is used in clangd for documentation shown in code completion
>>> and storing the docs in the symbols. See D45999.
>>>
>>> This patch reuses the code of the Doxygen comment lexer, disabling the
>>> bits that do command and html tag parsing.
>>> The new helper works on all comments, including non-doxygen comments.
>>> However, it does not understand or transform any doxygen directives,
>>> i.e. cannot extract brief text, etc.
>>>
>>> Reviewers: sammccall, hokein, ioeric
>>>
>>> Reviewed By: ioeric
>>>
>>> Subscribers: mgorny, cfe-commits
>>>
>>> Differential Revision: https://reviews.llvm.org/D46000
>>>
>>> Added:
>>> cfe/trunk/unittests/AST/CommentTextTest.cpp
>>> Modified:
>>> cfe/trunk/include/clang/AST/CommentLexer.h
>>> cfe/trunk/include/clang/AST/RawCommentList.h
>>> cfe/trunk/lib/AST/CommentLexer.cpp
>>> cfe/trunk/lib/AST/RawCommentList.cpp
>>> cfe/trunk/unittests/AST/CMakeLists.txt
>>>
>>> Modified: cfe/trunk/include/clang/AST/CommentLexer.h
>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>>> AST/CommentLexer.h?rev=332458&r1=332457&r2=332458&view=diff
>>> 
>>> ==
>>> --- cfe/trunk/include/clang/AST/CommentLexer.h (original)
>>> +++ cfe/trunk/include/clang/AST/CommentLexer.h Wed May 16 05:30:09 2018
>>> @@ -281,6 +281,11 @@ private:
>>>/// command, including command marker.
>>>SmallString<16> VerbatimBlockEndCommandName;
>>>
>>> +  /// If true, the commands, html tags, etc will be parsed and reported
>>> as
>>> +  /// separate tokens inside the comment body. If false, the comment
>>> text will
>>> +  /// be parsed into text and newline tokens.
>>> +  bool ParseCommands;
>>> +
>>>/// Given a character reference name (e.g., "lt"), return the
>>> character that
>>>/// it stands for (e.g., "<").
>>>StringRef resolveHTMLNamedCharacterReference(StringRef Name) const;
>>> @@ -315,12 +320,11 @@ private:
>>>/// Eat string matching regexp \code \s*\* \endcode.
>>>void skipLineStartingDecorations();
>>>
>>> -  /// Lex s

[clang-tools-extra] r333066 - [clang-tidy] new cppcoreguidelines-narrowing-conversions check.

2018-05-23 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Wed May 23 00:58:41 2018
New Revision: 333066

URL: http://llvm.org/viewvc/llvm-project?rev=333066&view=rev
Log:
[clang-tidy] new cppcoreguidelines-narrowing-conversions check.

Summary:
Checks for narrowing conversions, e.g.

int i = 0;
i += 0.1;

This has what some might consider false positives for:
i += ceil(d);

Reviewers: alexfh, hokein

Subscribers: srhines, nemanjai, mgorny, JDevlieghere, xazax.hun, kbarton

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

Added:

clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp

clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.h

clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.rst

clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp
Modified:
clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp
clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt
clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt

clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
clang-tools-extra/trunk/docs/ReleaseNotes.rst
clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst

Modified: clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp?rev=333066&r1=333065&r2=333066&view=diff
==
--- clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp 
(original)
+++ clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp Wed May 
23 00:58:41 2018
@@ -10,6 +10,7 @@
 #include "../ClangTidy.h"
 #include "../ClangTidyModule.h"
 #include "../ClangTidyModuleRegistry.h"
+#include "../cppcoreguidelines/NarrowingConversionsCheck.h"
 #include "ArgumentCommentCheck.h"
 #include "AssertSideEffectCheck.h"
 #include "BoolPointerImplicitConversionCheck.h"
@@ -92,6 +93,8 @@ public:
 "bugprone-move-forwarding-reference");
 CheckFactories.registerCheck(
 "bugprone-multiple-statement-macro");
+CheckFactories.registerCheck(
+"bugprone-narrowing-conversions");
 CheckFactories.registerCheck(
 "bugprone-parent-virtual-call");
 CheckFactories.registerCheck(

Modified: clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt?rev=333066&r1=333065&r2=333066&view=diff
==
--- clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt Wed May 23 
00:58:41 2018
@@ -48,6 +48,7 @@ add_clang_library(clangTidyBugproneModul
   clangBasic
   clangLex
   clangTidy
+  clangTidyCppCoreGuidelinesModule
   clangTidyUtils
   clangTooling
   )

Modified: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt?rev=333066&r1=333065&r2=333066&view=diff
==
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt 
(original)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt Wed May 
23 00:58:41 2018
@@ -4,6 +4,7 @@ add_clang_library(clangTidyCppCoreGuidel
   AvoidGotoCheck.cpp
   CppCoreGuidelinesTidyModule.cpp
   InterfacesGlobalInitCheck.cpp
+  NarrowingConversionsCheck.cpp
   NoMallocCheck.cpp
   OwningMemoryCheck.cpp
   ProBoundsArrayToPointerDecayCheck.cpp

Modified: 
clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp?rev=333066&r1=333065&r2=333066&view=diff
==
--- 
clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
 (original)
+++ 
clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
 Wed May 23 00:58:41 2018
@@ -13,6 +13,7 @@
 #include "../misc/UnconventionalAssignOperatorCheck.h"
 #include "AvoidGotoCheck.h"
 #include "InterfacesGlobalInitCheck.h"
+#include "NarrowingConversionsCheck.h"
 #include "NoMallocCheck.h"
 #include "OwningMemoryCheck.h"
 #include "ProBoundsArrayToPointerDecayCheck.h"
@@ -40,6 +41,8 @@ public:
 "cppcoreguidelines-avoid-goto");
 CheckFactories.registerCheck(
 "cppcoreguidelines-interfaces-global-init");
+CheckFactories.registerCheck(
+"cppcoreguidelines-narrowing-conversions");
 CheckFactories.registerCheck("cppcoreguidelines-no-malloc");
 CheckFactories.registerCheck(
 

[clang-tools-extra] r351308 - [clang-tidy] bugprone-string-constructor: Catch string from nullptr.

2019-01-16 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Wed Jan 16 00:36:23 2019
New Revision: 351308

URL: http://llvm.org/viewvc/llvm-project?rev=351308&view=rev
Log:
[clang-tidy] bugprone-string-constructor: Catch string from nullptr.

Summary: Context: https://twitter.com/willkirkby/status/1084219580799741953

Subscribers: xazax.hun, cfe-commits

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

Modified:
clang-tools-extra/trunk/clang-tidy/bugprone/StringConstructorCheck.cpp
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-constructor.cpp

Modified: clang-tools-extra/trunk/clang-tidy/bugprone/StringConstructorCheck.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/bugprone/StringConstructorCheck.cpp?rev=351308&r1=351307&r2=351308&view=diff
==
--- clang-tools-extra/trunk/clang-tidy/bugprone/StringConstructorCheck.cpp 
(original)
+++ clang-tools-extra/trunk/clang-tidy/bugprone/StringConstructorCheck.cpp Wed 
Jan 16 00:36:23 2019
@@ -100,6 +100,15 @@ void StringConstructorCheck::registerMat
integerLiteral().bind("int"))
   .bind("constructor"),
   this);
+
+  // Check the literal string constructor with char pointer.
+  // [i.e. string (const char* s);]
+  Finder->addMatcher(
+  cxxConstructExpr(hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+   hasArgument(0, expr().bind("from-ptr")),
+   hasArgument(1, unless(hasType(isInteger()
+  .bind("constructor"),
+  this);
 }
 
 void StringConstructorCheck::check(const MatchFinder::MatchResult &Result) {
@@ -128,6 +137,13 @@ void StringConstructorCheck::check(const
 if (Lit->getValue().ugt(Str->getLength())) {
   diag(Loc, "length is bigger then string literal size");
 }
+  } else if (const auto *Ptr = Result.Nodes.getNodeAs("from-ptr")) {
+Expr::EvalResult ConstPtr;
+if (Ptr->EvaluateAsRValue(ConstPtr, Ctx) &&
+((ConstPtr.Val.isInt() && ConstPtr.Val.getInt().isNullValue()) ||
+ (ConstPtr.Val.isLValue() && ConstPtr.Val.isNullPointer( {
+  diag(Loc, "constructing string from nullptr is undefined behaviour");
+}
   }
 }
 

Modified: 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-constructor.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/bugprone-string-constructor.cpp?rev=351308&r1=351307&r2=351308&view=diff
==
--- clang-tools-extra/trunk/test/clang-tidy/bugprone-string-constructor.cpp 
(original)
+++ clang-tools-extra/trunk/test/clang-tidy/bugprone-string-constructor.cpp Wed 
Jan 16 00:36:23 2019
@@ -9,6 +9,7 @@ template  string;
@@ -45,6 +46,15 @@ void Test() {
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string 
literal size
   std::string q5(kText3,  0x100);
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+  std::string q6(nullptr);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructing string from nullptr 
is undefined behaviour
+  std::string q7 = 0;
+  // CHECK-MESSAGES: [[@LINE-1]]:20: warning: constructing string from nullptr 
is undefined behaviour
+}
+
+std::string StringFromZero() {
+  return 0;
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: constructing string from nullptr 
is undefined behaviour
 }
 
 void Valid() {
@@ -53,4 +63,5 @@ void Valid() {
   std::wstring wstr(4, L'x');
   std::string s1("test", 4);
   std::string s2("test", 3);
+  std::string s3("test");
 }


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


r347453 - [ASTMatchers] Re-generate ast matchers doc after rL346455.

2018-11-22 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Thu Nov 22 02:44:36 2018
New Revision: 347453

URL: http://llvm.org/viewvc/llvm-project?rev=347453&view=rev
Log:
[ASTMatchers] Re-generate ast matchers doc after rL346455.

Modified:
cfe/trunk/docs/LibASTMatchersReference.html

Modified: cfe/trunk/docs/LibASTMatchersReference.html
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LibASTMatchersReference.html?rev=347453&r1=347452&r2=347453&view=diff
==
--- cfe/trunk/docs/LibASTMatchersReference.html (original)
+++ cfe/trunk/docs/LibASTMatchersReference.html Thu Nov 22 02:44:36 2018
@@ -795,6 +795,17 @@ Example matches a ? b : c
 
 
 
+MatcherStmt>constantExprMatcherConstantExpr>...
+Matches a constant 
expression wrapper.
+
+Example matches the constant in the case statement:
+(matcher = constantExpr())
+  switch (a) {
+  case 37: break;
+  }
+
+
+
 MatcherStmt>continueStmtMatcherContinueStmt>...
 Matches continue 
statements.
 


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


r347462 - [ASTMatchers] Add hasSideEffect() matcher.

2018-11-22 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Thu Nov 22 06:00:56 2018
New Revision: 347462

URL: http://llvm.org/viewvc/llvm-project?rev=347462&view=rev
Log:
[ASTMatchers] Add hasSideEffect() matcher.

Summary: Exposes Expr::HasSideEffects.

Reviewers: aaron.ballman

Subscribers: cfe-commits

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

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

Modified: cfe/trunk/docs/LibASTMatchersReference.html
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LibASTMatchersReference.html?rev=347462&r1=347461&r2=347462&view=diff
==
--- cfe/trunk/docs/LibASTMatchersReference.html (original)
+++ cfe/trunk/docs/LibASTMatchersReference.html Thu Nov 22 06:00:56 2018
@@ -2817,6 +2817,24 @@ enum class Y {};
 
 
 
+MatcherExpr>hasSideEffects
+Matches expressions 
with potential side effects other than producing
+a value, such as a calling a function, throwing an exception, or reading a
+volatile variable.
+
+Given
+  void f(int& a, int b, volatile int c) {
+call();
+a = 0;
+a;
+b;
+c;
+  }
+expr(hasSideEffects())
+  matches 'call()', 'a = 0', 'c', but not '0', 'a', 'b'.
+
+
+
 MatcherExpr>isInstantiationDependent
 Matches 
expressions that are instantiation-dependent even if it is
 neither type- nor value-dependent.

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=347462&r1=347461&r2=347462&view=diff
==
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Thu Nov 22 06:00:56 2018
@@ -4118,6 +4118,26 @@ AST_MATCHER_P(IfStmt, hasConditionVariab
  InnerMatcher.matches(*DeclarationStatement, Finder, Builder);
 }
 
+/// \brief Matches expressions with potential side effects other than producing
+/// a value, such as a calling a function, throwing an exception, or reading a
+/// volatile variable.
+///
+/// Given
+/// \code
+///   void f(int& a, int b, volatile int c) {
+/// call();
+/// a = 0;
+/// a;
+/// b;
+/// c;
+///   }
+/// \endcode
+/// expr(hasSideEffects())
+///   matches 'call()', 'a = 0', 'c', but not '0', 'a', 'b'.
+AST_MATCHER(Expr, hasSideEffects) {
+  return Node.HasSideEffects(Finder->getASTContext());
+}
+
 /// Matches the index expression of an array subscript expression.
 ///
 /// Given

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=347462&r1=347461&r2=347462&view=diff
==
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Thu Nov 22 06:00:56 2018
@@ -294,6 +294,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(hasReturnValue);
   REGISTER_MATCHER(hasRHS);
   REGISTER_MATCHER(hasSelector);
+  REGISTER_MATCHER(hasSideEffects);
   REGISTER_MATCHER(hasSingleDecl);
   REGISTER_MATCHER(hasSize);
   REGISTER_MATCHER(hasSizeExpr);

Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp?rev=347462&r1=347461&r2=347462&view=diff
==
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Thu Nov 22 
06:00:56 2018
@@ -2259,5 +2259,21 @@ TEST(Matcher, isMain) {
 notMatches("int main2() {}", functionDecl(isMain(;
 }
 
+TEST(Matcher, hasSideEffects) {
+  EXPECT_TRUE(matches("void call();"
+  "void f() { call(); }",
+  expr(hasSideEffects(;
+  EXPECT_TRUE(matches("void f(int& a) { a = 0; }", expr(hasSideEffects(;
+  EXPECT_TRUE(
+  matches("void f(volatile int a) { (void)a; }", expr(hasSideEffects(;
+
+  EXPECT_TRUE(notMatches("void call();"
+ "void f() { }",
+ expr(hasSideEffects(;
+  EXPECT_TRUE(
+  notMatches("void f(int& a) { (void)a; }", expr(hasSideEffects(;
+  EXPECT_TRUE(notMatches("void f(int a) { (void)a; }", 
expr(hasSideEffects(;
+}
+
 } // namespace ast_matchers
 } // namespace clang


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


r347463 - Revert rL347462 "[ASTMatchers] Add hasSideEffect() matcher."

2018-11-22 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Thu Nov 22 06:26:33 2018
New Revision: 347463

URL: http://llvm.org/viewvc/llvm-project?rev=347463&view=rev
Log:
Revert rL347462 "[ASTMatchers] Add hasSideEffect() matcher."

Breaks some buildbots.

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

Modified: cfe/trunk/docs/LibASTMatchersReference.html
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LibASTMatchersReference.html?rev=347463&r1=347462&r2=347463&view=diff
==
--- cfe/trunk/docs/LibASTMatchersReference.html (original)
+++ cfe/trunk/docs/LibASTMatchersReference.html Thu Nov 22 06:26:33 2018
@@ -2817,24 +2817,6 @@ enum class Y {};
 
 
 
-MatcherExpr>hasSideEffects
-Matches expressions 
with potential side effects other than producing
-a value, such as a calling a function, throwing an exception, or reading a
-volatile variable.
-
-Given
-  void f(int& a, int b, volatile int c) {
-call();
-a = 0;
-a;
-b;
-c;
-  }
-expr(hasSideEffects())
-  matches 'call()', 'a = 0', 'c', but not '0', 'a', 'b'.
-
-
-
 MatcherExpr>isInstantiationDependent
 Matches 
expressions that are instantiation-dependent even if it is
 neither type- nor value-dependent.

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=347463&r1=347462&r2=347463&view=diff
==
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Thu Nov 22 06:26:33 2018
@@ -4118,26 +4118,6 @@ AST_MATCHER_P(IfStmt, hasConditionVariab
  InnerMatcher.matches(*DeclarationStatement, Finder, Builder);
 }
 
-/// \brief Matches expressions with potential side effects other than producing
-/// a value, such as a calling a function, throwing an exception, or reading a
-/// volatile variable.
-///
-/// Given
-/// \code
-///   void f(int& a, int b, volatile int c) {
-/// call();
-/// a = 0;
-/// a;
-/// b;
-/// c;
-///   }
-/// \endcode
-/// expr(hasSideEffects())
-///   matches 'call()', 'a = 0', 'c', but not '0', 'a', 'b'.
-AST_MATCHER(Expr, hasSideEffects) {
-  return Node.HasSideEffects(Finder->getASTContext());
-}
-
 /// Matches the index expression of an array subscript expression.
 ///
 /// Given

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=347463&r1=347462&r2=347463&view=diff
==
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Thu Nov 22 06:26:33 2018
@@ -294,7 +294,6 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(hasReturnValue);
   REGISTER_MATCHER(hasRHS);
   REGISTER_MATCHER(hasSelector);
-  REGISTER_MATCHER(hasSideEffects);
   REGISTER_MATCHER(hasSingleDecl);
   REGISTER_MATCHER(hasSize);
   REGISTER_MATCHER(hasSizeExpr);

Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp?rev=347463&r1=347462&r2=347463&view=diff
==
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Thu Nov 22 
06:26:33 2018
@@ -2259,21 +2259,5 @@ TEST(Matcher, isMain) {
 notMatches("int main2() {}", functionDecl(isMain(;
 }
 
-TEST(Matcher, hasSideEffects) {
-  EXPECT_TRUE(matches("void call();"
-  "void f() { call(); }",
-  expr(hasSideEffects(;
-  EXPECT_TRUE(matches("void f(int& a) { a = 0; }", expr(hasSideEffects(;
-  EXPECT_TRUE(
-  matches("void f(volatile int a) { (void)a; }", expr(hasSideEffects(;
-
-  EXPECT_TRUE(notMatches("void call();"
- "void f() { }",
- expr(hasSideEffects(;
-  EXPECT_TRUE(
-  notMatches("void f(int& a) { (void)a; }", expr(hasSideEffects(;
-  EXPECT_TRUE(notMatches("void f(int a) { (void)a; }", 
expr(hasSideEffects(;
-}
-
 } // namespace ast_matchers
 } // namespace clang


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


r348239 - [WIP][Sema] Improve static_assert diagnostics for type traits.

2018-12-04 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Mon Dec  3 23:59:57 2018
New Revision: 348239

URL: http://llvm.org/viewvc/llvm-project?rev=348239&view=rev
Log:
[WIP][Sema] Improve static_assert diagnostics for type traits.

Summary:
In our codebase, `static_assert(std::some_type_trait::value, "msg")`
(where `some_type_trait` is an std type_trait and `Ts...` is the
appropriate template parameters) account for 11.2% of the `static_assert`s.

In these cases, the `Ts` are typically not spelled out explicitly, e.g.
`static_assert(std::is_same::value, "message");`

The diagnostic when the assert fails is typically not very useful, e.g.
`static_assert failed due to requirement 'std::is_same::value' "message"`

This change makes the diagnostic spell out the types explicitly , e.g.
`static_assert failed due to requirement 'std::is_same::value' 
"message"`

See tests for more examples.

After this is submitted, I intend to handle
`static_assert(!std::some_type_trait::value, "msg")`,
which is another 6.6% of static_asserts.

Subscribers: cfe-commits

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

Added:
cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp
Modified:
cfe/trunk/include/clang/AST/NestedNameSpecifier.h
cfe/trunk/lib/AST/NestedNameSpecifier.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/SemaCXX/static-assert.cpp

Modified: cfe/trunk/include/clang/AST/NestedNameSpecifier.h
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/NestedNameSpecifier.h?rev=348239&r1=348238&r2=348239&view=diff
==
--- cfe/trunk/include/clang/AST/NestedNameSpecifier.h (original)
+++ cfe/trunk/include/clang/AST/NestedNameSpecifier.h Mon Dec  3 23:59:57 2018
@@ -212,9 +212,12 @@ public:
   /// parameter pack (for C++11 variadic templates).
   bool containsUnexpandedParameterPack() const;
 
-  /// Print this nested name specifier to the given output
-  /// stream.
-  void print(raw_ostream &OS, const PrintingPolicy &Policy) const;
+  /// Print this nested name specifier to the given output stream. If
+  /// `ResolveTemplateArguments` is true, we'll print actual types, e.g.
+  /// `ns::SomeTemplate` instead of
+  /// `ns::SomeTemplate`.
+  void print(raw_ostream &OS, const PrintingPolicy &Policy,
+ bool ResolveTemplateArguments = false) const;
 
   void Profile(llvm::FoldingSetNodeID &ID) const {
 ID.AddPointer(Prefix.getOpaqueValue());

Modified: cfe/trunk/lib/AST/NestedNameSpecifier.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NestedNameSpecifier.cpp?rev=348239&r1=348238&r2=348239&view=diff
==
--- cfe/trunk/lib/AST/NestedNameSpecifier.cpp (original)
+++ cfe/trunk/lib/AST/NestedNameSpecifier.cpp Mon Dec  3 23:59:57 2018
@@ -16,6 +16,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/TemplateName.h"
 #include "clang/AST/Type.h"
@@ -270,9 +271,8 @@ bool NestedNameSpecifier::containsUnexpa
 
 /// Print this nested name specifier to the given output
 /// stream.
-void
-NestedNameSpecifier::print(raw_ostream &OS,
-   const PrintingPolicy &Policy) const {
+void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
+bool ResolveTemplateArguments) const {
   if (getPrefix())
 getPrefix()->print(OS, Policy);
 
@@ -305,6 +305,15 @@ NestedNameSpecifier::print(raw_ostream &
 LLVM_FALLTHROUGH;
 
   case TypeSpec: {
+const auto *Record =
+
dyn_cast_or_null(getAsRecordDecl());
+if (ResolveTemplateArguments && Record) {
+// Print the type trait with resolved template parameters.
+Record->printName(OS);
+printTemplateArgumentList(OS, Record->getTemplateArgs().asArray(),
+  Policy);
+break;
+}
 const Type *T = getAsType();
 
 PrintingPolicy InnerPolicy(Policy);

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=348239&r1=348238&r2=348239&view=diff
==
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Dec  3 23:59:57 2018
@@ -3052,6 +3052,28 @@ static Expr *lookThroughRangesV3Conditio
   return Cond;
 }
 
+// Print a diagnostic for the failing static_assert expression. Defaults to
+// pretty-printing the expression.
+static void prettyPrintFailedBooleanCondition(llvm::raw_string_ostream &OS,
+  const Expr *FailedCond,
+  const PrintingPolicy &Policy) {
+  const auto *DR = dyn_cast(FailedCond);
+  if (DR && DR->getQualifier()) {
+// If this is a

r348741 - [Sema] Further improvements to to static_assert diagnostics.

2018-12-10 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Mon Dec 10 00:19:38 2018
New Revision: 348741

URL: http://llvm.org/viewvc/llvm-project?rev=348741&view=rev
Log:
[Sema] Further improvements to to static_assert diagnostics.

Summary:
We're now handling cases like `static_assert(!expr)` and
static_assert(!(expr))`.

Reviewers: aaron.ballman, Quuxplusone

Subscribers: cfe-commits

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

Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/PCH/cxx-static_assert.cpp
cfe/trunk/test/Sema/static-assert.c
cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp
cfe/trunk/test/SemaCXX/static-assert.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=348741&r1=348740&r2=348741&view=diff
==
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Dec 10 00:19:38 2018
@@ -2861,11 +2861,7 @@ public:
 
   /// Find the failed Boolean condition within a given Boolean
   /// constant expression, and describe it with a string.
-  ///
-  /// \param AllowTopLevelCond Whether to allow the result to be the
-  /// complete top-level condition.
-  std::pair
-  findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond);
+  std::pair findFailedBooleanCondition(Expr *Cond);
 
   /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
   /// non-ArgDependent DiagnoseIfAttrs.

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=348741&r1=348740&r2=348741&view=diff
==
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Dec 10 00:19:38 2018
@@ -13878,8 +13878,7 @@ Decl *Sema::BuildStaticAssertDeclaration
   Expr *InnerCond = nullptr;
   std::string InnerCondDescription;
   std::tie(InnerCond, InnerCondDescription) =
-findFailedBooleanCondition(Converted.get(),
-   /*AllowTopLevelCond=*/false);
+findFailedBooleanCondition(Converted.get());
   if (InnerCond) {
 Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)
   << InnerCondDescription << !AssertMessage

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=348741&r1=348740&r2=348741&view=diff
==
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Dec 10 00:19:38 2018
@@ -3052,30 +3052,42 @@ static Expr *lookThroughRangesV3Conditio
   return Cond;
 }
 
-// Print a diagnostic for the failing static_assert expression. Defaults to
-// pretty-printing the expression.
-static void prettyPrintFailedBooleanCondition(llvm::raw_string_ostream &OS,
-  const Expr *FailedCond,
-  const PrintingPolicy &Policy) {
-  const auto *DR = dyn_cast(FailedCond);
-  if (DR && DR->getQualifier()) {
-// If this is a qualified name, expand the template arguments in nested
-// qualifiers.
-DR->getQualifier()->print(OS, Policy, true);
-// Then print the decl itself.
-const ValueDecl *VD = DR->getDecl();
-OS << VD->getName();
-if (const auto *IV = dyn_cast(VD)) {
-  // This is a template variable, print the expanded template arguments.
-  printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
+namespace {
+
+// A PrinterHelper that prints more helpful diagnostics for some 
sub-expressions
+// within failing boolean expression, such as substituting template parameters
+// for actual types.
+class FailedBooleanConditionPrinterHelper : public PrinterHelper {
+public:
+  explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &Policy)
+  : Policy(Policy) {}
+
+  bool handledStmt(Stmt *E, raw_ostream &OS) override {
+const auto *DR = dyn_cast(E);
+if (DR && DR->getQualifier()) {
+  // If this is a qualified name, expand the template arguments in nested
+  // qualifiers.
+  DR->getQualifier()->print(OS, Policy, true);
+  // Then print the decl itself.
+  const ValueDecl *VD = DR->getDecl();
+  OS << VD->getName();
+  if (const auto *IV = dyn_cast(VD)) {
+// This is a template variable, print the expanded template arguments.
+printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
+  }
+  return true;
 }
-return;
+return false;
   }
-  FailedCond->printPretty(OS, nullptr, Policy);
-}
+
+private:
+  const PrintingPolicy &Policy;
+};
+
+} // end anonymous namespace
 
 std::pair
-Sem

r348742 - Revert r348741 "[Sema] Further improvements to to static_assert diagnostics."

2018-12-10 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Mon Dec 10 00:53:17 2018
New Revision: 348742

URL: http://llvm.org/viewvc/llvm-project?rev=348742&view=rev
Log:
Revert r348741 "[Sema] Further improvements to to static_assert diagnostics."

Seems to break build bots.

Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/PCH/cxx-static_assert.cpp
cfe/trunk/test/Sema/static-assert.c
cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp
cfe/trunk/test/SemaCXX/static-assert.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=348742&r1=348741&r2=348742&view=diff
==
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Dec 10 00:53:17 2018
@@ -2861,7 +2861,11 @@ public:
 
   /// Find the failed Boolean condition within a given Boolean
   /// constant expression, and describe it with a string.
-  std::pair findFailedBooleanCondition(Expr *Cond);
+  ///
+  /// \param AllowTopLevelCond Whether to allow the result to be the
+  /// complete top-level condition.
+  std::pair
+  findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond);
 
   /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
   /// non-ArgDependent DiagnoseIfAttrs.

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=348742&r1=348741&r2=348742&view=diff
==
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Dec 10 00:53:17 2018
@@ -13878,7 +13878,8 @@ Decl *Sema::BuildStaticAssertDeclaration
   Expr *InnerCond = nullptr;
   std::string InnerCondDescription;
   std::tie(InnerCond, InnerCondDescription) =
-findFailedBooleanCondition(Converted.get());
+findFailedBooleanCondition(Converted.get(),
+   /*AllowTopLevelCond=*/false);
   if (InnerCond) {
 Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)
   << InnerCondDescription << !AssertMessage

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=348742&r1=348741&r2=348742&view=diff
==
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Dec 10 00:53:17 2018
@@ -3052,42 +3052,30 @@ static Expr *lookThroughRangesV3Conditio
   return Cond;
 }
 
-namespace {
-
-// A PrinterHelper that prints more helpful diagnostics for some 
sub-expressions
-// within failing boolean expression, such as substituting template parameters
-// for actual types.
-class FailedBooleanConditionPrinterHelper : public PrinterHelper {
-public:
-  explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &Policy)
-  : Policy(Policy) {}
-
-  bool handledStmt(Stmt *E, raw_ostream &OS) override {
-const auto *DR = dyn_cast(E);
-if (DR && DR->getQualifier()) {
-  // If this is a qualified name, expand the template arguments in nested
-  // qualifiers.
-  DR->getQualifier()->print(OS, Policy, true);
-  // Then print the decl itself.
-  const ValueDecl *VD = DR->getDecl();
-  OS << VD->getName();
-  if (const auto *IV = dyn_cast(VD)) {
-// This is a template variable, print the expanded template arguments.
-printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
-  }
-  return true;
+// Print a diagnostic for the failing static_assert expression. Defaults to
+// pretty-printing the expression.
+static void prettyPrintFailedBooleanCondition(llvm::raw_string_ostream &OS,
+  const Expr *FailedCond,
+  const PrintingPolicy &Policy) {
+  const auto *DR = dyn_cast(FailedCond);
+  if (DR && DR->getQualifier()) {
+// If this is a qualified name, expand the template arguments in nested
+// qualifiers.
+DR->getQualifier()->print(OS, Policy, true);
+// Then print the decl itself.
+const ValueDecl *VD = DR->getDecl();
+OS << VD->getName();
+if (const auto *IV = dyn_cast(VD)) {
+  // This is a template variable, print the expanded template arguments.
+  printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
 }
-return false;
+return;
   }
-
-private:
-  const PrintingPolicy &Policy;
-};
-
-} // end anonymous namespace
+  FailedCond->printPretty(OS, nullptr, Policy);
+}
 
 std::pair
-Sema::findFailedBooleanCondition(Expr *Cond) {
+Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
 

r348830 - [Sema]improve static_assert(!expr)

2018-12-10 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Mon Dec 10 23:04:49 2018
New Revision: 348830

URL: http://llvm.org/viewvc/llvm-project?rev=348830&view=rev
Log:
[Sema]improve static_assert(!expr)

Modified:
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/SemaCXX/static-assert.cpp

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=348830&r1=348829&r2=348830&view=diff
==
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Dec 10 23:04:49 2018
@@ -3071,6 +3071,20 @@ static void prettyPrintFailedBooleanCond
 }
 return;
   }
+  if (const auto *Paren = dyn_cast(FailedCond)) {
+OS << "(";
+prettyPrintFailedBooleanCondition(OS, Paren->getSubExpr(), Policy);
+OS << ")";
+return;
+  }
+  // If this is !(BooleanExpression), try pretty-printing the inner expression.
+  const auto *UnaryOp = dyn_cast(FailedCond);
+  if (UnaryOp && UnaryOp->getOpcode() == UO_LNot) {
+OS << "!";
+prettyPrintFailedBooleanCondition(OS, UnaryOp->getSubExpr(), Policy);
+return;
+  }
+
   FailedCond->printPretty(OS, nullptr, Policy);
 }
 

Modified: cfe/trunk/test/SemaCXX/static-assert.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/static-assert.cpp?rev=348830&r1=348829&r2=348830&view=diff
==
--- cfe/trunk/test/SemaCXX/static-assert.cpp (original)
+++ cfe/trunk/test/SemaCXX/static-assert.cpp Mon Dec 10 23:04:49 2018
@@ -111,6 +111,10 @@ static_assert(std::is_same::value' "message"}}
 static_assert(std::is_const::value, "message");
 // expected-error@-1{{static_assert failed due to requirement 
'std::is_const::value' "message"}}
+static_assert(!std::is_const::value, "message");
+// expected-error@-1{{static_assert failed due to requirement 
'!std::is_const::value' "message"}}
+static_assert(!(std::is_const::value), "message");
+// expected-error@-1{{static_assert failed due to requirement 
'!(std::is_const::value)' "message"}}
 
 struct BI_tag {};
 struct RAI_tag : BI_tag {};


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


r348831 - Revert r348830 "[Sema]improve static_assert(!expr)"

2018-12-10 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Mon Dec 10 23:28:00 2018
New Revision: 348831

URL: http://llvm.org/viewvc/llvm-project?rev=348831&view=rev
Log:
Revert r348830 "[Sema]improve static_assert(!expr)"

Submitted the wrong change.

Modified:
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/SemaCXX/static-assert.cpp

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=348831&r1=348830&r2=348831&view=diff
==
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Dec 10 23:28:00 2018
@@ -3071,20 +3071,6 @@ static void prettyPrintFailedBooleanCond
 }
 return;
   }
-  if (const auto *Paren = dyn_cast(FailedCond)) {
-OS << "(";
-prettyPrintFailedBooleanCondition(OS, Paren->getSubExpr(), Policy);
-OS << ")";
-return;
-  }
-  // If this is !(BooleanExpression), try pretty-printing the inner expression.
-  const auto *UnaryOp = dyn_cast(FailedCond);
-  if (UnaryOp && UnaryOp->getOpcode() == UO_LNot) {
-OS << "!";
-prettyPrintFailedBooleanCondition(OS, UnaryOp->getSubExpr(), Policy);
-return;
-  }
-
   FailedCond->printPretty(OS, nullptr, Policy);
 }
 

Modified: cfe/trunk/test/SemaCXX/static-assert.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/static-assert.cpp?rev=348831&r1=348830&r2=348831&view=diff
==
--- cfe/trunk/test/SemaCXX/static-assert.cpp (original)
+++ cfe/trunk/test/SemaCXX/static-assert.cpp Mon Dec 10 23:28:00 2018
@@ -111,10 +111,6 @@ static_assert(std::is_same::value' "message"}}
 static_assert(std::is_const::value, "message");
 // expected-error@-1{{static_assert failed due to requirement 
'std::is_const::value' "message"}}
-static_assert(!std::is_const::value, "message");
-// expected-error@-1{{static_assert failed due to requirement 
'!std::is_const::value' "message"}}
-static_assert(!(std::is_const::value), "message");
-// expected-error@-1{{static_assert failed due to requirement 
'!(std::is_const::value)' "message"}}
 
 struct BI_tag {};
 struct RAI_tag : BI_tag {};


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


r348834 - Reland r348741 "[Sema] Further improvements to to static_assert diagnostics."

2018-12-11 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Tue Dec 11 00:39:11 2018
New Revision: 348834

URL: http://llvm.org/viewvc/llvm-project?rev=348834&view=rev
Log:
Reland r348741 "[Sema] Further improvements to to static_assert diagnostics."

Fix a dangling reference to temporary, never return nullptr.

Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/PCH/cxx-static_assert.cpp
cfe/trunk/test/Sema/static-assert.c
cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp
cfe/trunk/test/SemaCXX/static-assert.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=348834&r1=348833&r2=348834&view=diff
==
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Dec 11 00:39:11 2018
@@ -2861,11 +2861,7 @@ public:
 
   /// Find the failed Boolean condition within a given Boolean
   /// constant expression, and describe it with a string.
-  ///
-  /// \param AllowTopLevelCond Whether to allow the result to be the
-  /// complete top-level condition.
-  std::pair
-  findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond);
+  std::pair findFailedBooleanCondition(Expr *Cond);
 
   /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
   /// non-ArgDependent DiagnoseIfAttrs.

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=348834&r1=348833&r2=348834&view=diff
==
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Dec 11 00:39:11 2018
@@ -13913,9 +13913,9 @@ Decl *Sema::BuildStaticAssertDeclaration
   Expr *InnerCond = nullptr;
   std::string InnerCondDescription;
   std::tie(InnerCond, InnerCondDescription) =
-findFailedBooleanCondition(Converted.get(),
-   /*AllowTopLevelCond=*/false);
-  if (InnerCond) {
+findFailedBooleanCondition(Converted.get());
+  if (InnerCond && !isa(InnerCond)
+&& !isa(InnerCond)) {
 Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)
   << InnerCondDescription << !AssertMessage
   << Msg.str() << InnerCond->getSourceRange();

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=348834&r1=348833&r2=348834&view=diff
==
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Dec 11 00:39:11 2018
@@ -3052,30 +3052,42 @@ static Expr *lookThroughRangesV3Conditio
   return Cond;
 }
 
-// Print a diagnostic for the failing static_assert expression. Defaults to
-// pretty-printing the expression.
-static void prettyPrintFailedBooleanCondition(llvm::raw_string_ostream &OS,
-  const Expr *FailedCond,
-  const PrintingPolicy &Policy) {
-  const auto *DR = dyn_cast(FailedCond);
-  if (DR && DR->getQualifier()) {
-// If this is a qualified name, expand the template arguments in nested
-// qualifiers.
-DR->getQualifier()->print(OS, Policy, true);
-// Then print the decl itself.
-const ValueDecl *VD = DR->getDecl();
-OS << VD->getName();
-if (const auto *IV = dyn_cast(VD)) {
-  // This is a template variable, print the expanded template arguments.
-  printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
+namespace {
+
+// A PrinterHelper that prints more helpful diagnostics for some 
sub-expressions
+// within failing boolean expression, such as substituting template parameters
+// for actual types.
+class FailedBooleanConditionPrinterHelper : public PrinterHelper {
+public:
+  explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &P)
+  : Policy(P) {}
+
+  bool handledStmt(Stmt *E, raw_ostream &OS) override {
+const auto *DR = dyn_cast(E);
+if (DR && DR->getQualifier()) {
+  // If this is a qualified name, expand the template arguments in nested
+  // qualifiers.
+  DR->getQualifier()->print(OS, Policy, true);
+  // Then print the decl itself.
+  const ValueDecl *VD = DR->getDecl();
+  OS << VD->getName();
+  if (const auto *IV = dyn_cast(VD)) {
+// This is a template variable, print the expanded template arguments.
+printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
+  }
+  return true;
 }
-return;
+return false;
   }
-  FailedCond->printPretty(OS, nullptr, Policy);
-}
+
+private:
+  const PrintingPolicy Policy;
+};
+
+} // end anonymous namespace
 
 std::pair
-Sema::fin

[clang-tools-extra] r355076 - [clang-tidy] misc-string-integer-assignment: fix false positive

2019-02-28 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Thu Feb 28 02:33:32 2019
New Revision: 355076

URL: http://llvm.org/viewvc/llvm-project?rev=355076&view=rev
Log:
[clang-tidy] misc-string-integer-assignment: fix false positive

Summary:
using CodePoint = uint32_t;
CodePoint cp;
basic_string s;
s += cp;

See PR27723.

Reviewers: xazax.hun, alexfh

Subscribers: rnkovacs, cfe-commits

Tags: #clang

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

Modified:
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp

clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp

Modified: 
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp?rev=355076&r1=355075&r2=355076&view=diff
==
--- 
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp 
(original)
+++ 
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp 
Thu Feb 28 02:33:32 2019
@@ -26,7 +26,8 @@ void StringIntegerAssignmentCheck::regis
 hasOverloadedOperatorName("+=")),
   callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
   hasName("::std::basic_string"),
-  hasTemplateArgument(0, 
refersToType(qualType().bind("type"))),
+  hasTemplateArgument(0, refersToType(hasCanonicalType(
+ qualType().bind("type",
   hasArgument(
   1,
   ignoringImpCasts(
@@ -34,7 +35,11 @@ void StringIntegerAssignmentCheck::regis
// Ignore calls to tolower/toupper (see PR27723).
unless(callExpr(callee(functionDecl(
hasAnyName("tolower", "std::tolower", "toupper",
-  "std::toupper"))
+  "std::toupper"),
+   // Do not warn if assigning e.g. `CodePoint` to
+   // `basic_string`
+   unless(hasType(qualType(
+   hasCanonicalType(equalsBoundNode("type"))
   .bind("expr"))),
   unless(isInTemplateInstantiation())),
   this);

Modified: 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp?rev=355076&r1=355075&r2=355076&view=diff
==
--- 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp 
(original)
+++ 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp 
Thu Feb 28 02:33:32 2019
@@ -53,8 +53,8 @@ int main() {
 
   std::basic_string as;
   as = 6;
-// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a 
chara
-// CHECK-FIXES: {{^}}  as = 6;{{$}}
+  as = static_cast(6);
+  as = 'a';
 
   s += toupper(x);
   s += tolower(x);


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


[clang-tools-extra] r355089 - [clang-tidy] bugprone-string-integer-assignment: Reduce false positives.

2019-02-28 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Thu Feb 28 05:39:01 2019
New Revision: 355089

URL: http://llvm.org/viewvc/llvm-project?rev=355089&view=rev
Log:
[clang-tidy] bugprone-string-integer-assignment: Reduce false positives.

Summary: Detect a few expressions as likely character expressions, see PR27723.

Reviewers: xazax.hun, alexfh

Subscribers: rnkovacs, jdoerfert, cfe-commits

Tags: #clang

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

Modified:
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp

clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp

Modified: 
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp?rev=355089&r1=355088&r2=355089&view=diff
==
--- 
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp 
(original)
+++ 
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp 
Thu Feb 28 05:39:01 2019
@@ -45,11 +45,40 @@ void StringIntegerAssignmentCheck::regis
   this);
 }
 
+static bool isLikelyCharExpression(const Expr *Argument,
+   const ASTContext &Ctx) {
+  const auto *BinOp = dyn_cast(Argument);
+  if (!BinOp)
+return false;
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  //  & , mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
+   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects)))
+return true;
+  //  + ( % ), where  is a char literal.
+  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
+const auto *ROp = dyn_cast(R);
+return ROp && ROp->getOpcode() == BO_Rem && isa(L);
+  };
+  if (BinOp->getOpcode() == BO_Add) {
+if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS))
+  return true;
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
 const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context))
+return;
+
   auto Diag =
   diag(Loc, "an integer is interpreted as a character code when assigning "
 "it to a string; if this is intended, cast the integer to the "

Modified: 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp?rev=355089&r1=355088&r2=355089&view=diff
==
--- 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp 
(original)
+++ 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp 
Thu Feb 28 05:39:01 2019
@@ -59,4 +59,11 @@ int main() {
   s += toupper(x);
   s += tolower(x);
   s += std::tolower(x);
+
+  // Likely character expressions.
+  s += x & 0xff;
+  s += 0xff & x;
+
+  s += 'a' + (x % 26);
+  s += (x % 10) + 'b';
 }


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


[clang-tools-extra] r356871 - [clang-tidy] Fix more false positives for bugprone-string-integer-assignment

2019-03-25 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Mon Mar 25 01:18:00 2019
New Revision: 356871

URL: http://llvm.org/viewvc/llvm-project?rev=356871&view=rev
Log:
[clang-tidy] Fix more false positives for bugprone-string-integer-assignment

Summary:
And add various tests gleaned for our codebase.

See PR27723.

Reviewers: JonasToth, alexfh, xazax.hun

Subscribers: rnkovacs, jdoerfert, cfe-commits

Tags: #clang

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

Modified:
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp

clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp

Modified: 
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp?rev=356871&r1=356870&r2=356871&view=diff
==
--- 
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp 
(original)
+++ 
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp 
Mon Mar 25 01:18:00 2019
@@ -45,38 +45,100 @@ void StringIntegerAssignmentCheck::regis
   this);
 }
 
-static bool isLikelyCharExpression(const Expr *Argument,
-   const ASTContext &Ctx) {
-  const auto *BinOp = dyn_cast(Argument);
-  if (!BinOp)
+class CharExpressionDetector {
+public:
+  CharExpressionDetector(QualType CharType, const ASTContext &Ctx)
+  : CharType(CharType), Ctx(Ctx) {}
+
+  bool isLikelyCharExpression(const Expr *E) const {
+if (isCharTyped(E))
+  return true;
+
+if (const auto *BinOp = dyn_cast(E)) {
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  // Handle both directions, e.g. `'a' + (i % 26)` and `(i % 26) + 'a'`.
+  if (BinOp->isAdditiveOp() || BinOp->isBitwiseOp())
+return handleBinaryOp(BinOp->getOpcode(), LHS, RHS) ||
+   handleBinaryOp(BinOp->getOpcode(), RHS, LHS);
+  // Except in the case of '%'.
+  if (BinOp->getOpcode() == BO_Rem)
+return handleBinaryOp(BinOp->getOpcode(), LHS, RHS);
+  return false;
+}
+
+// Ternary where at least one branch is a likely char expression, e.g.
+//i < 265 ? i : ' '
+if (const auto *CondOp = dyn_cast(E))
+  return isLikelyCharExpression(
+ CondOp->getFalseExpr()->IgnoreParenImpCasts()) ||
+ isLikelyCharExpression(
+ CondOp->getTrueExpr()->IgnoreParenImpCasts());
 return false;
-  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
-  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
-  //  & , mask is a compile time constant.
-  Expr::EvalResult RHSVal;
-  if (BinOp->getOpcode() == BO_And &&
-  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
-   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects)))
-return true;
-  //  + ( % ), where  is a char literal.
-  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
-const auto *ROp = dyn_cast(R);
-return ROp && ROp->getOpcode() == BO_Rem && isa(L);
-  };
-  if (BinOp->getOpcode() == BO_Add) {
-if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS))
+  }
+
+private:
+  bool handleBinaryOp(clang::BinaryOperatorKind Opcode, const Expr *const LHS,
+  const Expr *const RHS) const {
+//(c++ integer promotion rules make this an
+// int), e.g.
+//'a' + c
+if (isCharTyped(LHS) && isCharTyped(RHS))
   return true;
+
+//  &  or  % , e.g.
+//i & 0xff
+if ((Opcode == BO_And || Opcode == BO_Rem) && isCharValuedConstant(RHS))
+  return true;
+
+//  | , e.g.
+//c | 0x80
+if (Opcode == BO_Or && isCharTyped(LHS) && isCharValuedConstant(RHS))
+  return true;
+
+//  + , e.g.
+//'a' + (i % 26)
+if (Opcode == BO_Add)
+  return isCharConstant(LHS) && isLikelyCharExpression(RHS);
+
+return false;
   }
-  return false;
-}
+
+  // Returns true if `E` is an character constant.
+  bool isCharConstant(const Expr *E) const {
+return isCharTyped(E) && isCharValuedConstant(E);
+  };
+
+  // Returns true if `E` is an integer constant which fits in `CharType`.
+  bool isCharValuedConstant(const Expr *E) const {
+if (E->isInstantiationDependent())
+  return false;
+Expr::EvalResult EvalResult;
+if (!E->EvaluateAsInt(EvalResult, Ctx, Expr::SE_AllowSideEffects))
+  return false;
+return EvalResult.Val.getInt().getActiveBits() <= 
Ctx.getTypeSize(CharType);
+  };
+
+  // Returns true if `E` has the right character type.
+  bool isCharTyped(const Expr *E) const {
+return E->getType().getCanonicalType().getTypePtr() ==
+   CharType.getTypePtr();
+  };
+
+  const QualType CharType;
+  const ASTContext &Ctx;
+};
 
 void StringIntegerAssignmentCheck::check(
  

r354023 - [Builtins] Treat `bcmp` as a builtin.

2019-02-14 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Thu Feb 14 04:00:34 2019
New Revision: 354023

URL: http://llvm.org/viewvc/llvm-project?rev=354023&view=rev
Log:
[Builtins] Treat `bcmp` as a builtin.

Summary:
This makes it consistent with `memcmp` and `__builtin_bcmp`.

Also see the discussion in https://reviews.llvm.org/D56593.

Reviewers: jyknight

Subscribers: kristina, cfe-commits

Tags: #clang

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

Modified:
cfe/trunk/include/clang/Basic/Builtins.def
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/lib/Sema/SemaChecking.cpp
cfe/trunk/test/Analysis/bstring.c
cfe/trunk/test/Analysis/security-syntax-checks.m
cfe/trunk/test/SemaCXX/constexpr-string.cpp
cfe/trunk/test/SemaCXX/warn-bad-memaccess.cpp

Modified: cfe/trunk/include/clang/Basic/Builtins.def
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Builtins.def?rev=354023&r1=354022&r2=354023&view=diff
==
--- cfe/trunk/include/clang/Basic/Builtins.def (original)
+++ cfe/trunk/include/clang/Basic/Builtins.def Thu Feb 14 04:00:34 2019
@@ -448,7 +448,7 @@ BUILTIN(__builtin_va_end, "vA", "n")
 BUILTIN(__builtin_va_copy, "vAA", "n")
 BUILTIN(__builtin_stdarg_start, "vA.", "n")
 BUILTIN(__builtin_assume_aligned, "v*vC*z.", "nc")
-BUILTIN(__builtin_bcmp, "iv*v*z", "Fn")
+BUILTIN(__builtin_bcmp, "ivC*vC*z", "Fn")
 BUILTIN(__builtin_bcopy, "vv*v*z", "n")
 BUILTIN(__builtin_bzero, "vv*z", "nF")
 BUILTIN(__builtin_fprintf, "iP*cC*.", "Fp:1:")
@@ -953,6 +953,7 @@ LIBBUILTIN(strndup, "c*cC*z", "f",
 LIBBUILTIN(index, "c*cC*i",   "f", "strings.h", ALL_GNU_LANGUAGES)
 LIBBUILTIN(rindex, "c*cC*i",  "f", "strings.h", ALL_GNU_LANGUAGES)
 LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(bcmp, "ivC*vC*z",  "f", "strings.h", ALL_GNU_LANGUAGES)
 // In some systems str[n]casejmp is a macro that expands to _str[n]icmp.
 // We undefine then here to avoid wrong name.
 #undef strcasecmp

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=354023&r1=354022&r2=354023&view=diff
==
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Thu Feb 14 04:00:34 2019
@@ -3672,6 +3672,10 @@ unsigned FunctionDecl::getMemoryFunction
   case Builtin::BImemcmp:
 return Builtin::BImemcmp;
 
+  case Builtin::BI__builtin_bcmp:
+  case Builtin::BIbcmp:
+return Builtin::BIbcmp;
+
   case Builtin::BI__builtin_strncpy:
   case Builtin::BI__builtin___strncpy_chk:
   case Builtin::BIstrncpy:
@@ -3712,6 +3716,8 @@ unsigned FunctionDecl::getMemoryFunction
 return Builtin::BImemmove;
   else if (FnInfo->isStr("memcmp"))
 return Builtin::BImemcmp;
+  else if (FnInfo->isStr("bcmp"))
+return Builtin::BIbcmp;
   else if (FnInfo->isStr("strncpy"))
 return Builtin::BIstrncpy;
   else if (FnInfo->isStr("strncmp"))

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=354023&r1=354022&r2=354023&view=diff
==
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Feb 14 04:00:34 2019
@@ -8426,6 +8426,7 @@ bool IntExprEvaluator::VisitBuiltinCallE
   case Builtin::BIstrncmp:
   case Builtin::BIwcsncmp:
   case Builtin::BImemcmp:
+  case Builtin::BIbcmp:
   case Builtin::BIwmemcmp:
 // A call to strlen is not a constant expression.
 if (Info.getLangOpts().CPlusPlus11)
@@ -8440,6 +8441,7 @@ bool IntExprEvaluator::VisitBuiltinCallE
   case Builtin::BI__builtin_strncmp:
   case Builtin::BI__builtin_wcsncmp:
   case Builtin::BI__builtin_memcmp:
+  case Builtin::BI__builtin_bcmp:
   case Builtin::BI__builtin_wmemcmp: {
 LValue String1, String2;
 if (!EvaluatePointer(E->getArg(0), String1, Info) ||
@@ -8470,7 +8472,9 @@ bool IntExprEvaluator::VisitBuiltinCallE
 QualType CharTy2 = String2.Designator.getType(Info.Ctx);
 
 bool IsRawByte = BuiltinOp == Builtin::BImemcmp ||
- BuiltinOp == Builtin::BI__builtin_memcmp;
+ BuiltinOp == Builtin::BIbcmp ||
+ BuiltinOp == Builtin::BI__builtin_memcmp ||
+ BuiltinOp == Builtin::BI__builtin_bcmp;
 
 assert(IsRawByte ||
(Info.Ctx.hasSameUnqualifiedType(
@@ -8538,10 +8542,12 @@ bool IntExprEvaluator::VisitBuiltinCallE
   return Success(0, E);
 }
 
-bool StopAtNull = (BuiltinOp != Builtin::BImemcmp &&
-   BuiltinOp != Builtin::BIwmemcmp &&
-   BuiltinOp != Builtin::BI__builtin_memcmp &&
-   BuiltinOp != Builtin::BI__builtin_wmemcmp);
+bool StopAtNull =
+(BuiltinOp !=

[clang-tools-extra] r354780 - [clang-tidy] misc-string-integer-assignment: ignore toupper/tolower

2019-02-25 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Mon Feb 25 05:09:02 2019
New Revision: 354780

URL: http://llvm.org/viewvc/llvm-project?rev=354780&view=rev
Log:
[clang-tidy] misc-string-integer-assignment: ignore toupper/tolower

Summary: Tis represents ~20% of false positives. See PR27723.

Reviewers: xazax.hun, alexfh

Subscribers: rnkovacs, cfe-commits

Tags: #clang

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

Modified:
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp

clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp

Modified: 
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp?rev=354780&r1=354779&r2=354780&view=diff
==
--- 
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp 
(original)
+++ 
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp 
Mon Feb 25 05:09:02 2019
@@ -27,10 +27,15 @@ void StringIntegerAssignmentCheck::regis
   callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
   hasName("::std::basic_string"),
   hasTemplateArgument(0, 
refersToType(qualType().bind("type"))),
-  hasArgument(1,
-  ignoringImpCasts(expr(hasType(isInteger()),
-unless(hasType(isAnyCharacter(
-   .bind("expr"))),
+  hasArgument(
+  1,
+  ignoringImpCasts(
+  expr(hasType(isInteger()), unless(hasType(isAnyCharacter())),
+   // Ignore calls to tolower/toupper (see PR27723).
+   unless(callExpr(callee(functionDecl(
+   hasAnyName("tolower", "std::tolower", "toupper",
+  "std::toupper"))
+  .bind("expr"))),
   unless(isInTemplateInstantiation())),
   this);
 }

Modified: 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp?rev=354780&r1=354779&r2=354780&view=diff
==
--- 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp 
(original)
+++ 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp 
Mon Feb 25 05:09:02 2019
@@ -11,8 +11,14 @@ struct basic_string {
 
 typedef basic_string string;
 typedef basic_string wstring;
+
+int tolower(int i);
+int toupper(int i);
 }
 
+int tolower(int i);
+int toupper(int i);
+
 typedef int MyArcaneChar;
 
 int main() {
@@ -50,4 +56,7 @@ int main() {
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a 
chara
 // CHECK-FIXES: {{^}}  as = 6;{{$}}
 
+  s += toupper(x);
+  s += tolower(x);
+  s += std::tolower(x);
 }


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


[clang-tools-extra] r363053 - [clang-tidy] Fix typo in bugprone-string-constructor.

2019-06-11 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Tue Jun 11 05:12:06 2019
New Revision: 363053

URL: http://llvm.org/viewvc/llvm-project?rev=363053&view=rev
Log:
[clang-tidy] Fix typo in bugprone-string-constructor.

s/bigger then/bigger than/

Modified:
clang-tools-extra/trunk/clang-tidy/bugprone/StringConstructorCheck.cpp
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-constructor.cpp

Modified: clang-tools-extra/trunk/clang-tidy/bugprone/StringConstructorCheck.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/bugprone/StringConstructorCheck.cpp?rev=363053&r1=363052&r2=363053&view=diff
==
--- clang-tools-extra/trunk/clang-tidy/bugprone/StringConstructorCheck.cpp 
(original)
+++ clang-tools-extra/trunk/clang-tidy/bugprone/StringConstructorCheck.cpp Tue 
Jun 11 05:12:06 2019
@@ -134,7 +134,7 @@ void StringConstructorCheck::check(const
 const auto *Str = Result.Nodes.getNodeAs("str");
 const auto *Lit = Result.Nodes.getNodeAs("int");
 if (Lit->getValue().ugt(Str->getLength())) {
-  diag(Loc, "length is bigger then string literal size");
+  diag(Loc, "length is bigger than string literal size");
 }
   } else if (const auto *Ptr = Result.Nodes.getNodeAs("from-ptr")) {
 Expr::EvalResult ConstPtr;

Modified: 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-constructor.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/bugprone-string-constructor.cpp?rev=363053&r1=363052&r2=363053&view=diff
==
--- clang-tools-extra/trunk/test/clang-tidy/bugprone-string-constructor.cpp 
(original)
+++ clang-tools-extra/trunk/test/clang-tidy/bugprone-string-constructor.cpp Tue 
Jun 11 05:12:06 2019
@@ -39,11 +39,11 @@ void Test() {
   std::string q1(kText, -4);
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: negative value used as length 
parameter
   std::string q2("test", 200);
-  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string 
literal size
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger than string 
literal size
   std::string q3(kText, 200);
-  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string 
literal size
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger than string 
literal size
   std::string q4(kText2, 200);
-  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string 
literal size
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger than string 
literal size
   std::string q5(kText3,  0x100);
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
   std::string q6(nullptr);


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


r349729 - [Sema] Better static assert diagnostics for expressions involving temporaries/casts/....

2018-12-20 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Thu Dec 20 01:05:15 2018
New Revision: 349729

URL: http://llvm.org/viewvc/llvm-project?rev=349729&view=rev
Log:
[Sema] Better static assert diagnostics for expressions involving 
temporaries/casts/

Summary:
Handles expressions such as:
 - `std::is_const()`
 - `std::is_const()()`;
 - `std::is_same(decltype(U()), V>::value`;

Reviewers: aaron.ballman, Quuxplusone

Subscribers: cfe-commits, llvm-commits

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

Modified:
cfe/trunk/include/clang/AST/PrettyPrinter.h
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/lib/AST/TypePrinter.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp
cfe/trunk/test/SemaCXX/static-assert.cpp

Modified: cfe/trunk/include/clang/AST/PrettyPrinter.h
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/PrettyPrinter.h?rev=349729&r1=349728&r2=349729&view=diff
==
--- cfe/trunk/include/clang/AST/PrettyPrinter.h (original)
+++ cfe/trunk/include/clang/AST/PrettyPrinter.h Thu Dec 20 01:05:15 2018
@@ -51,7 +51,7 @@ struct PrintingPolicy {
 MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true),
 MSVCFormatting(false), ConstantsAsWritten(false),
 SuppressImplicitBase(false), FullyQualifiedName(false),
-RemapFilePaths(false) {}
+RemapFilePaths(false), PrintCanonicalTypes(false) {}
 
   /// Adjust this printing policy for cases where it's known that we're
   /// printing C++ code (for instance, if AST dumping reaches a C++-only
@@ -228,6 +228,9 @@ struct PrintingPolicy {
   /// Whether to apply -fdebug-prefix-map to any file paths.
   unsigned RemapFilePaths : 1;
 
+  /// Whether to print types as written or canonically.
+  unsigned PrintCanonicalTypes : 1;
+
   /// When RemapFilePaths is true, this function performs the action.
   std::function remapPath;
 };

Modified: cfe/trunk/include/clang/AST/Type.h
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=349729&r1=349728&r2=349729&view=diff
==
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Thu Dec 20 01:05:15 2018
@@ -980,9 +980,7 @@ public:
 
   void print(raw_ostream &OS, const PrintingPolicy &Policy,
  const Twine &PlaceHolder = Twine(),
- unsigned Indentation = 0) const {
-print(split(), OS, Policy, PlaceHolder, Indentation);
-  }
+ unsigned Indentation = 0) const;
 
   static void print(SplitQualType split, raw_ostream &OS,
 const PrintingPolicy &policy, const Twine &PlaceHolder,
@@ -996,9 +994,7 @@ public:
 unsigned Indentation = 0);
 
   void getAsStringInternal(std::string &Str,
-   const PrintingPolicy &Policy) const {
-return getAsStringInternal(split(), Str, Policy);
-  }
+   const PrintingPolicy &Policy) const;
 
   static void getAsStringInternal(SplitQualType split, std::string &out,
   const PrintingPolicy &policy) {

Modified: cfe/trunk/lib/AST/TypePrinter.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=349729&r1=349728&r2=349729&view=diff
==
--- cfe/trunk/lib/AST/TypePrinter.cpp (original)
+++ cfe/trunk/lib/AST/TypePrinter.cpp Thu Dec 20 01:05:15 2018
@@ -117,9 +117,7 @@ namespace {
 void spaceBeforePlaceHolder(raw_ostream &OS);
 void printTypeSpec(NamedDecl *D, raw_ostream &OS);
 
-void printBefore(const Type *ty, Qualifiers qs, raw_ostream &OS);
 void printBefore(QualType T, raw_ostream &OS);
-void printAfter(const Type *ty, Qualifiers qs, raw_ostream &OS);
 void printAfter(QualType T, raw_ostream &OS);
 void AppendScope(DeclContext *DC, raw_ostream &OS);
 void printTag(TagDecl *T, raw_ostream &OS);
@@ -129,6 +127,10 @@ namespace {
 void print##CLASS##Before(const CLASS##Type *T, raw_ostream &OS); \
 void print##CLASS##After(const CLASS##Type *T, raw_ostream &OS);
 #include "clang/AST/TypeNodes.def"
+
+  private:
+void printBefore(const Type *ty, Qualifiers qs, raw_ostream &OS);
+void printAfter(const Type *ty, Qualifiers qs, raw_ostream &OS);
   };
 
 } // namespace
@@ -160,8 +162,15 @@ void TypePrinter::spaceBeforePlaceHolder
 OS << ' ';
 }
 
+static SplitQualType splitAccordingToPolicy(QualType QT,
+const PrintingPolicy &Policy) {
+  if (Policy.PrintCanonicalTypes)
+QT = QT.getCanonicalType();
+  return QT.split();
+}
+
 void TypePrinter::print(QualType t, raw_ostream &OS, StringRef PlaceHolder) {
-  SplitQualType split = t.split();
+  SplitQualType split = splitAccordingToPolicy(t, Policy);
   print(split.Ty, split.Quals, OS, PlaceHolder);

r349755 - [Sema][NFC] Add test for static_assert diagnistics with constexpr template functions.

2018-12-20 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Thu Dec 20 05:30:40 2018
New Revision: 349755

URL: http://llvm.org/viewvc/llvm-project?rev=349755&view=rev
Log:
[Sema][NFC] Add test for static_assert diagnistics with constexpr template 
functions.

Modified:
cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp

Modified: cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp?rev=349755&r1=349754&r2=349755&view=diff
==
--- cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp (original)
+++ cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp Thu Dec 20 05:30:40 2018
@@ -15,6 +15,11 @@ struct S2 {
 };
 
 template 
+inline constexpr bool constexpr_return_false() {
+  return false;
+}
+
+template 
 void foo() {
   static_assert(S1::value);
   // expected-error@-1{{static_assert failed due to requirement 'S1::value'}}
@@ -92,6 +97,8 @@ void foo6() {
   // expected-error@-1{{static_assert failed due to requirement '(X 
const[0]){} == nullptr'}}
   static_assert(sizeof(X().X::~X())>) 
== 0);
   // expected-error@-1{{static_assert failed due to requirement 
'sizeof(X) == 0'}}
+  static_assert(constexpr_return_false());
+  // expected-error@-1{{static_assert failed due to requirement 
'constexpr_return_false()'}}
 }
 template void foo6();
 // expected-note@-1{{in instantiation of function template specialization 
'foo6' requested here}}


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


r371522 - [clang][codegen][NFC] Make test patterns more permissive.

2019-09-10 Thread Clement Courbet via cfe-commits
Author: courbet
Date: Tue Sep 10 07:20:08 2019
New Revision: 371522

URL: http://llvm.org/viewvc/llvm-project?rev=371522&view=rev
Log:
[clang][codegen][NFC] Make test patterns more permissive.

See the discussion in:
http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20190909/692736.html

Modified:
cfe/trunk/test/CodeGenCXX/auto-var-init.cpp

Modified: cfe/trunk/test/CodeGenCXX/auto-var-init.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/auto-var-init.cpp?rev=371522&r1=371521&r2=371522&view=diff
==
--- cfe/trunk/test/CodeGenCXX/auto-var-init.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/auto-var-init.cpp Tue Sep 10 07:20:08 2019
@@ -1042,8 +1042,7 @@ TEST_UNINIT(intptr4, int*[4]);
 // CHECK:%uninit = alloca [4 x i32*], align
 // CHECK-NEXT:   call void @{{.*}}used{{.*}}%uninit)
 // PATTERN-O1-LABEL: @test_intptr4_uninit()
-// PATTERN-O1:   %1 = bitcast [4 x i32*]* %uninit to i8*
-// PATTERN-O1-NEXT:  call void @llvm.memset.p0i8.i64(i8* nonnull align 16  
dereferenceable(32) %1, i8 -86, i64 32, i1 false)
+// PATTERN-O1:  call void @llvm.memset.p0i8.i64(i8* nonnull align 16  
dereferenceable(32) %{{[0-9*]}}, i8 -86, i64 32, i1 false)
 // ZERO-LABEL:   @test_intptr4_uninit()
 // ZERO: call void @llvm.memset{{.*}}, i8 0,
 


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


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-06 Thread Clement Courbet via cfe-commits


@@ -261,21 +262,27 @@ void 
UnnecessaryCopyInitialization::registerMatchers(MatchFinder *Finder) {
  this);
 }
 
+UnnecessaryCopyInitialization::CheckContext::CheckContext(

legrosbuffle wrote:

Given that we are deriving `IssueFix`, `IsVarUnused`, `IsVarOnlyUsedAsConst` 
from `Var`, `BlockStmt`, ... it sounds natural to have a ctor there. Otherwise 
we risk creating a `CheckContext` in an invalid state.

https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-06 Thread Clement Courbet via cfe-commits


@@ -290,69 +296,72 @@ void UnnecessaryCopyInitialization::check(
   // instantiations where the types differ and rely on implicit conversion 
would
   // no longer compile if we switched to a reference.
   if (differentReplacedTemplateParams(
-  NewVar->getType(), constructorArgumentType(OldVar, Result.Nodes),
+  Context.Var.getType(), constructorArgumentType(OldVar, Result.Nodes),
   *Result.Context))
 return;
 
   if (OldVar == nullptr) {
-handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix, ObjectArg,
-   *Result.Context);
+// `auto NewVar = functionCall();`
+handleCopyFromMethodReturn(Context, ObjectArg);
   } else {
-handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix,
-   *Result.Context);
+// `auto NewVar = OldVar;`
+handleCopyFromLocalVar(Context, *OldVar);
   }
 }
 
-void UnnecessaryCopyInitialization::makeDiagnostic(
-DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt,
-const DeclStmt &Stmt, ASTContext &Context, bool IssueFix) {
-  const bool IsVarUnused = isVariableUnused(Var, BlockStmt, Context);
-  Diagnostic << &Var << IsVarUnused;
-  if (!IssueFix)
-return;
-  if (IsVarUnused)
-recordRemoval(Stmt, Context, Diagnostic);
-  else
-recordFixes(Var, Context, Diagnostic);
-}
-
 void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
-const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
-bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
-  bool IsConstQualified = Var.getType().isConstQualified();
-  if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context))
+const CheckContext &Ctx, const VarDecl *ObjectArg) {
+  bool IsConstQualified = Ctx.Var.getType().isConstQualified();
+  if (!IsConstQualified && !Ctx.IsVarOnlyUsedAsConst)
 return;
   if (ObjectArg != nullptr &&
-  !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
+  !isInitializingVariableImmutable(*ObjectArg, Ctx.BlockStmt, Ctx.ASTCtx,
ExcludedContainerTypes))
 return;
-
-  auto Diagnostic =
-  diag(Var.getLocation(),
-   "the %select{|const qualified }0variable %1 is copy-constructed "
-   "from a const reference%select{"
-   "%select{ but is only used as const reference|}0"
-   "| but is never used}2; consider "
-   "%select{making it a const reference|removing the statement}2")
-  << IsConstQualified;
-  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context,
- IssueFix);
+  diagnoseCopyFromMethodReturn(Ctx, ObjectArg);
 }
 
 void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
-const VarDecl &Var, const VarDecl &OldVar, const Stmt &BlockStmt,
-const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
-  if (!isOnlyUsedAsConst(Var, BlockStmt, Context) ||
-  !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
+const CheckContext &Ctx, const VarDecl &OldVar) {
+  if (!Ctx.IsVarOnlyUsedAsConst ||
+  !isInitializingVariableImmutable(OldVar, Ctx.BlockStmt, Ctx.ASTCtx,
ExcludedContainerTypes))
 return;
-  auto Diagnostic = diag(Var.getLocation(),
- "local copy %1 of the variable %0 is never modified"
- "%select{| and never used}2; consider "
- "%select{avoiding the copy|removing the statement}2")
-<< &OldVar;
-  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context,
- IssueFix);
+  diagnoseCopyFromLocalVar(Ctx, OldVar);
+}
+
+void UnnecessaryCopyInitialization::diagnoseCopyFromMethodReturn(
+const CheckContext &Ctx, const VarDecl *ObjectArg) {

legrosbuffle wrote:

Thanks for the catch, this is a leftover from the previous iteration. Removed. 

https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-06 Thread Clement Courbet via cfe-commits


@@ -32,14 +32,34 @@ class UnnecessaryCopyInitialization : public ClangTidyCheck 
{
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
 
+protected:
+  // A helper to manipulate the state common to
+  // `CopyFromMethodReturn` and `CopyFromLocalVar`.
+  struct CheckContext {
+CheckContext(const ast_matchers::MatchFinder::MatchResult &Result);
+const VarDecl &Var;
+const Stmt &BlockStmt;
+const DeclStmt &VarDeclStmt;
+clang::ASTContext &ASTCtx;
+const bool IssueFix;
+const bool IsVarUnused;
+const bool IsVarOnlyUsedAsConst;
+  };
+
+  // Create diagnostics. These are virtual so that derived classes can change
+  // behaviour.
+  virtual void diagnoseCopyFromMethodReturn(const CheckContext &Ctx,

legrosbuffle wrote:

`ObjectArg` is a pointer because it can be null (unlike other variables, which 
are always non-null. Anyway, this is no longer provided as pre the previous 
comment.

https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-06 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle edited 
https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-06 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/73921

>From 851460af6526f175bc34b105a0f5f130a2f1c6b1 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Thu, 30 Nov 2023 11:08:51 +0100
Subject: [PATCH 1/3] [clang-tidy] performance-unnecessary-copy-init

Refactor diagnostic emission and add a hook so that derived checks
can observe for which variables a warning has been emitted.
---
 .../UnnecessaryCopyInitialization.cpp | 73 +--
 .../UnnecessaryCopyInitialization.h   |  7 ++
 2 files changed, 41 insertions(+), 39 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 990e20400fbfc..a9ef3faf8c343 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/Basic/Diagnostic.h"
 #include 
+#include 
 
 namespace clang::tidy::performance {
 namespace {
@@ -302,6 +303,19 @@ void UnnecessaryCopyInitialization::check(
   }
 }
 
+void UnnecessaryCopyInitialization::makeDiagnostic(
+DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt,
+const DeclStmt &Stmt, ASTContext &Context, bool IssueFix) {
+  const bool IsVarUnused = isVariableUnused(Var, BlockStmt, Context);
+  Diagnostic << &Var << IsVarUnused;
+  if (!IssueFix)
+return;
+  if (IsVarUnused)
+recordRemoval(Stmt, Context, Diagnostic);
+  else
+recordFixes(Var, Context, Diagnostic);
+}
+
 void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
 bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
@@ -312,52 +326,33 @@ void 
UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
   !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-  if (isVariableUnused(Var, BlockStmt, Context)) {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference but is never used; consider "
- "removing the statement")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference%select{ but is only used as const "
- "reference|}0; consider making it a const reference")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordFixes(Var, Context, Diagnostic);
-  }
+
+  auto Diagnostic =
+  diag(Var.getLocation(),
+   "the %select{|const qualified }0variable %1 is copy-constructed "
+   "from a const reference%select{"
+   "%select{ but is only used as const reference|}0"
+   "| but is never used}2; consider "
+   "%select{making it a const reference|removing the statement}2")
+  << IsConstQualified;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context,
+ IssueFix);
 }
 
 void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
-const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
+const VarDecl &Var, const VarDecl &OldVar, const Stmt &BlockStmt,
 const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
-  if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
+  if (!isOnlyUsedAsConst(Var, BlockStmt, Context) ||
   !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-
-  if (isVariableUnused(NewVar, BlockStmt, Context)) {
-auto Diagnostic = diag(NewVar.getLocation(),
-   "local copy %0 of the variable %1 is never modified 
"
-   "and never used; "
-   "consider removing the statement")
-  << &NewVar << &OldVar;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(NewVar.getLocation(),
- "local copy %0 of the variable %1 is never modified; "
- "consider avoiding the copy")
-<< &NewVar << &OldVar;
-if (IssueFix)
-  recordFixes(NewVar, Context, Diagnostic);
-  }
+  auto Diagnostic = diag(Var.getLocation(),
+ "local copy %1 of the variable %0 is never modified"
+ "%select{| and never used}2; consider "
+ "%select{avoiding the copy|removing the statement}2")
+<< &OldVar;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stm

[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-06 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/73921

>From 851460af6526f175bc34b105a0f5f130a2f1c6b1 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Thu, 30 Nov 2023 11:08:51 +0100
Subject: [PATCH 1/4] [clang-tidy] performance-unnecessary-copy-init

Refactor diagnostic emission and add a hook so that derived checks
can observe for which variables a warning has been emitted.
---
 .../UnnecessaryCopyInitialization.cpp | 73 +--
 .../UnnecessaryCopyInitialization.h   |  7 ++
 2 files changed, 41 insertions(+), 39 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 990e20400fbfc..a9ef3faf8c343 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/Basic/Diagnostic.h"
 #include 
+#include 
 
 namespace clang::tidy::performance {
 namespace {
@@ -302,6 +303,19 @@ void UnnecessaryCopyInitialization::check(
   }
 }
 
+void UnnecessaryCopyInitialization::makeDiagnostic(
+DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt,
+const DeclStmt &Stmt, ASTContext &Context, bool IssueFix) {
+  const bool IsVarUnused = isVariableUnused(Var, BlockStmt, Context);
+  Diagnostic << &Var << IsVarUnused;
+  if (!IssueFix)
+return;
+  if (IsVarUnused)
+recordRemoval(Stmt, Context, Diagnostic);
+  else
+recordFixes(Var, Context, Diagnostic);
+}
+
 void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
 bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
@@ -312,52 +326,33 @@ void 
UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
   !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-  if (isVariableUnused(Var, BlockStmt, Context)) {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference but is never used; consider "
- "removing the statement")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference%select{ but is only used as const "
- "reference|}0; consider making it a const reference")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordFixes(Var, Context, Diagnostic);
-  }
+
+  auto Diagnostic =
+  diag(Var.getLocation(),
+   "the %select{|const qualified }0variable %1 is copy-constructed "
+   "from a const reference%select{"
+   "%select{ but is only used as const reference|}0"
+   "| but is never used}2; consider "
+   "%select{making it a const reference|removing the statement}2")
+  << IsConstQualified;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context,
+ IssueFix);
 }
 
 void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
-const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
+const VarDecl &Var, const VarDecl &OldVar, const Stmt &BlockStmt,
 const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
-  if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
+  if (!isOnlyUsedAsConst(Var, BlockStmt, Context) ||
   !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-
-  if (isVariableUnused(NewVar, BlockStmt, Context)) {
-auto Diagnostic = diag(NewVar.getLocation(),
-   "local copy %0 of the variable %1 is never modified 
"
-   "and never used; "
-   "consider removing the statement")
-  << &NewVar << &OldVar;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(NewVar.getLocation(),
- "local copy %0 of the variable %1 is never modified; "
- "consider avoiding the copy")
-<< &NewVar << &OldVar;
-if (IssueFix)
-  recordFixes(NewVar, Context, Diagnostic);
-  }
+  auto Diagnostic = diag(Var.getLocation(),
+ "local copy %1 of the variable %0 is never modified"
+ "%select{| and never used}2; consider "
+ "%select{avoiding the copy|removing the statement}2")
+<< &OldVar;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stm

[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-06 Thread Clement Courbet via cfe-commits


@@ -261,21 +262,27 @@ void 
UnnecessaryCopyInitialization::registerMatchers(MatchFinder *Finder) {
  this);
 }
 
+UnnecessaryCopyInitialization::CheckContext::CheckContext(

legrosbuffle wrote:

I think it's a simple matter of preference, I think we can see the constructor 
as a factory function for the context.

To me the following are all kind of equivalent:
  - `CheckContext Context(Result);`
  - `CheckContext Context = MakeContext(Result);`
  - `CheckContext Context{NewVar, ...}`

With the caveat that the latter allows putting the context in an invalid state 
(e.g. with `IsVarUnused` in an inconsistent value w.r.t. `Var`). Anyway I don't 
feel strongly, so I've switched to a raw struct without ctor as suggested. 


https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-06 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/73921

>From 851460af6526f175bc34b105a0f5f130a2f1c6b1 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Thu, 30 Nov 2023 11:08:51 +0100
Subject: [PATCH 1/5] [clang-tidy] performance-unnecessary-copy-init

Refactor diagnostic emission and add a hook so that derived checks
can observe for which variables a warning has been emitted.
---
 .../UnnecessaryCopyInitialization.cpp | 73 +--
 .../UnnecessaryCopyInitialization.h   |  7 ++
 2 files changed, 41 insertions(+), 39 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 990e20400fbfc..a9ef3faf8c343 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/Basic/Diagnostic.h"
 #include 
+#include 
 
 namespace clang::tidy::performance {
 namespace {
@@ -302,6 +303,19 @@ void UnnecessaryCopyInitialization::check(
   }
 }
 
+void UnnecessaryCopyInitialization::makeDiagnostic(
+DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt,
+const DeclStmt &Stmt, ASTContext &Context, bool IssueFix) {
+  const bool IsVarUnused = isVariableUnused(Var, BlockStmt, Context);
+  Diagnostic << &Var << IsVarUnused;
+  if (!IssueFix)
+return;
+  if (IsVarUnused)
+recordRemoval(Stmt, Context, Diagnostic);
+  else
+recordFixes(Var, Context, Diagnostic);
+}
+
 void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
 bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
@@ -312,52 +326,33 @@ void 
UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
   !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-  if (isVariableUnused(Var, BlockStmt, Context)) {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference but is never used; consider "
- "removing the statement")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference%select{ but is only used as const "
- "reference|}0; consider making it a const reference")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordFixes(Var, Context, Diagnostic);
-  }
+
+  auto Diagnostic =
+  diag(Var.getLocation(),
+   "the %select{|const qualified }0variable %1 is copy-constructed "
+   "from a const reference%select{"
+   "%select{ but is only used as const reference|}0"
+   "| but is never used}2; consider "
+   "%select{making it a const reference|removing the statement}2")
+  << IsConstQualified;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context,
+ IssueFix);
 }
 
 void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
-const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
+const VarDecl &Var, const VarDecl &OldVar, const Stmt &BlockStmt,
 const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
-  if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
+  if (!isOnlyUsedAsConst(Var, BlockStmt, Context) ||
   !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-
-  if (isVariableUnused(NewVar, BlockStmt, Context)) {
-auto Diagnostic = diag(NewVar.getLocation(),
-   "local copy %0 of the variable %1 is never modified 
"
-   "and never used; "
-   "consider removing the statement")
-  << &NewVar << &OldVar;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(NewVar.getLocation(),
- "local copy %0 of the variable %1 is never modified; "
- "consider avoiding the copy")
-<< &NewVar << &OldVar;
-if (IssueFix)
-  recordFixes(NewVar, Context, Diagnostic);
-  }
+  auto Diagnostic = diag(Var.getLocation(),
+ "local copy %1 of the variable %0 is never modified"
+ "%select{| and never used}2; consider "
+ "%select{avoiding the copy|removing the statement}2")
+<< &OldVar;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stm

[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-06 Thread Clement Courbet via cfe-commits


@@ -289,74 +297,72 @@ void UnnecessaryCopyInitialization::check(
   // instantiations where the types differ and rely on implicit conversion 
would
   // no longer compile if we switched to a reference.
   if (differentReplacedTemplateParams(
-  NewVar->getType(), constructorArgumentType(OldVar, Result.Nodes),
+  Context.Var.getType(), constructorArgumentType(OldVar, Result.Nodes),
   *Result.Context))
 return;
 
   if (OldVar == nullptr) {
-handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix, ObjectArg,
-   *Result.Context);
+// `auto NewVar = functionCall();`
+handleCopyFromMethodReturn(Context, ObjectArg);
   } else {
-handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix,
-   *Result.Context);
+// `auto NewVar = OldVar;`
+handleCopyFromLocalVar(Context, *OldVar);
   }
 }
 
 void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
-const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
-bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
-  bool IsConstQualified = Var.getType().isConstQualified();
-  if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context))
+const CheckContext &Ctx, const VarDecl *ObjectArg) {
+  bool IsConstQualified = Ctx.Var.getType().isConstQualified();
+  if (!IsConstQualified && !Ctx.IsVarOnlyUsedAsConst)
 return;
   if (ObjectArg != nullptr &&
-  !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
+  !isInitializingVariableImmutable(*ObjectArg, Ctx.BlockStmt, Ctx.ASTCtx,
ExcludedContainerTypes))
 return;
-  if (isVariableUnused(Var, BlockStmt, Context)) {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference but is never used; consider "
- "removing the statement")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference%select{ but is only used as const "
- "reference|}0; consider making it a const reference")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordFixes(Var, Context, Diagnostic);
-  }
+  diagnoseCopyFromMethodReturn(Ctx);
 }
 
 void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
-const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
-const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
-  if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
-  !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
+const CheckContext &Ctx, const VarDecl &OldVar) {
+  if (!Ctx.IsVarOnlyUsedAsConst ||
+  !isInitializingVariableImmutable(OldVar, Ctx.BlockStmt, Ctx.ASTCtx,
ExcludedContainerTypes))
 return;
+  diagnoseCopyFromLocalVar(Ctx, OldVar);
+}
 
-  if (isVariableUnused(NewVar, BlockStmt, Context)) {
-auto Diagnostic = diag(NewVar.getLocation(),
-   "local copy %0 of the variable %1 is never modified 
"
-   "and never used; "
-   "consider removing the statement")
-  << &NewVar << &OldVar;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(NewVar.getLocation(),
- "local copy %0 of the variable %1 is never modified; "
- "consider avoiding the copy")
-<< &NewVar << &OldVar;
-if (IssueFix)
-  recordFixes(NewVar, Context, Diagnostic);
+void UnnecessaryCopyInitialization::diagnoseCopyFromMethodReturn(
+const CheckContext &Ctx) {
+  auto Diagnostic =
+  diag(Ctx.Var.getLocation(),
+   "the %select{|const qualified }0variable %1 is "
+   "copy-constructed "
+   "from a const reference%select{%select{ but is only used as const "
+   "reference|}0| but is never used}2; consider "
+   "%select{making it a const reference|removing the statement}2")
+  << Ctx.Var.getType().isConstQualified() << &Ctx.Var << Ctx.IsVarUnused;
+  maybeIssueFixes(Ctx, Diagnostic);
+}
+
+void UnnecessaryCopyInitialization::diagnoseCopyFromLocalVar(
+const CheckContext &Ctx, const VarDecl &OldVar) {
+  auto Diagnostic =
+  diag(Ctx.Var.getLocation(),
+   "local copy %1 of the variable %0 is never modified%select{"
+   "| and never used}2; consider %select{avoiding the copy|removing "
+   "the statement}2")
+  << &OldVar << &Ctx.Var << Ctx.IsVarUnused;
+  maybeIssueFixes(Ctx, Diagnostic);
+}
+
+void UnnecessaryCopyInitialization::maybeIssueFixes(
+const CheckContext &Ctx, D

[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-06 Thread Clement Courbet via cfe-commits


@@ -263,19 +264,26 @@ void 
UnnecessaryCopyInitialization::registerMatchers(MatchFinder *Finder) {
 
 void UnnecessaryCopyInitialization::check(
 const MatchFinder::MatchResult &Result) {
-  const auto *NewVar = Result.Nodes.getNodeAs("newVarDecl");
+  const auto &NewVar = *Result.Nodes.getNodeAs("newVarDecl");
+  const auto &BlockStmt = *Result.Nodes.getNodeAs("blockStmt");
+  const auto &VarDeclStmt = *Result.Nodes.getNodeAs("declStmt");
+  const CheckContext Context{
+  NewVar, BlockStmt, VarDeclStmt, *Result.Context,
+  // Do not propose fixes if the DeclStmt has multiple VarDecls or in
+  // macros since we cannot place them correctly.
+  /*IssueFix*/ VarDeclStmt.isSingleDecl() &&

legrosbuffle wrote:

Done.

https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-06 Thread Clement Courbet via cfe-commits

legrosbuffle wrote:

Thanks

https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-06 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle closed 
https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle created 
https://github.com/llvm/llvm-project/pull/73921

... so that derived checks can implement custom behaviour. Does nothing by 
default, which makes this  an NFC.

>From e251c440b42fe67dee4022d08d05e96d30d6aa02 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Thu, 30 Nov 2023 11:08:51 +0100
Subject: [PATCH] [clang-tidy] performance-unnecessary-copy-init: Add a hook...

... so that derived checks can implement custom behaviour.
---
 .../UnnecessaryCopyInitialization.cpp | 24 ---
 .../UnnecessaryCopyInitialization.h   |  9 +--
 2 files changed, 22 insertions(+), 11 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 990e20400fbfcd2..966071e92833b87 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -294,24 +294,28 @@ void UnnecessaryCopyInitialization::check(
 return;
 
   if (OldVar == nullptr) {
-handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix, ObjectArg,
-   *Result.Context);
+if (handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix,
+   ObjectArg, *Result.Context)) {
+  onWarningEmitted(*NewVar, *BlockStmt, *Result.Context);
+}
   } else {
-handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix,
-   *Result.Context);
+if (handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix,
+   *Result.Context)) {
+  onWarningEmitted(*NewVar, *BlockStmt, *Result.Context);
+}  
   }
 }
 
-void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
+bool UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
 bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
   bool IsConstQualified = Var.getType().isConstQualified();
   if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context))
-return;
+return false;
   if (ObjectArg != nullptr &&
   !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
ExcludedContainerTypes))
-return;
+return false;
   if (isVariableUnused(Var, BlockStmt, Context)) {
 auto Diagnostic =
 diag(Var.getLocation(),
@@ -331,15 +335,16 @@ void 
UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 if (IssueFix)
   recordFixes(Var, Context, Diagnostic);
   }
+  return true;
 }
 
-void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
+bool UnnecessaryCopyInitialization::handleCopyFromLocalVar(
 const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
 const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
   if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
   !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
ExcludedContainerTypes))
-return;
+return false;
 
   if (isVariableUnused(NewVar, BlockStmt, Context)) {
 auto Diagnostic = diag(NewVar.getLocation(),
@@ -358,6 +363,7 @@ void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
 if (IssueFix)
   recordFixes(NewVar, Context, Diagnostic);
   }
+  return true;
 }
 
 void UnnecessaryCopyInitialization::storeOptions(
diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
index ea009ba9979de97..7d76c9e7cab940c 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -33,13 +33,18 @@ class UnnecessaryCopyInitialization : public ClangTidyCheck 
{
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
 
 private:
-  void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt,
+  bool handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt,
   const DeclStmt &Stmt, bool IssueFix,
   const VarDecl *ObjectArg,
   ASTContext &Context);
-  void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar,
+  bool handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar,
   const Stmt &BlockStmt, const DeclStmt &Stmt,
   bool IssueFix, ASTContext &Context);
+
+  // A hook called for each emitted warning.
+  virtual void onWarningEmitted(const VarDecl &Var, const Stmt &BlockStmt,
+ASTContext &context) {}
+
   const std::vector AllowedTypes;
   const std::vector ExcludedContainer

[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/73921

>From e0d1f9741d0dba3286fd8043cf6d5c89ecc2d378 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Thu, 30 Nov 2023 11:08:51 +0100
Subject: [PATCH] [clang-tidy] performance-unnecessary-copy-init: Add a hook...

... so that derived checks can implement custom behaviour.
---
 .../UnnecessaryCopyInitialization.cpp | 24 ---
 .../UnnecessaryCopyInitialization.h   |  9 +--
 2 files changed, 22 insertions(+), 11 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 990e20400fbfcd2..1ba32315afe0d35 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -294,24 +294,28 @@ void UnnecessaryCopyInitialization::check(
 return;
 
   if (OldVar == nullptr) {
-handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix, ObjectArg,
-   *Result.Context);
+if (handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix,
+   ObjectArg, *Result.Context)) {
+  onWarningEmitted(*NewVar, *BlockStmt, *Result.Context);
+}
   } else {
-handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix,
-   *Result.Context);
+if (handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix,
+   *Result.Context)) {
+  onWarningEmitted(*NewVar, *BlockStmt, *Result.Context);
+}
   }
 }
 
-void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
+bool UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
 bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
   bool IsConstQualified = Var.getType().isConstQualified();
   if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context))
-return;
+return false;
   if (ObjectArg != nullptr &&
   !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
ExcludedContainerTypes))
-return;
+return false;
   if (isVariableUnused(Var, BlockStmt, Context)) {
 auto Diagnostic =
 diag(Var.getLocation(),
@@ -331,15 +335,16 @@ void 
UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 if (IssueFix)
   recordFixes(Var, Context, Diagnostic);
   }
+  return true;
 }
 
-void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
+bool UnnecessaryCopyInitialization::handleCopyFromLocalVar(
 const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
 const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
   if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
   !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
ExcludedContainerTypes))
-return;
+return false;
 
   if (isVariableUnused(NewVar, BlockStmt, Context)) {
 auto Diagnostic = diag(NewVar.getLocation(),
@@ -358,6 +363,7 @@ void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
 if (IssueFix)
   recordFixes(NewVar, Context, Diagnostic);
   }
+  return true;
 }
 
 void UnnecessaryCopyInitialization::storeOptions(
diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
index ea009ba9979de97..7d76c9e7cab940c 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -33,13 +33,18 @@ class UnnecessaryCopyInitialization : public ClangTidyCheck 
{
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
 
 private:
-  void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt,
+  bool handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt,
   const DeclStmt &Stmt, bool IssueFix,
   const VarDecl *ObjectArg,
   ASTContext &Context);
-  void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar,
+  bool handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar,
   const Stmt &BlockStmt, const DeclStmt &Stmt,
   bool IssueFix, ASTContext &Context);
+
+  // A hook called for each emitted warning.
+  virtual void onWarningEmitted(const VarDecl &Var, const Stmt &BlockStmt,
+ASTContext &context) {}
+
   const std::vector AllowedTypes;
   const std::vector ExcludedContainerTypes;
 };

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
ht

[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits

legrosbuffle wrote:

> First what's a purpose of this change. Is there any other check that will 
> need it or not ?

We have a downstream check that wants to do additional processing after this 
one. We can't submit that check because it depends on a large piece of 
downstream infrastructure.

> With current implementation I don't see any "custom behaviour" that could be 
> implemented, as this act more like observer.

Indeed, the downstream check does not change the behaviour, it does extra stuff 
in addition what the check already does. I've rephrased the commit message to 
make that clearer.

https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle edited 
https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/73921

>From 6050ba4784137bc20e58d553ea970e37237142ae Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Thu, 30 Nov 2023 11:08:51 +0100
Subject: [PATCH] [clang-tidy] performance-unnecessary-copy-init: Add a hook...

... so that derived checks can observe for which variables a warning has been 
emitted.
---
 .../UnnecessaryCopyInitialization.cpp | 24 ---
 .../UnnecessaryCopyInitialization.h   |  9 +--
 2 files changed, 22 insertions(+), 11 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 990e20400fbfcd2..1ba32315afe0d35 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -294,24 +294,28 @@ void UnnecessaryCopyInitialization::check(
 return;
 
   if (OldVar == nullptr) {
-handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix, ObjectArg,
-   *Result.Context);
+if (handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix,
+   ObjectArg, *Result.Context)) {
+  onWarningEmitted(*NewVar, *BlockStmt, *Result.Context);
+}
   } else {
-handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix,
-   *Result.Context);
+if (handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix,
+   *Result.Context)) {
+  onWarningEmitted(*NewVar, *BlockStmt, *Result.Context);
+}
   }
 }
 
-void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
+bool UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
 bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
   bool IsConstQualified = Var.getType().isConstQualified();
   if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context))
-return;
+return false;
   if (ObjectArg != nullptr &&
   !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
ExcludedContainerTypes))
-return;
+return false;
   if (isVariableUnused(Var, BlockStmt, Context)) {
 auto Diagnostic =
 diag(Var.getLocation(),
@@ -331,15 +335,16 @@ void 
UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 if (IssueFix)
   recordFixes(Var, Context, Diagnostic);
   }
+  return true;
 }
 
-void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
+bool UnnecessaryCopyInitialization::handleCopyFromLocalVar(
 const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
 const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
   if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
   !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
ExcludedContainerTypes))
-return;
+return false;
 
   if (isVariableUnused(NewVar, BlockStmt, Context)) {
 auto Diagnostic = diag(NewVar.getLocation(),
@@ -358,6 +363,7 @@ void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
 if (IssueFix)
   recordFixes(NewVar, Context, Diagnostic);
   }
+  return true;
 }
 
 void UnnecessaryCopyInitialization::storeOptions(
diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
index ea009ba9979de97..7d76c9e7cab940c 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -33,13 +33,18 @@ class UnnecessaryCopyInitialization : public ClangTidyCheck 
{
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
 
 private:
-  void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt,
+  bool handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt,
   const DeclStmt &Stmt, bool IssueFix,
   const VarDecl *ObjectArg,
   ASTContext &Context);
-  void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar,
+  bool handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar,
   const Stmt &BlockStmt, const DeclStmt &Stmt,
   bool IssueFix, ASTContext &Context);
+
+  // A hook called for each emitted warning.
+  virtual void onWarningEmitted(const VarDecl &Var, const Stmt &BlockStmt,
+ASTContext &context) {}
+
   const std::vector AllowedTypes;
   const std::vector ExcludedContainerTypes;
 };

___
cfe-commits mailing list

[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/73921

>From a6bc3d7ef798f95fe6ae758e7a9502851e6d4b12 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Thu, 30 Nov 2023 11:08:51 +0100
Subject: [PATCH] [clang-tidy] performance-unnecessary-copy-init: Add a hook...

... so that derived checks can observe for which variables a warning has been 
emitted.
---
 .../UnnecessaryCopyInitialization.cpp | 24 ---
 .../UnnecessaryCopyInitialization.h   |  9 +--
 2 files changed, 22 insertions(+), 11 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 990e20400fbfcd2..1ba32315afe0d35 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -294,24 +294,28 @@ void UnnecessaryCopyInitialization::check(
 return;
 
   if (OldVar == nullptr) {
-handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix, ObjectArg,
-   *Result.Context);
+if (handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix,
+   ObjectArg, *Result.Context)) {
+  onWarningEmitted(*NewVar, *BlockStmt, *Result.Context);
+}
   } else {
-handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix,
-   *Result.Context);
+if (handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix,
+   *Result.Context)) {
+  onWarningEmitted(*NewVar, *BlockStmt, *Result.Context);
+}
   }
 }
 
-void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
+bool UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
 bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
   bool IsConstQualified = Var.getType().isConstQualified();
   if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context))
-return;
+return false;
   if (ObjectArg != nullptr &&
   !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
ExcludedContainerTypes))
-return;
+return false;
   if (isVariableUnused(Var, BlockStmt, Context)) {
 auto Diagnostic =
 diag(Var.getLocation(),
@@ -331,15 +335,16 @@ void 
UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 if (IssueFix)
   recordFixes(Var, Context, Diagnostic);
   }
+  return true;
 }
 
-void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
+bool UnnecessaryCopyInitialization::handleCopyFromLocalVar(
 const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
 const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
   if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
   !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
ExcludedContainerTypes))
-return;
+return false;
 
   if (isVariableUnused(NewVar, BlockStmt, Context)) {
 auto Diagnostic = diag(NewVar.getLocation(),
@@ -358,6 +363,7 @@ void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
 if (IssueFix)
   recordFixes(NewVar, Context, Diagnostic);
   }
+  return true;
 }
 
 void UnnecessaryCopyInitialization::storeOptions(
diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
index ea009ba9979de97..5310c29fad3672c 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -33,13 +33,18 @@ class UnnecessaryCopyInitialization : public ClangTidyCheck 
{
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
 
 private:
-  void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt,
+  bool handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt,
   const DeclStmt &Stmt, bool IssueFix,
   const VarDecl *ObjectArg,
   ASTContext &Context);
-  void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar,
+  bool handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar,
   const Stmt &BlockStmt, const DeclStmt &Stmt,
   bool IssueFix, ASTContext &Context);
+
+  // A hook called after each warnings is emitted.
+  virtual void onWarningEmitted(const VarDecl &Var, const Stmt &BlockStmt,
+ASTContext &context) {}
+
   const std::vector AllowedTypes;
   const std::vector ExcludedContainerTypes;
 };

___
cfe-commits mailing

[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits

legrosbuffle wrote:

> In theory changes that are required for "private" checks should be done by 
> you on some own private fork instead of adding that "unused" code here. But 
> only option I see is simply moving diagnostic to separate methods, and make 
> those methods virtual. 

I see, we don't want code that's dead upstream. Makes sense. I'll do something 
like what you're suggesting.

https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/73921

>From d729f95270aff076ff11ccb1ef12cfb6dc99a82d Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Thu, 30 Nov 2023 11:08:51 +0100
Subject: [PATCH] [clang-tidy] performance-unnecessary-copy-init: Add a hook...

... so that derived checks can observe for which variables a warning has been 
emitted.
---
 .../UnnecessaryCopyInitialization.cpp | 80 +--
 .../UnnecessaryCopyInitialization.h   |  6 ++
 2 files changed, 45 insertions(+), 41 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 990e20400fbfcd2..5b45e911fd11ed0 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/Basic/Diagnostic.h"
 #include 
+#include 
 
 namespace clang::tidy::performance {
 namespace {
@@ -294,14 +295,28 @@ void UnnecessaryCopyInitialization::check(
 return;
 
   if (OldVar == nullptr) {
-handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix, ObjectArg,
-   *Result.Context);
+handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix,
+   ObjectArg, *Result.Context);
   } else {
 handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix,
*Result.Context);
   }
 }
 
+void UnnecessaryCopyInitialization::makeDiagnostic(
+DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt,
+const DeclStmt &Stmt, ASTContext &Context, bool IssueFix) {
+  const bool IsVarUnused = isVariableUnused(Var, BlockStmt, Context);
+  Diagnostic << &Var << IsVarUnused;
+  if (IssueFix) {
+if (IsVarUnused) {
+  recordRemoval(Stmt, Context, Diagnostic);
+} else {
+  recordFixes(Var, Context, Diagnostic);
+}
+  }
+}
+
 void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
 bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
@@ -312,52 +327,34 @@ void 
UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
   !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-  if (isVariableUnused(Var, BlockStmt, Context)) {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference but is never used; consider "
- "removing the statement")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference%select{ but is only used as const "
- "reference|}0; consider making it a const reference")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordFixes(Var, Context, Diagnostic);
-  }
+
+  auto Diagnostic =
+  diag(Var.getLocation(),
+   "the %select{|const qualified }0variable %1 is copy-constructed "
+   "from a const reference%select{"
+   "%select{ but is only used as const reference|}0"
+   "| but is never used}2; consider "
+   "%select{making it a const reference|removing the statement}2")
+  << IsConstQualified;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context,
+ IssueFix);
 }
 
 void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
-const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
+const VarDecl &Var, const VarDecl &OldVar, const Stmt &BlockStmt,
 const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
-  if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
+  if (!isOnlyUsedAsConst(Var, BlockStmt, Context) ||
   !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-
-  if (isVariableUnused(NewVar, BlockStmt, Context)) {
-auto Diagnostic = diag(NewVar.getLocation(),
-   "local copy %0 of the variable %1 is never modified 
"
-   "and never used; "
-   "consider removing the statement")
-  << &NewVar << &OldVar;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(NewVar.getLocation(),
- "local copy %0 of the variable %1 is never modified; "
- "consider avoiding the copy")
-<< &NewVar << &OldVar;
-if

[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/73921

>From a072ae129b1ad928c96368a3208d35cc0705e260 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Thu, 30 Nov 2023 11:08:51 +0100
Subject: [PATCH] [clang-tidy] performance-unnecessary-copy-init

Refactor diagnostic emission and add a hook so that derived checks
can observe for which variables a warning has been emitted.
---
 .../UnnecessaryCopyInitialization.cpp | 80 +--
 .../UnnecessaryCopyInitialization.h   |  6 ++
 2 files changed, 45 insertions(+), 41 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 990e20400fbfcd2..5b45e911fd11ed0 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/Basic/Diagnostic.h"
 #include 
+#include 
 
 namespace clang::tidy::performance {
 namespace {
@@ -294,14 +295,28 @@ void UnnecessaryCopyInitialization::check(
 return;
 
   if (OldVar == nullptr) {
-handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix, ObjectArg,
-   *Result.Context);
+handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Stmt, IssueFix,
+   ObjectArg, *Result.Context);
   } else {
 handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Stmt, IssueFix,
*Result.Context);
   }
 }
 
+void UnnecessaryCopyInitialization::makeDiagnostic(
+DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt,
+const DeclStmt &Stmt, ASTContext &Context, bool IssueFix) {
+  const bool IsVarUnused = isVariableUnused(Var, BlockStmt, Context);
+  Diagnostic << &Var << IsVarUnused;
+  if (IssueFix) {
+if (IsVarUnused) {
+  recordRemoval(Stmt, Context, Diagnostic);
+} else {
+  recordFixes(Var, Context, Diagnostic);
+}
+  }
+}
+
 void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
 bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
@@ -312,52 +327,34 @@ void 
UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
   !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-  if (isVariableUnused(Var, BlockStmt, Context)) {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference but is never used; consider "
- "removing the statement")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference%select{ but is only used as const "
- "reference|}0; consider making it a const reference")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordFixes(Var, Context, Diagnostic);
-  }
+
+  auto Diagnostic =
+  diag(Var.getLocation(),
+   "the %select{|const qualified }0variable %1 is copy-constructed "
+   "from a const reference%select{"
+   "%select{ but is only used as const reference|}0"
+   "| but is never used}2; consider "
+   "%select{making it a const reference|removing the statement}2")
+  << IsConstQualified;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context,
+ IssueFix);
 }
 
 void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
-const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
+const VarDecl &Var, const VarDecl &OldVar, const Stmt &BlockStmt,
 const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
-  if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
+  if (!isOnlyUsedAsConst(Var, BlockStmt, Context) ||
   !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-
-  if (isVariableUnused(NewVar, BlockStmt, Context)) {
-auto Diagnostic = diag(NewVar.getLocation(),
-   "local copy %0 of the variable %1 is never modified 
"
-   "and never used; "
-   "consider removing the statement")
-  << &NewVar << &OldVar;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(NewVar.getLocation(),
- "local copy %0 of the variable %1 is never modified; "
- "consider avoiding the copy")
-<< &Ne

[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/73921

>From 0bf4d8335063c1403dc91d8fccca42e3f03bad35 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Thu, 30 Nov 2023 11:08:51 +0100
Subject: [PATCH] [clang-tidy] performance-unnecessary-copy-init

Refactor diagnostic emission and add a hook so that derived checks
can observe for which variables a warning has been emitted.
---
 .../UnnecessaryCopyInitialization.cpp | 74 +--
 .../UnnecessaryCopyInitialization.h   |  7 ++
 2 files changed, 42 insertions(+), 39 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 990e20400fbfcd2..b2775ac021f4505 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/Basic/Diagnostic.h"
 #include 
+#include 
 
 namespace clang::tidy::performance {
 namespace {
@@ -302,6 +303,20 @@ void UnnecessaryCopyInitialization::check(
   }
 }
 
+void UnnecessaryCopyInitialization::makeDiagnostic(
+DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt,
+const DeclStmt &Stmt, ASTContext &Context, bool IssueFix) {
+  const bool IsVarUnused = isVariableUnused(Var, BlockStmt, Context);
+  Diagnostic << &Var << IsVarUnused;
+  if (IssueFix) {
+if (IsVarUnused) {
+  recordRemoval(Stmt, Context, Diagnostic);
+} else {
+  recordFixes(Var, Context, Diagnostic);
+}
+  }
+}
+
 void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
 bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
@@ -312,52 +327,33 @@ void 
UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
   !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-  if (isVariableUnused(Var, BlockStmt, Context)) {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference but is never used; consider "
- "removing the statement")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference%select{ but is only used as const "
- "reference|}0; consider making it a const reference")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordFixes(Var, Context, Diagnostic);
-  }
+
+  auto Diagnostic =
+  diag(Var.getLocation(),
+   "the %select{|const qualified }0variable %1 is copy-constructed "
+   "from a const reference%select{"
+   "%select{ but is only used as const reference|}0"
+   "| but is never used}2; consider "
+   "%select{making it a const reference|removing the statement}2")
+  << IsConstQualified;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context,
+ IssueFix);
 }
 
 void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
-const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
+const VarDecl &Var, const VarDecl &OldVar, const Stmt &BlockStmt,
 const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
-  if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
+  if (!isOnlyUsedAsConst(Var, BlockStmt, Context) ||
   !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-
-  if (isVariableUnused(NewVar, BlockStmt, Context)) {
-auto Diagnostic = diag(NewVar.getLocation(),
-   "local copy %0 of the variable %1 is never modified 
"
-   "and never used; "
-   "consider removing the statement")
-  << &NewVar << &OldVar;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(NewVar.getLocation(),
- "local copy %0 of the variable %1 is never modified; "
- "consider avoiding the copy")
-<< &NewVar << &OldVar;
-if (IssueFix)
-  recordFixes(NewVar, Context, Diagnostic);
-  }
+  auto Diagnostic = diag(Var.getLocation(),
+ "local copy %1 of the variable %0 is never modified"
+ "%select{| and never used}2; consider "
+ "%select{avoiding the copy|removing the statement}2")
+<< &OldVar;
+  makeDiagnostic(std::move(Diagnostic), Var, 

[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits

legrosbuffle wrote:

This is ready for another look. I took this as an opportunity to refactor the 
duplicated parts of the code. Let me know what you think.

https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits


@@ -302,6 +303,20 @@ void UnnecessaryCopyInitialization::check(
   }
 }
 
+void UnnecessaryCopyInitialization::makeDiagnostic(
+DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt,

legrosbuffle wrote:

I can't really do that because each of the two uses of this function are 
streaming one description-dependent parameter (`IsConstQualified` for one and 
`OldVar` for the other). These are even different types. So it feels simpler to 
stream before entering the function, so that the function only holds logic 
which is common to both callers.

https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits


@@ -302,6 +303,20 @@ void UnnecessaryCopyInitialization::check(
   }
 }
 
+void UnnecessaryCopyInitialization::makeDiagnostic(
+DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt,
+const DeclStmt &Stmt, ASTContext &Context, bool IssueFix) {
+  const bool IsVarUnused = isVariableUnused(Var, BlockStmt, Context);
+  Diagnostic << &Var << IsVarUnused;
+  if (IssueFix) {

legrosbuffle wrote:

Done.

https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits


@@ -302,6 +303,20 @@ void UnnecessaryCopyInitialization::check(
   }
 }
 
+void UnnecessaryCopyInitialization::makeDiagnostic(
+DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt,
+const DeclStmt &Stmt, ASTContext &Context, bool IssueFix) {
+  const bool IsVarUnused = isVariableUnused(Var, BlockStmt, Context);
+  Diagnostic << &Var << IsVarUnused;
+  if (IssueFix) {
+if (IsVarUnused) {

legrosbuffle wrote:

Done.

https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-11-30 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/73921

>From 851460af6526f175bc34b105a0f5f130a2f1c6b1 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Thu, 30 Nov 2023 11:08:51 +0100
Subject: [PATCH] [clang-tidy] performance-unnecessary-copy-init

Refactor diagnostic emission and add a hook so that derived checks
can observe for which variables a warning has been emitted.
---
 .../UnnecessaryCopyInitialization.cpp | 73 +--
 .../UnnecessaryCopyInitialization.h   |  7 ++
 2 files changed, 41 insertions(+), 39 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 990e20400fbfcd2..a9ef3faf8c343c9 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/Basic/Diagnostic.h"
 #include 
+#include 
 
 namespace clang::tidy::performance {
 namespace {
@@ -302,6 +303,19 @@ void UnnecessaryCopyInitialization::check(
   }
 }
 
+void UnnecessaryCopyInitialization::makeDiagnostic(
+DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt,
+const DeclStmt &Stmt, ASTContext &Context, bool IssueFix) {
+  const bool IsVarUnused = isVariableUnused(Var, BlockStmt, Context);
+  Diagnostic << &Var << IsVarUnused;
+  if (!IssueFix)
+return;
+  if (IsVarUnused)
+recordRemoval(Stmt, Context, Diagnostic);
+  else
+recordFixes(Var, Context, Diagnostic);
+}
+
 void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
 bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
@@ -312,52 +326,33 @@ void 
UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
   !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-  if (isVariableUnused(Var, BlockStmt, Context)) {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference but is never used; consider "
- "removing the statement")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference%select{ but is only used as const "
- "reference|}0; consider making it a const reference")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordFixes(Var, Context, Diagnostic);
-  }
+
+  auto Diagnostic =
+  diag(Var.getLocation(),
+   "the %select{|const qualified }0variable %1 is copy-constructed "
+   "from a const reference%select{"
+   "%select{ but is only used as const reference|}0"
+   "| but is never used}2; consider "
+   "%select{making it a const reference|removing the statement}2")
+  << IsConstQualified;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context,
+ IssueFix);
 }
 
 void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
-const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
+const VarDecl &Var, const VarDecl &OldVar, const Stmt &BlockStmt,
 const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
-  if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
+  if (!isOnlyUsedAsConst(Var, BlockStmt, Context) ||
   !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-
-  if (isVariableUnused(NewVar, BlockStmt, Context)) {
-auto Diagnostic = diag(NewVar.getLocation(),
-   "local copy %0 of the variable %1 is never modified 
"
-   "and never used; "
-   "consider removing the statement")
-  << &NewVar << &OldVar;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(NewVar.getLocation(),
- "local copy %0 of the variable %1 is never modified; "
- "consider avoiding the copy")
-<< &NewVar << &OldVar;
-if (IssueFix)
-  recordFixes(NewVar, Context, Diagnostic);
-  }
+  auto Diagnostic = diag(Var.getLocation(),
+ "local copy %1 of the variable %0 is never modified"
+ "%select{| and never used}2; consider "
+ "%select{avoiding the copy|removing the statement}2")
+<< &OldVar;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stm

[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-01 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/73921

>From 851460af6526f175bc34b105a0f5f130a2f1c6b1 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Thu, 30 Nov 2023 11:08:51 +0100
Subject: [PATCH 1/2] [clang-tidy] performance-unnecessary-copy-init

Refactor diagnostic emission and add a hook so that derived checks
can observe for which variables a warning has been emitted.
---
 .../UnnecessaryCopyInitialization.cpp | 73 +--
 .../UnnecessaryCopyInitialization.h   |  7 ++
 2 files changed, 41 insertions(+), 39 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 990e20400fbfcd2..a9ef3faf8c343c9 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/Basic/Diagnostic.h"
 #include 
+#include 
 
 namespace clang::tidy::performance {
 namespace {
@@ -302,6 +303,19 @@ void UnnecessaryCopyInitialization::check(
   }
 }
 
+void UnnecessaryCopyInitialization::makeDiagnostic(
+DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt,
+const DeclStmt &Stmt, ASTContext &Context, bool IssueFix) {
+  const bool IsVarUnused = isVariableUnused(Var, BlockStmt, Context);
+  Diagnostic << &Var << IsVarUnused;
+  if (!IssueFix)
+return;
+  if (IsVarUnused)
+recordRemoval(Stmt, Context, Diagnostic);
+  else
+recordFixes(Var, Context, Diagnostic);
+}
+
 void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
 bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
@@ -312,52 +326,33 @@ void 
UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
   !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-  if (isVariableUnused(Var, BlockStmt, Context)) {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference but is never used; consider "
- "removing the statement")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference%select{ but is only used as const "
- "reference|}0; consider making it a const reference")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordFixes(Var, Context, Diagnostic);
-  }
+
+  auto Diagnostic =
+  diag(Var.getLocation(),
+   "the %select{|const qualified }0variable %1 is copy-constructed "
+   "from a const reference%select{"
+   "%select{ but is only used as const reference|}0"
+   "| but is never used}2; consider "
+   "%select{making it a const reference|removing the statement}2")
+  << IsConstQualified;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context,
+ IssueFix);
 }
 
 void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
-const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
+const VarDecl &Var, const VarDecl &OldVar, const Stmt &BlockStmt,
 const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
-  if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
+  if (!isOnlyUsedAsConst(Var, BlockStmt, Context) ||
   !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-
-  if (isVariableUnused(NewVar, BlockStmt, Context)) {
-auto Diagnostic = diag(NewVar.getLocation(),
-   "local copy %0 of the variable %1 is never modified 
"
-   "and never used; "
-   "consider removing the statement")
-  << &NewVar << &OldVar;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(NewVar.getLocation(),
- "local copy %0 of the variable %1 is never modified; "
- "consider avoiding the copy")
-<< &NewVar << &OldVar;
-if (IssueFix)
-  recordFixes(NewVar, Context, Diagnostic);
-  }
+  auto Diagnostic = diag(Var.getLocation(),
+ "local copy %1 of the variable %0 is never modified"
+ "%select{| and never used}2; consider "
+ "%select{avoiding the copy|removing the statement}2")
+<< &OldVar;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt,

[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-01 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/73921

>From 851460af6526f175bc34b105a0f5f130a2f1c6b1 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Thu, 30 Nov 2023 11:08:51 +0100
Subject: [PATCH 1/2] [clang-tidy] performance-unnecessary-copy-init

Refactor diagnostic emission and add a hook so that derived checks
can observe for which variables a warning has been emitted.
---
 .../UnnecessaryCopyInitialization.cpp | 73 +--
 .../UnnecessaryCopyInitialization.h   |  7 ++
 2 files changed, 41 insertions(+), 39 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 990e20400fbfcd2..a9ef3faf8c343c9 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/Basic/Diagnostic.h"
 #include 
+#include 
 
 namespace clang::tidy::performance {
 namespace {
@@ -302,6 +303,19 @@ void UnnecessaryCopyInitialization::check(
   }
 }
 
+void UnnecessaryCopyInitialization::makeDiagnostic(
+DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt,
+const DeclStmt &Stmt, ASTContext &Context, bool IssueFix) {
+  const bool IsVarUnused = isVariableUnused(Var, BlockStmt, Context);
+  Diagnostic << &Var << IsVarUnused;
+  if (!IssueFix)
+return;
+  if (IsVarUnused)
+recordRemoval(Stmt, Context, Diagnostic);
+  else
+recordFixes(Var, Context, Diagnostic);
+}
+
 void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
 const VarDecl &Var, const Stmt &BlockStmt, const DeclStmt &Stmt,
 bool IssueFix, const VarDecl *ObjectArg, ASTContext &Context) {
@@ -312,52 +326,33 @@ void 
UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
   !isInitializingVariableImmutable(*ObjectArg, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-  if (isVariableUnused(Var, BlockStmt, Context)) {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference but is never used; consider "
- "removing the statement")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(Var.getLocation(),
- "the %select{|const qualified }0variable %1 is copy-constructed "
- "from a const reference%select{ but is only used as const "
- "reference|}0; consider making it a const reference")
-<< IsConstQualified << &Var;
-if (IssueFix)
-  recordFixes(Var, Context, Diagnostic);
-  }
+
+  auto Diagnostic =
+  diag(Var.getLocation(),
+   "the %select{|const qualified }0variable %1 is copy-constructed "
+   "from a const reference%select{"
+   "%select{ but is only used as const reference|}0"
+   "| but is never used}2; consider "
+   "%select{making it a const reference|removing the statement}2")
+  << IsConstQualified;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt, Stmt, Context,
+ IssueFix);
 }
 
 void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
-const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
+const VarDecl &Var, const VarDecl &OldVar, const Stmt &BlockStmt,
 const DeclStmt &Stmt, bool IssueFix, ASTContext &Context) {
-  if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
+  if (!isOnlyUsedAsConst(Var, BlockStmt, Context) ||
   !isInitializingVariableImmutable(OldVar, BlockStmt, Context,
ExcludedContainerTypes))
 return;
-
-  if (isVariableUnused(NewVar, BlockStmt, Context)) {
-auto Diagnostic = diag(NewVar.getLocation(),
-   "local copy %0 of the variable %1 is never modified 
"
-   "and never used; "
-   "consider removing the statement")
-  << &NewVar << &OldVar;
-if (IssueFix)
-  recordRemoval(Stmt, Context, Diagnostic);
-  } else {
-auto Diagnostic =
-diag(NewVar.getLocation(),
- "local copy %0 of the variable %1 is never modified; "
- "consider avoiding the copy")
-<< &NewVar << &OldVar;
-if (IssueFix)
-  recordFixes(NewVar, Context, Diagnostic);
-  }
+  auto Diagnostic = diag(Var.getLocation(),
+ "local copy %1 of the variable %0 is never modified"
+ "%select{| and never used}2; consider "
+ "%select{avoiding the copy|removing the statement}2")
+<< &OldVar;
+  makeDiagnostic(std::move(Diagnostic), Var, BlockStmt,

[clang-tools-extra] [clang-tidy] performance-unnecessary-copy-init: Add a hook... (PR #73921)

2023-12-01 Thread Clement Courbet via cfe-commits


@@ -302,6 +303,20 @@ void UnnecessaryCopyInitialization::check(
   }
 }
 
+void UnnecessaryCopyInitialization::makeDiagnostic(
+DiagnosticBuilder Diagnostic, const VarDecl &Var, const Stmt &BlockStmt,

legrosbuffle wrote:

Done. I've kept the code common to these two functions factored out into 
`maybeIssueFixes`, and I've created a helper struct for the 5 common parameters 
to these two functions (and the additional 2 boolean variables that these two 
have in common).

https://github.com/llvm/llvm-project/pull/73921
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang-tidy] Handle C++ structured bindings in `performance-for-range-copy` (PR #77105)

2024-01-05 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle created 
https://github.com/llvm/llvm-project/pull/77105

Right now we are not triggering on:

```
for (auto [x, y] : container) {
  // const-only access
}
```

>From d5b83c7e8624ba6fde2ea9eb8c3589fe083067b8 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Fri, 5 Jan 2024 15:48:51 +0100
Subject: [PATCH] [clang-tidy] Handle C++ bindings in
 `performance-for-range-copy`

Right now we are not triggering on:

```
for (auto [x, y] : container) {
  // const-only access
}
```
---
 .../performance/ForRangeCopyCheck.cpp | 13 ++--
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +++
 .../checkers/performance/for-range-copy.cpp   | 31 ---
 clang/lib/Analysis/ExprMutationAnalyzer.cpp   | 13 ++--
 .../Analysis/ExprMutationAnalyzerTest.cpp | 20 
 5 files changed, 70 insertions(+), 11 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp 
b/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
index 5bfa6fb0d02d5c..655e480ffa62cb 100644
--- a/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
@@ -97,6 +97,15 @@ bool ForRangeCopyCheck::handleConstValueCopy(const VarDecl 
&LoopVar,
   return true;
 }
 
+static bool isReferenced(const VarDecl &LoopVar, const Stmt &Stmt,
+ ASTContext &Context) {
+  const auto IsLoopVar = varDecl(equalsNode(&LoopVar));
+  return !match(stmt(hasDescendant(declRefExpr(to(valueDecl(anyOf(
+IsLoopVar, bindingDecl(forDecomposition(IsLoopVar,
+Stmt, Context)
+  .empty();
+}
+
 bool ForRangeCopyCheck::handleCopyIsOnlyConstReferenced(
 const VarDecl &LoopVar, const CXXForRangeStmt &ForRange,
 ASTContext &Context) {
@@ -113,9 +122,7 @@ bool ForRangeCopyCheck::handleCopyIsOnlyConstReferenced(
   // compiler warning which can't be suppressed.
   // Since this case is very rare, it is safe to ignore it.
   if (!ExprMutationAnalyzer(*ForRange.getBody(), Context).isMutated(&LoopVar) 
&&
-  !utils::decl_ref_expr::allDeclRefExprs(LoopVar, *ForRange.getBody(),
- Context)
-   .empty()) {
+  isReferenced(LoopVar, *ForRange.getBody(), Context)) {
 auto Diag = diag(
 LoopVar.getLocation(),
 "loop variable is copied but only used as const reference; consider "
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 4d25e2ebe85f5f..4491d239dc7888 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -419,6 +419,10 @@ Changes in existing checks
   ` check to properly escape
   single quotes.
 
+- Improved :doc:`performance-for-range-copy
+  ` check to handle cases where
+  the loop variable is a structured binding.
+
 - Improved :doc:`performance-noexcept-move-constructor
   ` to better handle
   conditional noexcept expressions, eliminating false-positives.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/performance/for-range-copy.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/performance/for-range-copy.cpp
index 1a2eedc9e65c53..e8c967dacfb7d5 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/performance/for-range-copy.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/performance/for-range-copy.cpp
@@ -47,6 +47,11 @@ struct S {
   S &operator=(const S &);
 };
 
+struct Point {
+  ~Point() {}
+  int x, y;
+};
+
 struct Convertible {
   operator S() const {
 return S();
@@ -87,6 +92,10 @@ void instantiated() {
   // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is 
{{.*}}
   // CHECK-FIXES: {{^}}  for (const S& S2 : View>()) {}
 
+  for (const auto [X, Y] : View>()) {}
+  // CHECK-MESSAGES: [[@LINE-1]]:19: warning: the loop variable's type is
+  // CHECK-FIXES: {{^}}  for (const auto& [X, Y] : View>()) {}
+
   for (const T T2 : View>()) {}
   // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is 
{{.*}}
   // CHECK-FIXES: {{^}}  for (const T& T2 : View>()) {}
@@ -123,11 +132,6 @@ struct Mutable {
   ~Mutable() {}
 };
 
-struct Point {
-  ~Point() {}
-  int x, y;
-};
-
 Mutable& operator<<(Mutable &Out, bool B) {
   Out.setBool(B);
   return Out;
@@ -144,6 +148,7 @@ void useByValue(Mutable M);
 void useByConstValue(const Mutable M);
 void mutate(Mutable *M);
 void mutate(Mutable &M);
+void mutate(int &);
 void onceConstOnceMutated(const Mutable &M1, Mutable &M2);
 
 void negativeVariableIsMutated() {
@@ -234,6 +239,22 @@ void positiveOnlyAccessedFieldAsConst() {
   }
 }
 
+void positiveOnlyAccessedFieldAsConstBinding() {
+  for (auto [X, Y] : View>()) {
+// CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but
+// CHECK-FIXES: for (const auto& [X, Y] : View>()) {
+use(X);
+use(Y);
+  }
+}
+
+void negativeOnlyAccessedFieldAsConstBinding() {
+  for (auto [X, Y

[clang-tools-extra] [clang] [clang-tidy] Handle C++ structured bindings in `performance-for-range-copy` (PR #77105)

2024-01-08 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/77105

>From 7420ce9460fa0e07bc570087c39b8ee98775713a Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Fri, 5 Jan 2024 15:48:51 +0100
Subject: [PATCH] [clang-tidy] Handle C++ bindings in
 `performance-for-range-copy`

Right now we are not triggering on:

```
for (auto [x, y] : container) {
  // const-only access
}
```
---
 .../performance/ForRangeCopyCheck.cpp | 13 ++--
 clang-tools-extra/docs/ReleaseNotes.rst   |  4 +++
 .../checkers/performance/for-range-copy.cpp   | 31 ---
 clang/lib/Analysis/ExprMutationAnalyzer.cpp   | 13 ++--
 .../Analysis/ExprMutationAnalyzerTest.cpp | 20 
 5 files changed, 70 insertions(+), 11 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp 
b/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
index 5bfa6fb0d02d5c..655e480ffa62cb 100644
--- a/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
@@ -97,6 +97,15 @@ bool ForRangeCopyCheck::handleConstValueCopy(const VarDecl 
&LoopVar,
   return true;
 }
 
+static bool isReferenced(const VarDecl &LoopVar, const Stmt &Stmt,
+ ASTContext &Context) {
+  const auto IsLoopVar = varDecl(equalsNode(&LoopVar));
+  return !match(stmt(hasDescendant(declRefExpr(to(valueDecl(anyOf(
+IsLoopVar, bindingDecl(forDecomposition(IsLoopVar,
+Stmt, Context)
+  .empty();
+}
+
 bool ForRangeCopyCheck::handleCopyIsOnlyConstReferenced(
 const VarDecl &LoopVar, const CXXForRangeStmt &ForRange,
 ASTContext &Context) {
@@ -113,9 +122,7 @@ bool ForRangeCopyCheck::handleCopyIsOnlyConstReferenced(
   // compiler warning which can't be suppressed.
   // Since this case is very rare, it is safe to ignore it.
   if (!ExprMutationAnalyzer(*ForRange.getBody(), Context).isMutated(&LoopVar) 
&&
-  !utils::decl_ref_expr::allDeclRefExprs(LoopVar, *ForRange.getBody(),
- Context)
-   .empty()) {
+  isReferenced(LoopVar, *ForRange.getBody(), Context)) {
 auto Diag = diag(
 LoopVar.getLocation(),
 "loop variable is copied but only used as const reference; consider "
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 4d25e2ebe85f5f..4491d239dc7888 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -419,6 +419,10 @@ Changes in existing checks
   ` check to properly escape
   single quotes.
 
+- Improved :doc:`performance-for-range-copy
+  ` check to handle cases where
+  the loop variable is a structured binding.
+
 - Improved :doc:`performance-noexcept-move-constructor
   ` to better handle
   conditional noexcept expressions, eliminating false-positives.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/performance/for-range-copy.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/performance/for-range-copy.cpp
index 1a2eedc9e65c53..f9d06898ca03de 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/performance/for-range-copy.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/performance/for-range-copy.cpp
@@ -47,6 +47,11 @@ struct S {
   S &operator=(const S &);
 };
 
+struct Point {
+  ~Point() {}
+  int x, y;
+};
+
 struct Convertible {
   operator S() const {
 return S();
@@ -87,6 +92,10 @@ void instantiated() {
   // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is 
{{.*}}
   // CHECK-FIXES: {{^}}  for (const S& S2 : View>()) {}
 
+  for (const auto [X, Y] : View>()) {}
+  // CHECK-MESSAGES: [[@LINE-1]]:19: warning: the loop variable's type is
+  // CHECK-FIXES: {{^}}  for (const auto& [X, Y] : View>()) {}
+
   for (const T T2 : View>()) {}
   // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is 
{{.*}}
   // CHECK-FIXES: {{^}}  for (const T& T2 : View>()) {}
@@ -123,11 +132,6 @@ struct Mutable {
   ~Mutable() {}
 };
 
-struct Point {
-  ~Point() {}
-  int x, y;
-};
-
 Mutable& operator<<(Mutable &Out, bool B) {
   Out.setBool(B);
   return Out;
@@ -144,6 +148,7 @@ void useByValue(Mutable M);
 void useByConstValue(const Mutable M);
 void mutate(Mutable *M);
 void mutate(Mutable &M);
+void mutate(int &);
 void onceConstOnceMutated(const Mutable &M1, Mutable &M2);
 
 void negativeVariableIsMutated() {
@@ -234,6 +239,22 @@ void positiveOnlyAccessedFieldAsConst() {
   }
 }
 
+void positiveOnlyUsedAsConstBinding() {
+  for (auto [X, Y] : View>()) {
+// CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but
+// CHECK-FIXES: for (const auto& [X, Y] : View>()) {
+use(X);
+use(Y);
+  }
+}
+
+void negativeMutatedBinding() {
+  for (auto [X, Y] : View>()) {
+use(X);
+mutate(Y);
+  }
+}
+
 void positiveOnlyUsedInCopyConstructor() {
   for (auto A : View>()) {
   

[clang] [clang-tools-extra] [clang-tidy] Handle C++ structured bindings in `performance-for-range-copy` (PR #77105)

2024-01-08 Thread Clement Courbet via cfe-commits


@@ -234,6 +239,22 @@ void positiveOnlyAccessedFieldAsConst() {
   }
 }
 
+void positiveOnlyAccessedFieldAsConstBinding() {
+  for (auto [X, Y] : View>()) {
+// CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but
+// CHECK-FIXES: for (const auto& [X, Y] : View>()) {
+use(X);
+use(Y);
+  }
+}
+
+void negativeOnlyAccessedFieldAsConstBinding() {

legrosbuffle wrote:

Done.

https://github.com/llvm/llvm-project/pull/77105
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang-tidy] Handle C++ structured bindings in `performance-for-range-copy` (PR #77105)

2024-01-08 Thread Clement Courbet via cfe-commits


@@ -234,6 +239,22 @@ void positiveOnlyAccessedFieldAsConst() {
   }
 }
 
+void positiveOnlyAccessedFieldAsConstBinding() {

legrosbuffle wrote:

Done.

https://github.com/llvm/llvm-project/pull/77105
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[lld] [clang] [clang-tools-extra] [llvm] [llvm-exegesis] Add support for validation counters (PR #76653)

2024-01-11 Thread Clement Courbet via cfe-commits


@@ -112,9 +116,11 @@ class Counter {
   PerfEvent Event;
   int FileDescriptor = -1;
   bool IsDummyEvent;
+  std::vector ValidationEvents;

legrosbuffle wrote:

OK, let's rename `Counter` to `CounterGroup`, but let's at least create a 
(private) abstraction for an event and attached FD, to avoid the aligned arrays 
code duplication in `Counter::initRealEvent`:

```
  struct ConfiguredEvent {
llvm::Error init(const pid_t ProcessID, const int GroupFd) {
  constexpr  int Cpu = -1; // measure any processor.
  constexpr int GroupFd = -1; // no grouping of counters.
  constexpr uint32_t Flags = 0;
  perf_event_attr AttrCopy = *Event.attribute();
  FileDescriptor = perf_event_open(&AttrCopy, ProcessID, Cpu, GroupFd, 
Flags);
  if (FileDescriptor == -1) {
return ...;
  }
};
PerfEvent Event;
int FileDescriptor = -1;
  };
  // The main event, configured as an ungrouped event.
  ConfiguredEvent MainEvent;
  bool IsDummyEvent;
  // A set of optional validation events grouped into the file descriptor for
  // `MainEvent` using `PERF_IOC_FLAG_GROUP`.
  std::vector ValidationEvents;
```

https://github.com/llvm/llvm-project/pull/76653
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] 5331e12 - [clang][transformer] Fix crash on replacement-less ASTEdit.

2022-08-10 Thread Clement Courbet via cfe-commits

Author: Clement Courbet
Date: 2022-08-10T09:08:05+02:00
New Revision: 5331e1229aa6d0d33b5ec9fab7c05310187746d9

URL: 
https://github.com/llvm/llvm-project/commit/5331e1229aa6d0d33b5ec9fab7c05310187746d9
DIFF: 
https://github.com/llvm/llvm-project/commit/5331e1229aa6d0d33b5ec9fab7c05310187746d9.diff

LOG: [clang][transformer] Fix crash on replacement-less ASTEdit.

Given that we provide an EditGenerator edit(ASTEdit), we can't ever be
sure that the user won't give us an empty replacement.

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

Added: 


Modified: 
clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp
clang/lib/Tooling/Transformer/RewriteRule.cpp

Removed: 




diff  --git 
a/clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp 
b/clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp
index a3600ab58ff3f..9106d5a77dd7d 100644
--- a/clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp
+++ b/clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp
@@ -90,6 +90,32 @@ TEST(TransformerClangTidyCheckTest, 
DiagnosticsCorrectlyGenerated) {
   EXPECT_EQ(Errors[0].Message.FileOffset, 10U);
 }
 
+transformer::ASTEdit noReplacementEdit(transformer::RangeSelector Target) {
+  transformer::ASTEdit E;
+  E.TargetRange = std::move(Target);
+  return E;
+}
+
+TEST(TransformerClangTidyCheckTest, EmptyReplacement) {
+  class DiagOnlyCheck : public TransformerClangTidyCheck {
+  public:
+DiagOnlyCheck(StringRef Name, ClangTidyContext *Context)
+: TransformerClangTidyCheck(
+  makeRule(returnStmt(), edit(noReplacementEdit(node(RootID))),
+   cat("message")),
+  Name, Context) {}
+  };
+  std::string Input = "int h() { return 5; }";
+  std::vector Errors;
+  EXPECT_EQ("int h() { }", test::runCheckOnCode(Input, 
&Errors));
+  EXPECT_EQ(Errors.size(), 1U);
+  EXPECT_EQ(Errors[0].Message.Message, "message");
+  EXPECT_THAT(Errors[0].Message.Ranges, testing::IsEmpty());
+
+  // The diagnostic is anchored to the match, "return 5".
+  EXPECT_EQ(Errors[0].Message.FileOffset, 10U);
+}
+
 TEST(TransformerClangTidyCheckTest, DiagnosticMessageEscaped) {
   class GiveDiagWithPercentSymbol : public TransformerClangTidyCheck {
   public:

diff  --git a/clang/lib/Tooling/Transformer/RewriteRule.cpp 
b/clang/lib/Tooling/Transformer/RewriteRule.cpp
index 3e76489782f34..822d00d33d164 100644
--- a/clang/lib/Tooling/Transformer/RewriteRule.cpp
+++ b/clang/lib/Tooling/Transformer/RewriteRule.cpp
@@ -50,17 +50,21 @@ translateEdits(const MatchResult &Result, ArrayRef 
ASTEdits) {
 // produces a bad range, whereas the latter will simply ignore A.
 if (!EditRange)
   return SmallVector();
-auto Replacement = E.Replacement->eval(Result);
-if (!Replacement)
-  return Replacement.takeError();
-auto Metadata = E.Metadata(Result);
-if (!Metadata)
-  return Metadata.takeError();
 transformer::Edit T;
 T.Kind = E.Kind;
 T.Range = *EditRange;
-T.Replacement = std::move(*Replacement);
-T.Metadata = std::move(*Metadata);
+if (E.Replacement) {
+  auto Replacement = E.Replacement->eval(Result);
+  if (!Replacement)
+return Replacement.takeError();
+  T.Replacement = std::move(*Replacement);
+}
+if (E.Metadata) {
+  auto Metadata = E.Metadata(Result);
+  if (!Metadata)
+return Metadata.takeError();
+  T.Metadata = std::move(*Metadata);
+}
 Edits.push_back(std::move(T));
   }
   return Edits;



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


[clang] 90d2291 - [NFC] Fix comment.

2022-02-08 Thread Clement Courbet via cfe-commits

Author: Clement Courbet
Date: 2022-02-08T09:42:44+01:00
New Revision: 90d2291fbb4a382d8a36dfbb2bcfcc55f21b2bdc

URL: 
https://github.com/llvm/llvm-project/commit/90d2291fbb4a382d8a36dfbb2bcfcc55f21b2bdc
DIFF: 
https://github.com/llvm/llvm-project/commit/90d2291fbb4a382d8a36dfbb2bcfcc55f21b2bdc.diff

LOG: [NFC] Fix comment.

The extra space causes the table to render incorrectly in doxygen.

Added: 


Modified: 
clang/include/clang/Basic/Lambda.h

Removed: 




diff  --git a/clang/include/clang/Basic/Lambda.h 
b/clang/include/clang/Basic/Lambda.h
index 853821a33c2ad..de01d6f33c015 100644
--- a/clang/include/clang/Basic/Lambda.h
+++ b/clang/include/clang/Basic/Lambda.h
@@ -32,7 +32,7 @@ enum LambdaCaptureDefault {
 /// is an expression.
 enum LambdaCaptureKind {
   LCK_This,   ///< Capturing the \c *this object by reference
-  LCK_StarThis, /// < Capturing the \c *this object by copy
+  LCK_StarThis, ///< Capturing the \c *this object by copy
   LCK_ByCopy, ///< Capturing by copy (a.k.a., by value)
   LCK_ByRef,  ///< Capturing by reference
   LCK_VLAType ///< Capturing variable-length array type



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


[clang-tools-extra] [clang-tidy] `isOnlyUsedAsConst`: Handle static method calls. (PR #84005)

2024-03-06 Thread Clement Courbet via cfe-commits

legrosbuffle wrote:

> LGTM, verify if some release notes shouldn't be updated.

This is very minor, I've only seen a few instances in the Google codebase, but 
it was trivial enough to include.

https://github.com/llvm/llvm-project/pull/84005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] Add support for determining constness of more expressions. (PR #82617)

2024-02-26 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/82617

>From b2b98e9594b224f471f88924b8b060bee06de483 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Wed, 21 Feb 2024 09:15:22 +
Subject: [PATCH] [clang-tidy] Add support for determining constness of more
 expressions.

This uses a more systematic approach for determining whcich `DeclRefExpr`s 
mutate
the underlying object: Instead of using a few matchers, we walk up the
AST until we find a parent that we can prove cannot change the
underlying object.

This allows us to handle most address taking and dereference, bindings
to value and const& variables, and track constness of pointee
(see changes in DeclRefExprUtilsTest.cpp).

This allows supporting more patterns in 
`performance-unnecessary-copy-initialization`.

Those two patterns are relatively common:

```
const auto e = (*vector_ptr)[i]
```

and

```
const auto e = vector_ptr->at(i);
```

In our codebase, we have around 25% additional findings from
`performance-unnecessary-copy-initialization` with this change.
I did not see any additional false positives.
---
 .../UnnecessaryCopyInitialization.cpp |  27 +-
 .../clang-tidy/utils/DeclRefExprUtils.cpp | 212 +++---
 .../clang-tidy/utils/DeclRefExprUtils.h   |  33 ++-
 clang-tools-extra/docs/ReleaseNotes.rst   |   6 +
 .../unnecessary-copy-initialization.cpp   |  27 +-
 .../clang-tidy/DeclRefExprUtilsTest.cpp   | 274 +++---
 6 files changed, 396 insertions(+), 183 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index dfe12c5b6007da..9beb185cba929d 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -86,16 +86,22 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, 
isConstRefReturningMethodCall,
   const auto MethodDecl =
   cxxMethodDecl(returns(hasCanonicalType(matchers::isReferenceToConst(
   .bind(MethodDeclId);
-  const auto ReceiverExpr = declRefExpr(to(varDecl().bind(ObjectArgId)));
+  const auto ReceiverExpr =
+  ignoringParenImpCasts(declRefExpr(to(varDecl().bind(ObjectArgId;
+  const auto OnExpr = anyOf(
+  // Direct reference to `*this`: `a.f()` or `a->f()`.
+  ReceiverExpr,
+  // Access through dereference, typically used for `operator[]`: 
`(*a)[3]`.
+  unaryOperator(hasOperatorName("*"), hasUnaryOperand(ReceiverExpr)));
   const auto ReceiverType =
   hasCanonicalType(recordType(hasDeclaration(namedDecl(
   unless(matchers::matchesAnyListedName(ExcludedContainerTypes));
 
-  return expr(anyOf(
-  cxxMemberCallExpr(callee(MethodDecl), on(ReceiverExpr),
-thisPointerType(ReceiverType)),
-  cxxOperatorCallExpr(callee(MethodDecl), hasArgument(0, ReceiverExpr),
-  hasArgument(0, hasType(ReceiverType);
+  return expr(
+  anyOf(cxxMemberCallExpr(callee(MethodDecl), on(OnExpr),
+  thisPointerType(ReceiverType)),
+cxxOperatorCallExpr(callee(MethodDecl), hasArgument(0, OnExpr),
+hasArgument(0, hasType(ReceiverType);
 }
 
 AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) {
@@ -136,10 +142,11 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, 
initializerReturnsReferenceToConst,
 static bool isInitializingVariableImmutable(
 const VarDecl &InitializingVar, const Stmt &BlockStmt, ASTContext &Context,
 const std::vector &ExcludedContainerTypes) {
-  if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context))
+  QualType T = InitializingVar.getType().getCanonicalType();
+  if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context,
+ T->isPointerType() ? 1 : 0))
 return false;
 
-  QualType T = InitializingVar.getType().getCanonicalType();
   // The variable is a value type and we know it is only used as const. Safe
   // to reference it and avoid the copy.
   if (!isa(T))
@@ -273,7 +280,9 @@ void UnnecessaryCopyInitialization::check(
   VarDeclStmt.isSingleDecl() && !NewVar.getLocation().isMacroID();
   const bool IsVarUnused = isVariableUnused(NewVar, BlockStmt, 
*Result.Context);
   const bool IsVarOnlyUsedAsConst =
-  isOnlyUsedAsConst(NewVar, BlockStmt, *Result.Context);
+  isOnlyUsedAsConst(NewVar, BlockStmt, *Result.Context,
+// `NewVar` is always of non-pointer type.
+0);
   const CheckContext Context{
   NewVar,   BlockStmt,   VarDeclStmt, *Result.Context,
   IssueFix, IsVarUnused, IsVarOnlyUsedAsConst};
diff --git a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp 
b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
index 2d73179150e8b8..663691c519b8e9 100644
--- a/clang-tools-extra/clan

[clang-tools-extra] [clang-tidy] Add support for determining constness of more expressions. (PR #82617)

2024-02-26 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/82617

>From b2b98e9594b224f471f88924b8b060bee06de483 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Wed, 21 Feb 2024 09:15:22 +
Subject: [PATCH 1/2] [clang-tidy] Add support for determining constness of
 more expressions.

This uses a more systematic approach for determining whcich `DeclRefExpr`s 
mutate
the underlying object: Instead of using a few matchers, we walk up the
AST until we find a parent that we can prove cannot change the
underlying object.

This allows us to handle most address taking and dereference, bindings
to value and const& variables, and track constness of pointee
(see changes in DeclRefExprUtilsTest.cpp).

This allows supporting more patterns in 
`performance-unnecessary-copy-initialization`.

Those two patterns are relatively common:

```
const auto e = (*vector_ptr)[i]
```

and

```
const auto e = vector_ptr->at(i);
```

In our codebase, we have around 25% additional findings from
`performance-unnecessary-copy-initialization` with this change.
I did not see any additional false positives.
---
 .../UnnecessaryCopyInitialization.cpp |  27 +-
 .../clang-tidy/utils/DeclRefExprUtils.cpp | 212 +++---
 .../clang-tidy/utils/DeclRefExprUtils.h   |  33 ++-
 clang-tools-extra/docs/ReleaseNotes.rst   |   6 +
 .../unnecessary-copy-initialization.cpp   |  27 +-
 .../clang-tidy/DeclRefExprUtilsTest.cpp   | 274 +++---
 6 files changed, 396 insertions(+), 183 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index dfe12c5b6007da..9beb185cba929d 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -86,16 +86,22 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, 
isConstRefReturningMethodCall,
   const auto MethodDecl =
   cxxMethodDecl(returns(hasCanonicalType(matchers::isReferenceToConst(
   .bind(MethodDeclId);
-  const auto ReceiverExpr = declRefExpr(to(varDecl().bind(ObjectArgId)));
+  const auto ReceiverExpr =
+  ignoringParenImpCasts(declRefExpr(to(varDecl().bind(ObjectArgId;
+  const auto OnExpr = anyOf(
+  // Direct reference to `*this`: `a.f()` or `a->f()`.
+  ReceiverExpr,
+  // Access through dereference, typically used for `operator[]`: 
`(*a)[3]`.
+  unaryOperator(hasOperatorName("*"), hasUnaryOperand(ReceiverExpr)));
   const auto ReceiverType =
   hasCanonicalType(recordType(hasDeclaration(namedDecl(
   unless(matchers::matchesAnyListedName(ExcludedContainerTypes));
 
-  return expr(anyOf(
-  cxxMemberCallExpr(callee(MethodDecl), on(ReceiverExpr),
-thisPointerType(ReceiverType)),
-  cxxOperatorCallExpr(callee(MethodDecl), hasArgument(0, ReceiverExpr),
-  hasArgument(0, hasType(ReceiverType);
+  return expr(
+  anyOf(cxxMemberCallExpr(callee(MethodDecl), on(OnExpr),
+  thisPointerType(ReceiverType)),
+cxxOperatorCallExpr(callee(MethodDecl), hasArgument(0, OnExpr),
+hasArgument(0, hasType(ReceiverType);
 }
 
 AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) {
@@ -136,10 +142,11 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, 
initializerReturnsReferenceToConst,
 static bool isInitializingVariableImmutable(
 const VarDecl &InitializingVar, const Stmt &BlockStmt, ASTContext &Context,
 const std::vector &ExcludedContainerTypes) {
-  if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context))
+  QualType T = InitializingVar.getType().getCanonicalType();
+  if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context,
+ T->isPointerType() ? 1 : 0))
 return false;
 
-  QualType T = InitializingVar.getType().getCanonicalType();
   // The variable is a value type and we know it is only used as const. Safe
   // to reference it and avoid the copy.
   if (!isa(T))
@@ -273,7 +280,9 @@ void UnnecessaryCopyInitialization::check(
   VarDeclStmt.isSingleDecl() && !NewVar.getLocation().isMacroID();
   const bool IsVarUnused = isVariableUnused(NewVar, BlockStmt, 
*Result.Context);
   const bool IsVarOnlyUsedAsConst =
-  isOnlyUsedAsConst(NewVar, BlockStmt, *Result.Context);
+  isOnlyUsedAsConst(NewVar, BlockStmt, *Result.Context,
+// `NewVar` is always of non-pointer type.
+0);
   const CheckContext Context{
   NewVar,   BlockStmt,   VarDeclStmt, *Result.Context,
   IssueFix, IsVarUnused, IsVarOnlyUsedAsConst};
diff --git a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp 
b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
index 2d73179150e8b8..663691c519b8e9 100644
--- a/clang-tools-extra/

[clang-tools-extra] [clang-tidy] Add support for determining constness of more expressions. (PR #82617)

2024-02-26 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/82617

>From b2b98e9594b224f471f88924b8b060bee06de483 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Wed, 21 Feb 2024 09:15:22 +
Subject: [PATCH 1/3] [clang-tidy] Add support for determining constness of
 more expressions.

This uses a more systematic approach for determining whcich `DeclRefExpr`s 
mutate
the underlying object: Instead of using a few matchers, we walk up the
AST until we find a parent that we can prove cannot change the
underlying object.

This allows us to handle most address taking and dereference, bindings
to value and const& variables, and track constness of pointee
(see changes in DeclRefExprUtilsTest.cpp).

This allows supporting more patterns in 
`performance-unnecessary-copy-initialization`.

Those two patterns are relatively common:

```
const auto e = (*vector_ptr)[i]
```

and

```
const auto e = vector_ptr->at(i);
```

In our codebase, we have around 25% additional findings from
`performance-unnecessary-copy-initialization` with this change.
I did not see any additional false positives.
---
 .../UnnecessaryCopyInitialization.cpp |  27 +-
 .../clang-tidy/utils/DeclRefExprUtils.cpp | 212 +++---
 .../clang-tidy/utils/DeclRefExprUtils.h   |  33 ++-
 clang-tools-extra/docs/ReleaseNotes.rst   |   6 +
 .../unnecessary-copy-initialization.cpp   |  27 +-
 .../clang-tidy/DeclRefExprUtilsTest.cpp   | 274 +++---
 6 files changed, 396 insertions(+), 183 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index dfe12c5b6007da..9beb185cba929d 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -86,16 +86,22 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, 
isConstRefReturningMethodCall,
   const auto MethodDecl =
   cxxMethodDecl(returns(hasCanonicalType(matchers::isReferenceToConst(
   .bind(MethodDeclId);
-  const auto ReceiverExpr = declRefExpr(to(varDecl().bind(ObjectArgId)));
+  const auto ReceiverExpr =
+  ignoringParenImpCasts(declRefExpr(to(varDecl().bind(ObjectArgId;
+  const auto OnExpr = anyOf(
+  // Direct reference to `*this`: `a.f()` or `a->f()`.
+  ReceiverExpr,
+  // Access through dereference, typically used for `operator[]`: 
`(*a)[3]`.
+  unaryOperator(hasOperatorName("*"), hasUnaryOperand(ReceiverExpr)));
   const auto ReceiverType =
   hasCanonicalType(recordType(hasDeclaration(namedDecl(
   unless(matchers::matchesAnyListedName(ExcludedContainerTypes));
 
-  return expr(anyOf(
-  cxxMemberCallExpr(callee(MethodDecl), on(ReceiverExpr),
-thisPointerType(ReceiverType)),
-  cxxOperatorCallExpr(callee(MethodDecl), hasArgument(0, ReceiverExpr),
-  hasArgument(0, hasType(ReceiverType);
+  return expr(
+  anyOf(cxxMemberCallExpr(callee(MethodDecl), on(OnExpr),
+  thisPointerType(ReceiverType)),
+cxxOperatorCallExpr(callee(MethodDecl), hasArgument(0, OnExpr),
+hasArgument(0, hasType(ReceiverType);
 }
 
 AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) {
@@ -136,10 +142,11 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, 
initializerReturnsReferenceToConst,
 static bool isInitializingVariableImmutable(
 const VarDecl &InitializingVar, const Stmt &BlockStmt, ASTContext &Context,
 const std::vector &ExcludedContainerTypes) {
-  if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context))
+  QualType T = InitializingVar.getType().getCanonicalType();
+  if (!isOnlyUsedAsConst(InitializingVar, BlockStmt, Context,
+ T->isPointerType() ? 1 : 0))
 return false;
 
-  QualType T = InitializingVar.getType().getCanonicalType();
   // The variable is a value type and we know it is only used as const. Safe
   // to reference it and avoid the copy.
   if (!isa(T))
@@ -273,7 +280,9 @@ void UnnecessaryCopyInitialization::check(
   VarDeclStmt.isSingleDecl() && !NewVar.getLocation().isMacroID();
   const bool IsVarUnused = isVariableUnused(NewVar, BlockStmt, 
*Result.Context);
   const bool IsVarOnlyUsedAsConst =
-  isOnlyUsedAsConst(NewVar, BlockStmt, *Result.Context);
+  isOnlyUsedAsConst(NewVar, BlockStmt, *Result.Context,
+// `NewVar` is always of non-pointer type.
+0);
   const CheckContext Context{
   NewVar,   BlockStmt,   VarDeclStmt, *Result.Context,
   IssueFix, IsVarUnused, IsVarOnlyUsedAsConst};
diff --git a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp 
b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
index 2d73179150e8b8..663691c519b8e9 100644
--- a/clang-tools-extra/

[clang-tools-extra] [llvm] [clang-tidy] Add support for determining constness of more expressions. (PR #82617)

2024-02-26 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/82617

>From 9b93c8bf0614e64352de8e210adf6ff316c0133e Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Mon, 19 Feb 2024 14:58:27 +
Subject: [PATCH 1/5] [llvm-exegesis][NFC] Refactor all `ValidationEvent` info
 in a single table.

All data is derived from a single table rather than being spread out
over an enum, a table and the main entry point.
---
 llvm/include/llvm/Target/TargetPfmCounters.td |  1 +
 .../llvm-exegesis/lib/BenchmarkResult.cpp | 49 +--
 .../tools/llvm-exegesis/lib/BenchmarkResult.h | 15 +
 llvm/tools/llvm-exegesis/lib/CMakeLists.txt   |  1 +
 .../lib/LatencyBenchmarkRunner.cpp|  4 +-
 llvm/tools/llvm-exegesis/lib/Target.h |  1 +
 .../llvm-exegesis/lib/ValidationEvent.cpp | 53 
 .../tools/llvm-exegesis/lib/ValidationEvent.h | 60 +++
 llvm/tools/llvm-exegesis/llvm-exegesis.cpp| 20 +--
 9 files changed, 124 insertions(+), 80 deletions(-)
 create mode 100644 llvm/tools/llvm-exegesis/lib/ValidationEvent.cpp
 create mode 100644 llvm/tools/llvm-exegesis/lib/ValidationEvent.h

diff --git a/llvm/include/llvm/Target/TargetPfmCounters.td 
b/llvm/include/llvm/Target/TargetPfmCounters.td
index 8c4d5f50c63a24..cfe432a992b71f 100644
--- a/llvm/include/llvm/Target/TargetPfmCounters.td
+++ b/llvm/include/llvm/Target/TargetPfmCounters.td
@@ -35,6 +35,7 @@ class ValidationEvent  {
   int EventNumber = event_number;
 }
 
+// TableGen names for events defined in `llvm::exegesis::ValidationEvent`.
 def InstructionRetired  : ValidationEvent<0>;
 def L1DCacheLoadMiss : ValidationEvent<1>;
 def L1DCacheStoreMiss : ValidationEvent<2>;
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp 
b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
index 189add6464173f..f84ebd2a4e68ef 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
@@ -9,6 +9,7 @@
 #include "BenchmarkResult.h"
 #include "BenchmarkRunner.h"
 #include "Error.h"
+#include "ValidationEvent.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/StringRef.h"
@@ -198,7 +199,7 @@ struct 
CustomMappingTraits> {
   static void inputOne(IO &Io, StringRef KeyStr,
std::map &VI) {
 Expected Key =
-exegesis::stringToValidationEvent(KeyStr);
+exegesis::getValidationEventByName(KeyStr);
 if (!Key) {
   Io.setError("Key is not a valid validation event");
   return;
@@ -208,7 +209,7 @@ struct 
CustomMappingTraits> {
 
   static void output(IO &Io, std::map &VI) 
{
 for (auto &IndividualVI : VI) {
-  Io.mapRequired(exegesis::validationEventToString(IndividualVI.first),
+  Io.mapRequired(exegesis::getValidationEventName(IndividualVI.first),
  IndividualVI.second);
 }
   }
@@ -441,49 +442,5 @@ bool operator==(const BenchmarkMeasure &A, const 
BenchmarkMeasure &B) {
  std::tie(B.Key, B.PerInstructionValue, B.PerSnippetValue);
 }
 
-const char *validationEventToString(ValidationEvent VE) {
-  switch (VE) {
-  case exegesis::ValidationEvent::InstructionRetired:
-return "instructions-retired";
-  case exegesis::ValidationEvent::L1DCacheLoadMiss:
-return "l1d-cache-load-misses";
-  case exegesis::ValidationEvent::L1DCacheStoreMiss:
-return "l1d-cache-store-misses";
-  case exegesis::ValidationEvent::L1ICacheLoadMiss:
-return "l1i-cache-load-misses";
-  case exegesis::ValidationEvent::DataTLBLoadMiss:
-return "data-tlb-load-misses";
-  case exegesis::ValidationEvent::DataTLBStoreMiss:
-return "data-tlb-store-misses";
-  case exegesis::ValidationEvent::InstructionTLBLoadMiss:
-return "instruction-tlb-load-misses";
-  case exegesis::ValidationEvent::BranchPredictionMiss:
-return "branch-prediction-misses";
-  }
-  llvm_unreachable("Unhandled exegesis::ValidationEvent enum");
-}
-
-Expected stringToValidationEvent(StringRef Input) {
-  if (Input == "instructions-retired")
-return exegesis::ValidationEvent::InstructionRetired;
-  else if (Input == "l1d-cache-load-misses")
-return exegesis::ValidationEvent::L1DCacheLoadMiss;
-  else if (Input == "l1d-cache-store-misses")
-return exegesis::ValidationEvent::L1DCacheStoreMiss;
-  else if (Input == "l1i-cache-load-misses")
-return exegesis::ValidationEvent::L1ICacheLoadMiss;
-  else if (Input == "data-tlb-load-misses")
-return exegesis::ValidationEvent::DataTLBLoadMiss;
-  else if (Input == "data-tlb-store-misses")
-return exegesis::ValidationEvent::DataTLBStoreMiss;
-  else if (Input == "instruction-tlb-load-misses")
-return exegesis::ValidationEvent::InstructionTLBLoadMiss;
-  else if (Input == "branch-prediction-misses")
-return exegesis::ValidationEvent::BranchPredictionMiss;
-  else
-return make_error("Invalid validation event string",
-   errc::invalid_argumen

[clang-tools-extra] [llvm] [clang-tidy] Add support for determining constness of more expressions. (PR #82617)

2024-02-26 Thread Clement Courbet via cfe-commits

legrosbuffle wrote:

Thanks all. Comments addressed.

> Overall looking fine, but this check need to be run on bigger code-base to 
> verify if there are no false positives or crashes.

Sorry, this was not very clear. By "our codebase" I meant the whole of Google 
code :) This also ran on numerous third party repos.



https://github.com/llvm/llvm-project/pull/82617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [llvm] [clang-tidy] Add support for determining constness of more expressions. (PR #82617)

2024-02-26 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle closed 
https://github.com/llvm/llvm-project/pull/82617
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [clang-tools-extra] [libc] [llvm-exegesis] Add middle half repetition mode (PR #77020)

2024-01-30 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle approved this pull request.


https://github.com/llvm/llvm-project/pull/77020
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang] [llvm] [llvm-exegesis] Replace --num-repetitions with --min-instructions (PR #77153)

2024-02-01 Thread Clement Courbet via cfe-commits

legrosbuffle wrote:

> I'm assuming at some point we'll want to deprecate this old option?

It's a single line of code so it probably can stay there for backwards 
compatibility :)

https://github.com/llvm/llvm-project/pull/77153
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang] [llvm] [llvm-exegesis] Replace --num-repetitions with --min-instructions (PR #77153)

2024-02-01 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle approved this pull request.


https://github.com/llvm/llvm-project/pull/77153
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang] [clang-tidy] Handle C++ structured bindings in `performance-for-range-copy` (PR #77105)

2024-01-16 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle closed 
https://github.com/llvm/llvm-project/pull/77105
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[compiler-rt] [libc] [llvm] [clang-tools-extra] [clang] [libc] `FPRep` builders return `FPRep` instead of raw `StorageType` (PR #78588)

2024-01-22 Thread Clement Courbet via cfe-commits


@@ -535,92 +472,178 @@ struct FPRep : public 
FPRepBase {
 // - Quiet Not a Number
 // - Unnormal
 // This can be reduced to the following logic:
-if (exp_bits() == encode(BiasedExponent::BITS_ALL_ONES()))
+if (exp_bits() == encode(BiasedExp::BITS_ALL_ONES()))
   return !is_inf();
-if (exp_bits() != encode(BiasedExponent::BITS_ALL_ZEROES()))
-  return (sig_bits() & encode(Significand::MSB())) == 0;
+if (exp_bits() != encode(BiasedExp::BITS_ALL_ZEROES()))
+  return (sig_bits() & encode(Sig::MSB())) == 0;
 return false;
   }
   LIBC_INLINE constexpr bool is_quiet_nan() const {
 return exp_sig_bits() >=
-   encode(BiasedExponent::BITS_ALL_ONES(),
-  Significand::MSB() | (Significand::MSB() >> 1));
+   encode(BiasedExp::BITS_ALL_ONES(), Sig::MSB() | (Sig::MSB() >> 1));
   }
   LIBC_INLINE constexpr bool is_signaling_nan() const {
 return is_nan() && !is_quiet_nan();
   }
   LIBC_INLINE constexpr bool is_inf() const {
-return exp_sig_bits() ==
-   encode(BiasedExponent::BITS_ALL_ONES(), Significand::MSB());
-  }
-  LIBC_INLINE constexpr bool is_zero() const {
-return exp_sig_bits() ==
-   encode(BiasedExponent::BITS_ALL_ZEROES(), Significand::ZERO());
+return exp_sig_bits() == encode(BiasedExp::BITS_ALL_ONES(), Sig::MSB());
   }
   LIBC_INLINE constexpr bool is_finite() const {
 return !is_inf() && !is_nan();
   }
   LIBC_INLINE
   constexpr bool is_subnormal() const {
-return exp_sig_bits() >
-   encode(BiasedExponent::BITS_ALL_ZEROES(), Significand::ZERO());
+return exp_bits() == encode(BiasedExp::BITS_ALL_ZEROES());
   }
   LIBC_INLINE constexpr bool is_normal() const {
 const auto exp = exp_bits();
-if (exp == encode(BiasedExponent::BITS_ALL_ZEROES()) ||
-exp == encode(BiasedExponent::BITS_ALL_ONES()))
+if (exp == encode(BiasedExp::BITS_ALL_ZEROES()) ||
+exp == encode(BiasedExp::BITS_ALL_ONES()))
   return false;
 return get_implicit_bit();
   }
+  LIBC_INLINE constexpr StorageType get_explicit_mantissa() const {
+return sig_bits();
+  }
 
-  LIBC_INLINE static constexpr FPRep zero(Sign sign = Sign::POS) {
-return encode(sign, BiasedExponent::BITS_ALL_ZEROES(), 
Significand::ZERO());
+  // This functions is specific to FPRepSem.
+  // TODO: Remove if possible.
+  LIBC_INLINE constexpr bool get_implicit_bit() const {
+return static_cast(bits & EXPLICIT_BIT_MASK);
   }
-  LIBC_INLINE static constexpr FPRep one(Sign sign = Sign::POS) {
-return encode(sign, Exponent::ZERO(), Significand::MSB());
+
+  // This functions is specific to FPRepSem.
+  // TODO: Remove if possible.
+  LIBC_INLINE constexpr void set_implicit_bit(bool implicitVal) {
+if (get_implicit_bit() != implicitVal)
+  bits ^= EXPLICIT_BIT_MASK;
   }
-  LIBC_INLINE static constexpr FPRep min_subnormal(Sign sign = Sign::POS) {
-return encode(sign, BiasedExponent::BITS_ALL_ZEROES(), Significand::LSB());
+};
+
+// 'FPRep' is the bottom of the class hierarchy that only deals with 'FPType'.
+// The operations dealing with specific float semantics are implemented by
+// 'FPRepSem' above and specialized when needed.
+//
+// 'RetT' is the return type used by the builders. If not specified it defaults
+// to the 'StorageType' but 'FPBits' class below defaults it to itself so

legrosbuffle wrote:

Yes, much clearer.

https://github.com/llvm/llvm-project/pull/78588
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[compiler-rt] [libc] [llvm] [clang-tools-extra] [clang] [libc] `FPRep` builders return `FPRep` instead of raw `StorageType` (PR #78588)

2024-01-22 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle approved this pull request.


https://github.com/llvm/llvm-project/pull/78588
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Reapply "[clang analysis][thread-safety] Handle return-by-reference..… (PR #68572)

2023-10-18 Thread Clement Courbet via cfe-commits


@@ -2278,7 +2303,7 @@ void 
ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
   PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
 
   CFGBlockInfo &Initial = BlockInfo[CFGraph->getEntry().getBlockID()];
-  CFGBlockInfo &Final   = BlockInfo[CFGraph->getExit().getBlockID()];
+  CFGBlockInfo &Final = BlockInfo[CFGraph->getExit().getBlockID()];

legrosbuffle wrote:

Done.

https://github.com/llvm/llvm-project/pull/68572
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Reapply "[clang analysis][thread-safety] Handle return-by-reference..… (PR #68572)

2023-10-18 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/68572

>From f3b0c9708bbf6fb0962fb82b605a7fc0b52d4a5b Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Mon, 9 Oct 2023 10:20:12 +0200
Subject: [PATCH] =?UTF-8?q?Reapply=20"[clang=20analysis][thread-safety]=20?=
 =?UTF-8?q?Handle=20return-by-reference..=E2=80=A6=20(#68394)"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The new warnings are now under a separate flag 
`-Wthread-safety-reference-return`, which is on by default under 
`-Wthread-safety-reference`.

 - People can opt out via `-Wthread-safety-reference 
-Wnothread-safety-reference-return`.

This reverts commit 859f2d032386632562521a99db20923217d98988.
---
 .../clang/Analysis/Analyses/ThreadSafety.h|  8 +-
 clang/include/clang/Basic/DiagnosticGroups.td |  4 +-
 .../clang/Basic/DiagnosticSemaKinds.td| 10 ++-
 clang/lib/Analysis/ThreadSafety.cpp   | 78 --
 clang/lib/Sema/AnalysisBasedWarnings.cpp  | 12 +++
 .../SemaCXX/warn-thread-safety-analysis.cpp   | 79 +++
 6 files changed, 163 insertions(+), 28 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/ThreadSafety.h 
b/clang/include/clang/Analysis/Analyses/ThreadSafety.h
index 1808d1d71e05d2c..0866b09bab2995e 100644
--- a/clang/include/clang/Analysis/Analyses/ThreadSafety.h
+++ b/clang/include/clang/Analysis/Analyses/ThreadSafety.h
@@ -47,7 +47,13 @@ enum ProtectedOperationKind {
   POK_PassByRef,
 
   /// Passing a pt-guarded variable by reference.
-  POK_PtPassByRef
+  POK_PtPassByRef,
+
+  /// Returning a guarded variable by reference.
+  POK_ReturnByRef,
+
+  /// Returning a pt-guarded variable by reference.
+  POK_PtReturnByRef,
 };
 
 /// This enum distinguishes between different kinds of lock actions. For
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 674eb9f4ef2e73f..2e4e22e4f90bee8 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1066,7 +1066,9 @@ def Most : DiagGroup<"most", [
 def ThreadSafetyAttributes : DiagGroup<"thread-safety-attributes">;
 def ThreadSafetyAnalysis   : DiagGroup<"thread-safety-analysis">;
 def ThreadSafetyPrecise: DiagGroup<"thread-safety-precise">;
-def ThreadSafetyReference  : DiagGroup<"thread-safety-reference">;
+def ThreadSafetyReferenceReturn  : DiagGroup<"thread-safety-reference-return">;
+def ThreadSafetyReference  : DiagGroup<"thread-safety-reference",
+ [ThreadSafetyReferenceReturn]>;
 def ThreadSafetyNegative   : DiagGroup<"thread-safety-negative">;
 def ThreadSafety : DiagGroup<"thread-safety",
  [ThreadSafetyAttributes,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 7f39f5e79792c07..fb281773fdbf819 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3864,7 +3864,7 @@ def warn_fun_requires_negative_cap : Warning<
   "calling function %0 requires negative capability '%1'">,
   InGroup, DefaultIgnore;
 
-// Thread safety warnings on pass by reference
+// Thread safety warnings on pass/return by reference
 def warn_guarded_pass_by_reference : Warning<
   "passing variable %1 by reference requires holding %0 "
   "%select{'%2'|'%2' exclusively}3">,
@@ -3873,6 +3873,14 @@ def warn_pt_guarded_pass_by_reference : Warning<
   "passing the value that %1 points to by reference requires holding %0 "
   "%select{'%2'|'%2' exclusively}3">,
   InGroup, DefaultIgnore;
+def warn_guarded_return_by_reference : Warning<
+  "returning variable %1 by reference requires holding %0 "
+  "%select{'%2'|'%2' exclusively}3">,
+  InGroup, DefaultIgnore;
+def warn_pt_guarded_return_by_reference : Warning<
+  "returning the value that %1 points to by reference requires holding %0 "
+  "%select{'%2'|'%2' exclusively}3">,
+  InGroup, DefaultIgnore;
 
 // Imprecise thread safety warnings
 def warn_variable_requires_lock : Warning<
diff --git a/clang/lib/Analysis/ThreadSafety.cpp 
b/clang/lib/Analysis/ThreadSafety.cpp
index 58dd7113665b132..7fdf22c2f3919cb 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -1008,7 +1008,7 @@ class ThreadSafetyAnalyzer {
   threadSafety::SExprBuilder SxBuilder;
 
   ThreadSafetyHandler &Handler;
-  const CXXMethodDecl *CurrentMethod = nullptr;
+  const FunctionDecl *CurrentFunction;
   LocalVariableMap LocalVarMap;
   FactManager FactMan;
   std::vector BlockInfo;
@@ -1243,10 +1243,10 @@ bool ThreadSafetyAnalyzer::inCurrentScope(const 
CapabilityExpr &CapE) {
 
   // Members are in scope from methods of the same class.
   if (const auto *P = dyn_cast(SExp)) {
-if (!CurrentMethod)
+if (!isa_and_nonnull(CurrentFunction))
   return false;
 const ValueDecl *V

[clang] Reapply "[clang analysis][thread-safety] Handle return-by-reference..… (PR #68572)

2023-10-18 Thread Clement Courbet via cfe-commits


@@ -1061,11 +1061,13 @@ def Most : DiagGroup<"most", [
  ]>;
 
 // Thread Safety warnings
-def ThreadSafetyAttributes : DiagGroup<"thread-safety-attributes">;
-def ThreadSafetyAnalysis   : DiagGroup<"thread-safety-analysis">;
-def ThreadSafetyPrecise: DiagGroup<"thread-safety-precise">;
-def ThreadSafetyReference  : DiagGroup<"thread-safety-reference">;
-def ThreadSafetyNegative   : DiagGroup<"thread-safety-negative">;
+def ThreadSafetyAttributes   : DiagGroup<"thread-safety-attributes">;
+def ThreadSafetyAnalysis : DiagGroup<"thread-safety-analysis">;
+def ThreadSafetyPrecise  : DiagGroup<"thread-safety-precise">;

legrosbuffle wrote:

Done.

https://github.com/llvm/llvm-project/pull/68572
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Reapply "[clang analysis][thread-safety] Handle return-by-reference..… (PR #68572)

2023-10-18 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle closed 
https://github.com/llvm/llvm-project/pull/68572
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] fc1b24d - [clang-tidy]performance-unnecessary-copy-initialization: fix false negative

2021-10-28 Thread Clement Courbet via cfe-commits

Author: Clement Courbet
Date: 2021-10-29T08:41:03+02:00
New Revision: fc1b24d7360f59c8b89f1b6290fe849a6207dc44

URL: 
https://github.com/llvm/llvm-project/commit/fc1b24d7360f59c8b89f1b6290fe849a6207dc44
DIFF: 
https://github.com/llvm/llvm-project/commit/fc1b24d7360f59c8b89f1b6290fe849a6207dc44.diff

LOG: [clang-tidy]performance-unnecessary-copy-initialization: fix false negative

We're missing all cases where the return value is a type alias.

Unfortunately, this includes things we care about, such as
`std::vector::operator[]` (return value is `const_reference`,
not `const T&`).

Match the canonical type instead.

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

Added: 


Modified: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp

clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Removed: 




diff  --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 6f9495fd1e66c..2cdd7827ee42a 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -84,7 +84,8 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, 
isConstRefReturningMethodCall,
   // returned either points to a global static variable or to a member of the
   // called object.
   return cxxMemberCallExpr(
-  callee(cxxMethodDecl(returns(matchers::isReferenceToConst()))
+  callee(cxxMethodDecl(
+ returns(hasCanonicalType(matchers::isReferenceToConst(
  .bind(MethodDeclId)),
   on(declRefExpr(to(
   varDecl(
@@ -97,7 +98,8 @@ AST_MATCHER_FUNCTION(StatementMatcher, 
isConstRefReturningFunctionCall) {
   // Only allow initialization of a const reference from a free function if it
   // has no arguments. Otherwise it could return an alias to one of its
   // arguments and the arguments need to be checked for const use as well.
-  return callExpr(callee(functionDecl(returns(matchers::isReferenceToConst()))
+  return callExpr(callee(functionDecl(returns(hasCanonicalType(
+  matchers::isReferenceToConst(
  .bind(FunctionDeclId)),
   argumentCountIs(0), unless(callee(cxxMethodDecl(
   .bind(InitFunctionCallId);

diff  --git 
a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
index 68a010c4d953c..4c469c966860b 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -12,6 +12,8 @@ struct ExpensiveToCopyType {
   ExpensiveToCopyType();
   virtual ~ExpensiveToCopyType();
   const ExpensiveToCopyType &reference() const;
+  using ConstRef = const ExpensiveToCopyType &;
+  ConstRef referenceWithAlias() const;
   const ExpensiveToCopyType *pointer() const;
   Iterator begin() const;
   Iterator end() const;
@@ -206,6 +208,15 @@ void positiveNonConstVarInCodeBlock(const 
ExpensiveToCopyType &Obj) {
   }
 }
 
+void positiveNonConstVarInCodeBlockWithAlias(const ExpensiveToCopyType &Obj) {
+  {
+const ExpensiveToCopyType Assigned = Obj.referenceWithAlias();
+// CHECK-MESSAGES: [[@LINE-1]]:31: warning: the const qualified variable
+// CHECK-FIXES: const ExpensiveToCopyType& Assigned = 
Obj.referenceWithAlias();
+useAsConstReference(Assigned);
+  }
+}
+
 void negativeNonConstVarWithNonConstUse(const ExpensiveToCopyType &Obj) {
   {
 auto NonConstInvoked = Obj.reference();



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


[clang] 1427742 - [Sema][NFC] Improve test coverage for builtin operators.

2021-11-03 Thread Clement Courbet via cfe-commits

Author: Clement Courbet
Date: 2021-11-03T13:32:48+01:00
New Revision: 1427742750ed1fcd2ead639c4ec5178fc34c9257

URL: 
https://github.com/llvm/llvm-project/commit/1427742750ed1fcd2ead639c4ec5178fc34c9257
DIFF: 
https://github.com/llvm/llvm-project/commit/1427742750ed1fcd2ead639c4ec5178fc34c9257.diff

LOG: [Sema][NFC] Improve test coverage for builtin operators.

In preparation for D112453.

Added: 
clang/test/CXX/over/over.built/p10.cpp
clang/test/CXX/over/over.built/p11.cpp
clang/test/CXX/over/over.built/p24.cpp
clang/test/CXX/over/over.built/p4.cpp
clang/test/CXX/over/over.built/p5.cpp
clang/test/CXX/over/over.built/p6.cpp
clang/test/CXX/over/over.built/p7-ast.cpp
clang/test/CXX/over/over.built/p7.cpp
clang/test/CXX/over/over.built/p8.cpp
clang/test/CXX/over/over.built/p9.cpp

Modified: 


Removed: 




diff  --git a/clang/test/CXX/over/over.built/p10.cpp 
b/clang/test/CXX/over/over.built/p10.cpp
new file mode 100644
index 0..678056da58205
--- /dev/null
+++ b/clang/test/CXX/over/over.built/p10.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare
+
+struct A{};
+
+template 
+void f(int i, float f, bool b, char c, int* pi, A* pa, T* pt) {
+  (void)+i;
+  (void)-i;
+  (void)+f;
+  (void)-f;
+  (void)+b;
+  (void)-b;
+  (void)+c;
+  (void)-c;
+
+  (void)-pi; // expected-error {{invalid argument type}}
+  (void)-pa; // expected-error {{invalid argument type}}
+  (void)-pt; // FIXME: we should be able to give an error here.
+}
+

diff  --git a/clang/test/CXX/over/over.built/p11.cpp 
b/clang/test/CXX/over/over.built/p11.cpp
new file mode 100644
index 0..7ebf16b95439f
--- /dev/null
+++ b/clang/test/CXX/over/over.built/p11.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare
+
+template 
+void f(int i, float f, bool b, char c, int* pi, T* pt) {
+  (void)~i;
+  (void)~f; // expected-error {{invalid argument type}}
+  (void)~b;
+  (void)~c;
+  (void)~pi; // expected-error {{invalid argument type}}
+  (void)~pt; // FIXME: we should be able to give an error here.
+}
+

diff  --git a/clang/test/CXX/over/over.built/p24.cpp 
b/clang/test/CXX/over/over.built/p24.cpp
new file mode 100644
index 0..3c48dcd9aa673
--- /dev/null
+++ b/clang/test/CXX/over/over.built/p24.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare
+
+template 
+void f(int i, float f, bool b, char c, int* pi, T* pt) {
+  (void)!i;
+  (void)!f;
+  (void)!b;
+  (void)!c;
+  (void)!pi;
+  (void)!pt;
+}
+// expected-no-diagnostics

diff  --git a/clang/test/CXX/over/over.built/p4.cpp 
b/clang/test/CXX/over/over.built/p4.cpp
new file mode 100644
index 0..d7cd99c68d6a2
--- /dev/null
+++ b/clang/test/CXX/over/over.built/p4.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++17 -verify %s -Wno-tautological-compare
+
+void f(int i, bool b) {
+  (void)++i;
+  (void)i++;
+
+  (void)++b; // expected-error {{ISO C++17 does not allow incrementing 
expression of type bool}}
+  (void)b++; // expected-error {{ISO C++17 does not allow incrementing 
expression of type bool}}
+}
+

diff  --git a/clang/test/CXX/over/over.built/p5.cpp 
b/clang/test/CXX/over/over.built/p5.cpp
new file mode 100644
index 0..4ba32564e9ad8
--- /dev/null
+++ b/clang/test/CXX/over/over.built/p5.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare
+
+void f(int i, bool b) {
+  (void)--i;
+  (void)i--;
+
+  (void)--b; // expected-error {{cannot decrement expression of type bool}}
+  (void)b--; // expected-error {{cannot decrement expression of type bool}}
+}
+

diff  --git a/clang/test/CXX/over/over.built/p6.cpp 
b/clang/test/CXX/over/over.built/p6.cpp
new file mode 100644
index 0..ca81c9aecce86
--- /dev/null
+++ b/clang/test/CXX/over/over.built/p6.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare
+
+struct A{};
+
+template 
+void f(int* pi, A* pa, T* pt) {
+  (void)++pi;
+  (void)pi++;
+  (void)--pi;
+  (void)pi--;
+
+  (void)++pa;
+  (void)pa++;
+  (void)--pa;
+  (void)pa--;
+
+  (void)++pt;
+  (void)pt++;
+  (void)--pt;
+  (void)pt--;
+}
+// expected-no-diagnostics
+

diff  --git a/clang/test/CXX/over/over.built/p7-ast.cpp 
b/clang/test/CXX/over/over.built/p7-ast.cpp
new file mode 100644
index 0..9f501a496fea8
--- /dev/null
+++ b/clang/test/CXX/over/over.built/p7-ast.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++17 -ast-dump %s -ast-dump-filter Test | FileCheck %s
+
+struct A{};
+
+template 
+auto Test(T* pt) {
+  // CHECK: UnaryOperator {{.*}} '' prefix '*'
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
+  return *pt;
+}
+
+

diff  --git a/clang/test/CXX/over/over.built/p7.cpp 
b/clang/test/CXX/over/over.built/p7.cpp
new file mode 100644
index 0..348c4cdf37830
--- /dev/n

[clang] 45b84a5 - [Sema][NFC] Improve test coverage for builtin binary operators.

2021-11-03 Thread Clement Courbet via cfe-commits

Author: Clement Courbet
Date: 2021-11-03T15:51:35+01:00
New Revision: 45b84a547efe8991b28883c73efa2de798dc2c30

URL: 
https://github.com/llvm/llvm-project/commit/45b84a547efe8991b28883c73efa2de798dc2c30
DIFF: 
https://github.com/llvm/llvm-project/commit/45b84a547efe8991b28883c73efa2de798dc2c30.diff

LOG: [Sema][NFC] Improve test coverage for builtin binary operators.

In preparation for D112453.

Added: 
clang/test/CXX/over/over.built/p13.cpp
clang/test/CXX/over/over.built/p14.cpp

Modified: 
clang/test/CXX/over/over.built/p7-ast.cpp

Removed: 




diff  --git a/clang/test/CXX/over/over.built/p13.cpp 
b/clang/test/CXX/over/over.built/p13.cpp
new file mode 100644
index ..de57130386e8
--- /dev/null
+++ b/clang/test/CXX/over/over.built/p13.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare
+
+template 
+void f(int i, float f, bool b, char c, int* pi, T* pt) {
+  (void)(i*i);
+  (void)(i*f);
+  (void)(i*b);
+  (void)(i*c);
+  (void)(i*pi); // expected-error {{invalid operands to binary expression}}
+  (void)(i*pt); // FIXME
+
+  (void)(i/i);
+  (void)(i/f);
+  (void)(i/b);
+  (void)(i/c);
+  (void)(i/pi); // expected-error {{invalid operands to binary expression}}
+  (void)(i/pt); // FIXME
+
+  (void)(i-i);
+  (void)(i-f);
+  (void)(i-b);
+  (void)(i-c);
+  (void)(i-pi); // expected-error {{invalid operands to binary expression}}
+  (void)(i-pt); // FIXME
+
+  (void)(i
+void f(int* pi, T* pt) {
+  (void)(pi+3);
+  (void)(3+pi);
+  (void)(pi-3);
+  (void)(pi[3]);
+  (void)(3[pi]);
+
+  (void)(pt+3);
+  (void)(3+pt);
+  (void)(pt-3);
+  (void)(pt[3]);
+  (void)(3[pt]);
+}
+// expected-no-diagnostics

diff  --git a/clang/test/CXX/over/over.built/p7-ast.cpp 
b/clang/test/CXX/over/over.built/p7-ast.cpp
index 9f501a496fea..f3c44cff3951 100644
--- a/clang/test/CXX/over/over.built/p7-ast.cpp
+++ b/clang/test/CXX/over/over.built/p7-ast.cpp
@@ -6,7 +6,25 @@ template 
 auto Test(T* pt) {
   // CHECK: UnaryOperator {{.*}} '' prefix '*'
   // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
-  return *pt;
+  (void)*pt;
+
+  // CHECK: UnaryOperator {{.*}} '' prefix '++'
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
+  (void)(++pt);
+
+  // CHECK: UnaryOperator {{.*}} '' prefix '+'
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
+  (void)(+pt);
+
+  // CHECK: BinaryOperator {{.*}} '' '+'
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
+  // CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
+  (void)(pt + 3);
+
+  // CHECK: BinaryOperator {{.*}} '' '-'
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
+  (void)(pt -pt);
 }
 
 



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


[clang] d3dc7d0 - [Sema][NFC] Improve test coverage of builtin operators.

2021-11-04 Thread Clement Courbet via cfe-commits

Author: Clement Courbet
Date: 2021-11-04T15:43:32+01:00
New Revision: d3dc7d077f1d9c9478813a34ed38abbcb4fc1ef5

URL: 
https://github.com/llvm/llvm-project/commit/d3dc7d077f1d9c9478813a34ed38abbcb4fc1ef5
DIFF: 
https://github.com/llvm/llvm-project/commit/d3dc7d077f1d9c9478813a34ed38abbcb4fc1ef5.diff

LOG: [Sema][NFC] Improve test coverage of builtin operators.

In preparation for D112453.

Fix numbering of tests for [over.built]: 15->16, 16->17.

Added: 
clang/test/CXX/over/over.built/ast.cpp
clang/test/CXX/over/over.built/p17.cpp
clang/test/CXX/over/over.built/p18.cpp
clang/test/CXX/over/over.built/p19.cpp
clang/test/CXX/over/over.built/p20.cpp
clang/test/CXX/over/over.built/p21.cpp
clang/test/CXX/over/over.built/p22.cpp
clang/test/CXX/over/over.built/p26.cpp

Modified: 
clang/test/CXX/over/over.built/p15.cpp
clang/test/CXX/over/over.built/p16.cpp
clang/test/CXX/over/over.built/p23.cpp
clang/test/CXX/over/over.built/p24.cpp
clang/test/CXX/over/over.built/p25.cpp

Removed: 
clang/test/CXX/over/over.built/p7-ast.cpp



diff  --git a/clang/test/CXX/over/over.built/p7-ast.cpp 
b/clang/test/CXX/over/over.built/ast.cpp
similarity index 64%
rename from clang/test/CXX/over/over.built/p7-ast.cpp
rename to clang/test/CXX/over/over.built/ast.cpp
index f3c44cff3951f..f76606b1f9869 100644
--- a/clang/test/CXX/over/over.built/p7-ast.cpp
+++ b/clang/test/CXX/over/over.built/ast.cpp
@@ -2,8 +2,8 @@
 
 struct A{};
 
-template 
-auto Test(T* pt) {
+template 
+auto Test(T* pt, U* pu) {
   // CHECK: UnaryOperator {{.*}} '' prefix '*'
   // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
   (void)*pt;
@@ -24,7 +24,18 @@ auto Test(T* pt) {
   // CHECK: BinaryOperator {{.*}} '' '-'
   // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
   // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
-  (void)(pt -pt);
+  (void)(pt - pt);
+
+  // CHECK: BinaryOperator {{.*}} '' '-'
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *'
+  (void)(pt - pu);
+
+  // CHECK: BinaryOperator {{.*}} '' '=='
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *'
+  (void)(pt == pu);
+
 }
 
 

diff  --git a/clang/test/CXX/over/over.built/p15.cpp 
b/clang/test/CXX/over/over.built/p15.cpp
index 9b223bcbc24d5..680ffa9a3dcb7 100644
--- a/clang/test/CXX/over/over.built/p15.cpp
+++ b/clang/test/CXX/over/over.built/p15.cpp
@@ -1,75 +1,12 @@
 // RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare
 
-struct A { operator decltype(nullptr)(); }; // expected-note 16{{implicitly 
converted}}
-struct B { operator const int *(); }; // expected-note 8{{implicitly 
converted}}
-void f(A a, B b, volatile int *pi) {
-  (void)(a == a);
-  (void)(a != a);
-  (void)(a < a); // expected-error {{invalid operands}}
-  (void)(a > a); // expected-error {{invalid operands}}
-  (void)(a <= a); // expected-error {{invalid operands}}
-  (void)(a >= a); // expected-error {{invalid operands}}
-
-  (void)(a == b);
-  (void)(a != b);
-  (void)(a < b); // expected-error {{invalid operands}}
-  (void)(a > b); // expected-error {{invalid operands}}
-  (void)(a <= b); // expected-error {{invalid operands}}
-  (void)(a >= b); // expected-error {{invalid operands}}
-
-  (void)(b == a);
-  (void)(b != a);
-  (void)(b < a); // expected-error {{invalid operands}}
-  (void)(b > a); // expected-error {{invalid operands}}
-  (void)(b <= a); // expected-error {{invalid operands}}
-  (void)(b >= a); // expected-error {{invalid operands}}
-
-  (void)(a == pi);
-  (void)(a != pi);
-  (void)(a < pi); // expected-error {{invalid operands}}
-  (void)(a > pi); // expected-error {{invalid operands}}
-  (void)(a <= pi); // expected-error {{invalid operands}}
-  (void)(a >= pi); // expected-error {{invalid operands}}
-
-  (void)(pi == a);
-  (void)(pi != a);
-  (void)(pi < a); // expected-error {{invalid operands}}
-  (void)(pi > a); // expected-error {{invalid operands}}
-  (void)(pi <= a); // expected-error {{invalid operands}}
-  (void)(pi >= a); // expected-error {{invalid operands}}
-
-  (void)(b == pi);
-  (void)(b != pi);
-  (void)(b < pi);
-  (void)(b > pi);
-  (void)(b <= pi);
-  (void)(b >= pi);
-
-  (void)(pi == b);
-  (void)(pi != b);
-  (void)(pi < b);
-  (void)(pi > b);
-  (void)(pi <= b);
-  (void)(pi >= b);
-
-  (void)(b == b);
-  (void)(b != b);
-  (void)(b < b);
-  (void)(b > b);
-  (void)(b <= b);
-  (void)(b >= b);
-
-  (void)(pi == pi);
-  (void)(pi != pi);
-  (void)(pi < pi);
-  (void)(pi > pi);
-  (void)(pi <= pi);
-  (void)(pi >= pi);
-}
-
-// FIXME: This is wrong: the type T = 'const volatile int * const * const *'
-// would work here, and there exists a builtin candidate for that t

[clang] 737f540 - [Sema][NFC] Add tests for builtin spaceship operator.

2021-11-05 Thread Clement Courbet via cfe-commits

Author: Clement Courbet
Date: 2021-11-05T11:44:19+01:00
New Revision: 737f540abd578df094f04f690a9b5b52028374b4

URL: 
https://github.com/llvm/llvm-project/commit/737f540abd578df094f04f690a9b5b52028374b4
DIFF: 
https://github.com/llvm/llvm-project/commit/737f540abd578df094f04f690a9b5b52028374b4.diff

LOG: [Sema][NFC] Add tests for builtin spaceship operator.

In preparation for D112453.

Added: 
clang/test/CXX/over/over.built/ast-20.cpp
clang/test/CXX/over/over.built/spaceship.cpp

Modified: 


Removed: 




diff  --git a/clang/test/CXX/over/over.built/ast-20.cpp 
b/clang/test/CXX/over/over.built/ast-20.cpp
new file mode 100644
index 0..4fd1c6edb34f6
--- /dev/null
+++ b/clang/test/CXX/over/over.built/ast-20.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -std=c++20 -ast-dump %s -ast-dump-filter Test | FileCheck %s
+
+namespace std {
+  struct strong_ordering {
+int n;
+constexpr operator int() const { return n; }
+static const strong_ordering less, equal, greater;
+  };
+  constexpr strong_ordering strong_ordering::less{-1},
+  strong_ordering::equal{0}, strong_ordering::greater{1};
+}
+
+template 
+auto Test(T* pt, U* pu) {
+  // CHECK: BinaryOperator {{.*}} '' '<=>'
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
+  // CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *'
+  (void)(pt <=> pu);
+
+}
+
+

diff  --git a/clang/test/CXX/over/over.built/spaceship.cpp 
b/clang/test/CXX/over/over.built/spaceship.cpp
new file mode 100644
index 0..510d601578b5a
--- /dev/null
+++ b/clang/test/CXX/over/over.built/spaceship.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s -Wno-tautological-compare
+
+namespace std {
+  struct strong_ordering {
+int n;
+constexpr operator int() const { return n; }
+static const strong_ordering less, equal, greater;
+  };
+  constexpr strong_ordering strong_ordering::less{-1},
+  strong_ordering::equal{0}, strong_ordering::greater{1};
+}
+
+template 
+void f(int i, int* pi, T* pt, T t) {
+  (void)(i <=> i);
+  (void)(i <=> pi); // expected-error {{comparison between pointer and 
integer}}
+  (void)(i <=> pt);
+  (void)(pi <=> pt);
+  (void)(pi <=> t);
+}
+



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


[clang-tools-extra] ba4411e - [clang-tidy] performance-unnecessary-copy-initialization: Fix false negative.

2021-11-23 Thread Clement Courbet via cfe-commits

Author: Clement Courbet
Date: 2021-11-24T08:07:21+01:00
New Revision: ba4411e7c6a5879ce8acf246b0cd03ec738d9d6b

URL: 
https://github.com/llvm/llvm-project/commit/ba4411e7c6a5879ce8acf246b0cd03ec738d9d6b
DIFF: 
https://github.com/llvm/llvm-project/commit/ba4411e7c6a5879ce8acf246b0cd03ec738d9d6b.diff

LOG: [clang-tidy] performance-unnecessary-copy-initialization: Fix false 
negative.

`isConstRefReturningMethodCall` should be considering
`CXXOperatorCallExpr` in addition to `CXXMemberCallExpr`. Clang considers
these to be distinct (`CXXOperatorCallExpr` derives from `CallExpr`, not
`CXXMemberCallExpr`), but we don't care in the context of this
check.

This is important because of
`std::vector::operator[](size_t) const`.

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

Added: 


Modified: 
clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp

clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp

clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Removed: 




diff  --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
index 514ce6f6e3b87..c1514aed88f70 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -83,13 +83,19 @@ AST_MATCHER_FUNCTION_P(StatementMatcher, 
isConstRefReturningMethodCall,
   // variable being declared. The assumption is that the const reference being
   // returned either points to a global static variable or to a member of the
   // called object.
-  return cxxMemberCallExpr(
-  callee(cxxMethodDecl(
- returns(hasCanonicalType(matchers::isReferenceToConst(
- .bind(MethodDeclId)),
-  on(declRefExpr(to(varDecl().bind(ObjectArgId,
-  thisPointerType(namedDecl(
-  unless(matchers::matchesAnyListedName(ExcludedContainerTypes);
+  const auto MethodDecl =
+  cxxMethodDecl(returns(hasCanonicalType(matchers::isReferenceToConst(
+  .bind(MethodDeclId);
+  const auto ReceiverExpr = declRefExpr(to(varDecl().bind(ObjectArgId)));
+  const auto ReceiverType =
+  hasCanonicalType(recordType(hasDeclaration(namedDecl(
+  unless(matchers::matchesAnyListedName(ExcludedContainerTypes));
+
+  return expr(anyOf(
+  cxxMemberCallExpr(callee(MethodDecl), on(ReceiverExpr),
+thisPointerType(ReceiverType)),
+  cxxOperatorCallExpr(callee(MethodDecl), hasArgument(0, ReceiverExpr),
+  hasArgument(0, hasType(ReceiverType);
 }
 
 AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) {

diff  --git 
a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
index 88b850fe2ff82..96c7ca8a460c2 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp
@@ -21,6 +21,7 @@ struct ExpensiveToCopy {
 
 struct ConstInCorrectType {
   const ExpensiveToCopy &secretlyMutates() const;
+  const ExpensiveToCopy &operator[](int) const;
 };
 
 using NSVTE = ns::ViewType;
@@ -59,12 +60,28 @@ void excludedConstIncorrectType() {
   E.constMethod();
 }
 
+void excludedConstIncorrectTypeOperator() {
+  ConstInCorrectType C;
+  const auto E = C[42];
+  E.constMethod();
+}
+
 void excludedConstIncorrectTypeAsPointer(ConstInCorrectType *C) {
   const auto E = C->secretlyMutates();
   E.constMethod();
 }
 
+void excludedConstIncorrectTypeAsPointerOperator(ConstInCorrectType *C) {
+  const auto E = (*C)[42];
+  E.constMethod();
+}
+
 void excludedConstIncorrectTypeAsReference(const ConstInCorrectType &C) {
   const auto E = C.secretlyMutates();
   E.constMethod();
 }
+
+void excludedConstIncorrectTypeAsReferenceOperator(const ConstInCorrectType 
&C) {
+  const auto E = C[42];
+  E.constMethod();
+}

diff  --git 
a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
index 4c469c966860b..5eac571c2afa7 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
@@ -3,11 +3,19 @@
 template 
 struct Iterator {
   void operator++();
-  const T &operator*() const;
+  T &operator*() const;
   

[clang-tools-extra] 3b72448 - [clang-tidy] Add unit tests for `DeclRefExprUtils`.

2021-11-24 Thread Clement Courbet via cfe-commits

Author: Clement Courbet
Date: 2021-11-24T16:47:55+01:00
New Revision: 3b72448084052785b79566fa5bd374feb8ae3907

URL: 
https://github.com/llvm/llvm-project/commit/3b72448084052785b79566fa5bd374feb8ae3907
DIFF: 
https://github.com/llvm/llvm-project/commit/3b72448084052785b79566fa5bd374feb8ae3907.diff

LOG: [clang-tidy] Add unit tests for `DeclRefExprUtils`.

In preparation for D114539.

Added: 
clang-tools-extra/unittests/clang-tidy/DeclRefExprUtilsTest.cpp

Modified: 
clang-tools-extra/unittests/clang-tidy/CMakeLists.txt

Removed: 




diff  --git a/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt 
b/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
index 4a8d50f01473..6c9fa61cf92e 100644
--- a/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
+++ b/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
@@ -20,6 +20,7 @@ add_extra_unittest(ClangTidyTests
   AddConstTest.cpp
   ClangTidyDiagnosticConsumerTest.cpp
   ClangTidyOptionsTest.cpp
+  DeclRefExprUtilsTest.cpp
   IncludeInserterTest.cpp
   GlobListTest.cpp
   GoogleModuleTest.cpp

diff  --git a/clang-tools-extra/unittests/clang-tidy/DeclRefExprUtilsTest.cpp 
b/clang-tools-extra/unittests/clang-tidy/DeclRefExprUtilsTest.cpp
new file mode 100644
index ..d47add410b2c
--- /dev/null
+++ b/clang-tools-extra/unittests/clang-tidy/DeclRefExprUtilsTest.cpp
@@ -0,0 +1,315 @@
+#include "../clang-tidy/utils/DeclRefExprUtils.h"
+#include "ClangTidyDiagnosticConsumer.h"
+#include "ClangTidyTest.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tidy {
+
+namespace {
+using namespace clang::ast_matchers;
+
+class ConstReferenceDeclRefExprsTransform : public ClangTidyCheck {
+public:
+  ConstReferenceDeclRefExprsTransform(StringRef CheckName,
+  ClangTidyContext *Context)
+  : ClangTidyCheck(CheckName, Context) {}
+
+  void registerMatchers(MatchFinder *Finder) override {
+Finder->addMatcher(varDecl(hasName("target")).bind("var"), this);
+  }
+
+  void check(const MatchFinder::MatchResult &Result) override {
+const auto *D = Result.Nodes.getNodeAs("var");
+using utils::decl_ref_expr::constReferenceDeclRefExprs;
+const auto const_decrefexprs = constReferenceDeclRefExprs(
+*D, *cast(D->getDeclContext())->getBody(),
+*Result.Context);
+
+for (const DeclRefExpr *const Expr : const_decrefexprs) {
+  assert(Expr);
+  diag(Expr->getBeginLoc(), "const usage")
+  << FixItHint::CreateInsertion(Expr->getBeginLoc(), "/*const*/");
+}
+  }
+};
+} // namespace
+
+namespace test {
+
+void RunTest(StringRef Snippet) {
+
+  StringRef CommonCode = R"(
+struct ConstTag{};
+struct NonConstTag{};
+
+struct S {
+  void constMethod() const;
+  void nonConstMethod();
+
+  void operator()(ConstTag) const;
+  void operator()(NonConstTag);
+
+  void operator[](int);
+  void operator[](int) const;
+
+  bool operator==(const S&) const;
+
+  int int_member;
+  int* ptr_member;
+
+};
+
+struct Derived : public S {
+
+};
+
+void useVal(S);
+void useRef(S&);
+void usePtr(S*);
+void usePtrPtr(S**);
+void usePtrConstPtr(S* const*);
+void useConstRef(const S&);
+void useConstPtr(const S*);
+void useConstPtrRef(const S*&);
+void useConstPtrPtr(const S**);
+void useConstPtrConstRef(const S* const&);
+void useConstPtrConstPtr(const S* const*);
+
+void useInt(int);
+void useIntRef(int&);
+void useIntConstRef(const int&);
+void useIntPtr(int*);
+void useIntConstPtr(const int*);
+
+)";
+
+  std::string Code = (CommonCode + Snippet).str();
+
+  llvm::SmallVector Parts;
+  StringRef(Code).split(Parts, "/*const*/");
+
+  EXPECT_EQ(Code, runCheckOnCode(
+  join(Parts, "")));
+}
+
+TEST(ConstReferenceDeclRefExprsTest, ConstValueVar) {
+  RunTest(R"(
+void f(const S target) {
+  useVal(/*const*/target);
+  useConstRef(/*const*/target);
+  useConstPtr(&target);
+  useConstPtrConstRef(&target);
+  /*const*/target.constMethod();
+  /*const*/target(ConstTag{});
+  /*const*/target[42];
+  useConstRef((/*const*/target));
+  (/*const*/target).constMethod();
+  (void)(/*const*/target == /*const*/target);
+  (void)target;
+  (void)⌖
+  (void)*⌖
+  S copy1 = /*const*/target;
+  S copy2(/*const*/target);
+  useInt(target.int_member);
+  useIntConstRef(target.int_member);
+  useIntPtr(target.ptr_member);
+  useIntConstPtr(&target.int_member);
+}
+)");
+}
+
+TEST(ConstReferenceDeclRefExprsTest, ConstRefVar) {
+  RunTest(R"(
+void f(const S& target) {
+  useVal(/*const*/target);
+  useConstRef(/*const*/target);
+  useConstPtr(&target);
+ 

[clang] 156c075 - [clang][transformer] Finish plumbing `Note` all the way to the output.

2022-08-10 Thread Clement Courbet via cfe-commits

Author: Clement Courbet
Date: 2022-08-11T07:54:44+02:00
New Revision: 156c0754bc2ee0b7d198cfeff230374a1961ac04

URL: 
https://github.com/llvm/llvm-project/commit/156c0754bc2ee0b7d198cfeff230374a1961ac04
DIFF: 
https://github.com/llvm/llvm-project/commit/156c0754bc2ee0b7d198cfeff230374a1961ac04.diff

LOG: [clang][transformer] Finish plumbing `Note` all the way to the output.

Right now we can only add a single warning, notes are not possible.

Apparently some provisions were made to allow notes, but they were never
propagated all the way to the diagnostics.

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

Added: 


Modified: 
clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.cpp
clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp
clang/include/clang/Tooling/Transformer/RewriteRule.h
clang/lib/Tooling/Transformer/RewriteRule.cpp

Removed: 




diff  --git a/clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.cpp 
b/clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.cpp
index bd76e67f12c85..136b616836f1e 100644
--- a/clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.cpp
@@ -7,6 +7,7 @@
 
//===--===//
 
 #include "TransformerClangTidyCheck.h"
+#include "clang/Basic/DiagnosticIDs.h"
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/STLExtras.h"
 
@@ -126,18 +127,28 @@ void TransformerClangTidyCheck::check(
   }
 
   // Associate the diagnostic with the location of the first change.
-  DiagnosticBuilder Diag =
-  diag((*Edits)[0].Range.getBegin(), escapeForDiagnostic(*Explanation));
-  for (const auto &T : *Edits)
-switch (T.Kind) {
-case transformer::EditKind::Range:
-  Diag << FixItHint::CreateReplacement(T.Range, T.Replacement);
-  break;
-case transformer::EditKind::AddInclude:
-  Diag << Inserter.createIncludeInsertion(
-  Result.SourceManager->getFileID(T.Range.getBegin()), T.Replacement);
-  break;
+  {
+DiagnosticBuilder Diag =
+diag((*Edits)[0].Range.getBegin(), escapeForDiagnostic(*Explanation));
+for (const auto &T : *Edits) {
+  switch (T.Kind) {
+  case transformer::EditKind::Range:
+Diag << FixItHint::CreateReplacement(T.Range, T.Replacement);
+break;
+  case transformer::EditKind::AddInclude:
+Diag << Inserter.createIncludeInsertion(
+Result.SourceManager->getFileID(T.Range.getBegin()), 
T.Replacement);
+break;
+  }
 }
+  }
+  // Emit potential notes.
+  for (const auto &T : *Edits) {
+if (!T.Note.empty()) {
+  diag(T.Range.getBegin(), escapeForDiagnostic(T.Note),
+   DiagnosticIDs::Note);
+}
+  }
 }
 
 void TransformerClangTidyCheck::storeOptions(

diff  --git 
a/clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp 
b/clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp
index 9106d5a77dd7d..5c5a0943c6cf8 100644
--- a/clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp
+++ b/clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp
@@ -28,6 +28,7 @@ using transformer::IncludeFormat;
 using transformer::makeRule;
 using transformer::node;
 using transformer::noopEdit;
+using transformer::note;
 using transformer::RewriteRuleWith;
 using transformer::RootID;
 using transformer::statement;
@@ -85,6 +86,7 @@ TEST(TransformerClangTidyCheckTest, 
DiagnosticsCorrectlyGenerated) {
   EXPECT_EQ(Errors.size(), 1U);
   EXPECT_EQ(Errors[0].Message.Message, "message");
   EXPECT_THAT(Errors[0].Message.Ranges, testing::IsEmpty());
+  EXPECT_THAT(Errors[0].Notes, testing::IsEmpty());
 
   // The diagnostic is anchored to the match, "return 5".
   EXPECT_EQ(Errors[0].Message.FileOffset, 10U);
@@ -116,6 +118,27 @@ TEST(TransformerClangTidyCheckTest, EmptyReplacement) {
   EXPECT_EQ(Errors[0].Message.FileOffset, 10U);
 }
 
+TEST(TransformerClangTidyCheckTest, NotesCorrectlyGenerated) {
+  class DiagAndNoteCheck : public TransformerClangTidyCheck {
+  public:
+DiagAndNoteCheck(StringRef Name, ClangTidyContext *Context)
+: TransformerClangTidyCheck(
+  makeRule(returnStmt(),
+   note(node(RootID), cat("some note")),
+   cat("message")),
+  Name, Context) {}
+  };
+  std::string Input = "int h() { return 5; }";
+  std::vector Errors;
+  EXPECT_EQ(Input, test::runCheckOnCode(Input, &Errors));
+  EXPECT_EQ(Errors.size(), 1U);
+  EXPECT_EQ(Errors[0].Notes.size(), 1U);
+  EXPECT_EQ(Errors[0].Notes[0].Message, "some note");
+
+  // The note is anchored to the match, "return 5".
+  EXPECT_EQ(Errors[0].Notes[0].FileOffset, 10U);
+}
+
 TEST(TransformerClangTidyCheckTest, DiagnosticMessageEscaped) {
   class GiveDiagWithPerc

[clang] 672311b - [CFG] Fix crash on CFG building when deriving from a template.

2022-08-16 Thread Clement Courbet via cfe-commits

Author: Clement Courbet
Date: 2022-08-16T13:01:13+02:00
New Revision: 672311bd77c594888e2660c124d7eae01822fffa

URL: 
https://github.com/llvm/llvm-project/commit/672311bd77c594888e2660c124d7eae01822fffa
DIFF: 
https://github.com/llvm/llvm-project/commit/672311bd77c594888e2660c124d7eae01822fffa.diff

LOG: [CFG] Fix crash on CFG building when deriving from a template.

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

Added: 


Modified: 
clang/lib/Analysis/CFG.cpp
clang/unittests/Analysis/CFGBuildResult.h
clang/unittests/Analysis/CFGTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 5c45264896027..2b99b8e680805 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -1891,7 +1891,7 @@ void CFGBuilder::addImplicitDtorsForDestructor(const 
CXXDestructorDecl *DD) {
 // (which is 
diff erent from the current class) is responsible for
 // destroying them.
 const CXXRecordDecl *CD = VI.getType()->getAsCXXRecordDecl();
-if (!CD->hasTrivialDestructor()) {
+if (CD && !CD->hasTrivialDestructor()) {
   autoCreateBlock();
   appendBaseDtor(Block, &VI);
 }
@@ -1901,7 +1901,7 @@ void CFGBuilder::addImplicitDtorsForDestructor(const 
CXXDestructorDecl *DD) {
   for (const auto &BI : RD->bases()) {
 if (!BI.isVirtual()) {
   const CXXRecordDecl *CD = BI.getType()->getAsCXXRecordDecl();
-  if (!CD->hasTrivialDestructor()) {
+  if (CD && !CD->hasTrivialDestructor()) {
 autoCreateBlock();
 appendBaseDtor(Block, &BI);
   }

diff  --git a/clang/unittests/Analysis/CFGBuildResult.h 
b/clang/unittests/Analysis/CFGBuildResult.h
index 4851d3d7fb6d6..72ad1cc7ce401 100644
--- a/clang/unittests/Analysis/CFGBuildResult.h
+++ b/clang/unittests/Analysis/CFGBuildResult.h
@@ -56,13 +56,15 @@ class CFGCallback : public 
ast_matchers::MatchFinder::MatchCallback {
 TheBuildResult = BuildResult::SawFunctionBody;
 Options.AddImplicitDtors = true;
 if (std::unique_ptr Cfg =
-CFG::buildCFG(nullptr, Body, Result.Context, Options))
+CFG::buildCFG(Func, Body, Result.Context, Options))
   TheBuildResult = {BuildResult::BuiltCFG, Func, std::move(Cfg),
 std::move(AST)};
   }
 };
 
-inline BuildResult BuildCFG(const char *Code, CFG::BuildOptions Options = {}) {
+template 
+BuildResult BuildCFG(const char *Code, CFG::BuildOptions Options = {},
+ FuncMatcherT FuncMatcher = ast_matchers::anything()) {
   std::vector Args = {"-std=c++11",
"-fno-delayed-template-parsing"};
   std::unique_ptr AST = tooling::buildASTFromCodeWithArgs(Code, Args);
@@ -72,7 +74,8 @@ inline BuildResult BuildCFG(const char *Code, 
CFG::BuildOptions Options = {}) {
   CFGCallback Callback(std::move(AST));
   Callback.Options = Options;
   ast_matchers::MatchFinder Finder;
-  Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback);
+  Finder.addMatcher(ast_matchers::functionDecl(FuncMatcher).bind("func"),
+&Callback);
 
   Finder.matchAST(Callback.AST->getASTContext());
   return std::move(Callback.TheBuildResult);

diff  --git a/clang/unittests/Analysis/CFGTest.cpp 
b/clang/unittests/Analysis/CFGTest.cpp
index 1cce8bade42fe..7ce35e3fe4a4f 100644
--- a/clang/unittests/Analysis/CFGTest.cpp
+++ b/clang/unittests/Analysis/CFGTest.cpp
@@ -70,6 +70,27 @@ TEST(CFG, VariableOfIncompleteType) {
   EXPECT_EQ(BuildResult::BuiltCFG, BuildCFG(Code).getStatus());
 }
 
+// Constructing a CFG with a dependent base should not crash.
+TEST(CFG, DependantBaseAddImplicitDtors) {
+  const char *Code = R"(
+template 
+struct Base {
+  virtual ~Base() {}
+};
+
+template 
+struct Derived : public Base {
+  virtual ~Derived() {}
+};
+  )";
+  CFG::BuildOptions Options;
+  Options.AddImplicitDtors = true;
+  Options.setAllAlwaysAdd();
+  EXPECT_EQ(BuildResult::BuiltCFG,
+BuildCFG(Code, Options, ast_matchers::hasName("~Derived"))
+.getStatus());
+}
+
 TEST(CFG, IsLinear) {
   auto expectLinear = [](bool IsLinear, const char *Code) {
 BuildResult B = BuildCFG(Code);



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


[clang] dbfa97b - [doc] Fix invalid reference to `hasReturnArgument` matcher.

2022-10-17 Thread Clement Courbet via cfe-commits

Author: Clement Courbet
Date: 2022-10-18T08:47:21+02:00
New Revision: dbfa97bd1108fe2a8e4fb13a16508f3dd0676a9b

URL: 
https://github.com/llvm/llvm-project/commit/dbfa97bd1108fe2a8e4fb13a16508f3dd0676a9b
DIFF: 
https://github.com/llvm/llvm-project/commit/dbfa97bd1108fe2a8e4fb13a16508f3dd0676a9b.diff

LOG: [doc] Fix invalid reference to `hasReturnArgument` matcher.

The matcher is called `hasReturnValue`.

Added: 


Modified: 
clang/docs/LibASTMatchersReference.html

Removed: 




diff  --git a/clang/docs/LibASTMatchersReference.html 
b/clang/docs/LibASTMatchersReference.html
index 4ac9ab0090cd4..61844ffc9de90 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -112,7 +112,7 @@ Traverse Mode
 traverse() matcher is used to set the mode:
 
 Finder->addMatcher(traverse(TK_IgnoreUnlessSpelledInSource,
-  returnStmt(hasReturnArgument(integerLiteral(equals(0
+  returnStmt(hasReturnValue(integerLiteral(equals(0
   ), this);
 
 



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


[clang] [NFC] Preparatory work for D153131 (PR #66750)

2023-09-19 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle created 
https://github.com/llvm/llvm-project/pull/66750

None

>From 3679b5c95a8de88a5cabc9ecdacdbbfef9c68ea8 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Tue, 19 Sep 2023 10:19:49 +0200
Subject: [PATCH] [NFC] Preparatory work for D153131

---
 clang/lib/Analysis/ThreadSafety.cpp | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/clang/lib/Analysis/ThreadSafety.cpp 
b/clang/lib/Analysis/ThreadSafety.cpp
index 34260ac8f4e7d6f..3107d035254dde6 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -2265,8 +2265,11 @@ void 
ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
   const PostOrderCFGView *SortedGraph = walker.getSortedGraph();
   PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
 
+  CFGBlockInfo &Initial = BlockInfo[CFGraph->getEntry().getBlockID()];
+  CFGBlockInfo &Final   = BlockInfo[CFGraph->getExit().getBlockID()];
+
   // Mark entry block as reachable
-  BlockInfo[CFGraph->getEntry().getBlockID()].Reachable = true;
+  Initial.Reachable = true;
 
   // Compute SSA names for local variables
   LocalVarMap.traverseCFG(CFGraph, SortedGraph, BlockInfo);
@@ -2282,8 +2285,8 @@ void 
ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
   // to initial lockset. Also turn off checking for lock and unlock functions.
   // FIXME: is there a more intelligent way to check lock/unlock functions?
   if (!SortedGraph->empty() && D->hasAttrs()) {
-const CFGBlock *FirstBlock = *SortedGraph->begin();
-FactSet &InitialLockset = BlockInfo[FirstBlock->getBlockID()].EntrySet;
+assert(*SortedGraph->begin() == &CFGraph->getEntry());
+FactSet &InitialLockset = Initial.EntrySet;
 
 CapExprSet ExclusiveLocksToAdd;
 CapExprSet SharedLocksToAdd;
@@ -2455,15 +2458,12 @@ void 
ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
 }
   }
 
-  CFGBlockInfo *Initial = &BlockInfo[CFGraph->getEntry().getBlockID()];
-  CFGBlockInfo *Final   = &BlockInfo[CFGraph->getExit().getBlockID()];
-
   // Skip the final check if the exit block is unreachable.
-  if (!Final->Reachable)
+  if (!Final.Reachable)
 return;
 
   // By default, we expect all locks held on entry to be held on exit.
-  FactSet ExpectedExitSet = Initial->EntrySet;
+  FactSet ExpectedExitSet = Initial.EntrySet;
 
   // Adjust the expected exit set by adding or removing locks, as declared
   // by *-LOCK_FUNCTION and UNLOCK_FUNCTION.  The intersect below will then
@@ -2479,7 +2479,7 @@ void 
ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
 ExpectedExitSet.removeLock(FactMan, Lock);
 
   // FIXME: Should we call this function for all blocks which exit the 
function?
-  intersectAndWarn(ExpectedExitSet, Final->ExitSet, Final->ExitLoc,
+  intersectAndWarn(ExpectedExitSet, Final.ExitSet, Final.ExitLoc,
LEK_LockedAtEndOfFunction, LEK_NotLockedAtEndOfFunction);
 
   Handler.leaveFunction(CurrentFunction);

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


[clang] [NFC] Preparatory work for D153131 (PR #66750)

2023-09-19 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle closed 
https://github.com/llvm/llvm-project/pull/66750
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang analysis][NFCI] Preparatory work for D153131. (PR #67420)

2023-09-26 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle created 
https://github.com/llvm/llvm-project/pull/67420

This was ported over from phabricator.

Review https://reviews.llvm.org/D153131.

>From 3581fc00f690194ac4bac631311ecdb18593b7ba Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Tue, 26 Sep 2023 14:02:44 +0200
Subject: [PATCH] [clang analysis][NFCI] Preparatory work for D153131.

This was ported over from phabricator.i
Review https://reviews.llvm.org/D153131.
---
 clang/lib/Analysis/ThreadSafety.cpp | 133 +++-
 1 file changed, 72 insertions(+), 61 deletions(-)

diff --git a/clang/lib/Analysis/ThreadSafety.cpp 
b/clang/lib/Analysis/ThreadSafety.cpp
index 3e6ceb7d54c427a..f160cf4d013c78d 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -1015,6 +1015,19 @@ class ThreadSafetyAnalyzer {
 
   BeforeSet *GlobalBeforeSet;
 
+  void warnIfMutexNotHeld(const FactSet &FSet, const NamedDecl *D,
+  const Expr *Exp, AccessKind AK, Expr *MutexExp,
+  ProtectedOperationKind POK, til::LiteralPtr *Self,
+  SourceLocation Loc);
+  void warnIfMutexHeld(const FactSet &FSet, const NamedDecl *D, const Expr 
*Exp,
+   Expr *MutexExp, til::LiteralPtr *Self,
+   SourceLocation Loc);
+
+  void checkAccess(const FactSet &FSet, const Expr *Exp, AccessKind AK,
+   ProtectedOperationKind POK);
+  void checkPtAccess(const FactSet &FSet, const Expr *Exp, AccessKind AK,
+ ProtectedOperationKind POK);
+
 public:
   ThreadSafetyAnalyzer(ThreadSafetyHandler &H, BeforeSet* Bset)
   : Arena(&Bpa), SxBuilder(Arena), Handler(H), GlobalBeforeSet(Bset) {}
@@ -1534,16 +1547,15 @@ class BuildLockset : public 
ConstStmtVisitor {
   unsigned CtxIndex;
 
   // helper functions
-  void warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp, AccessKind AK,
-  Expr *MutexExp, ProtectedOperationKind POK,
-  til::LiteralPtr *Self, SourceLocation Loc);
-  void warnIfMutexHeld(const NamedDecl *D, const Expr *Exp, Expr *MutexExp,
-   til::LiteralPtr *Self, SourceLocation Loc);
 
   void checkAccess(const Expr *Exp, AccessKind AK,
-   ProtectedOperationKind POK = POK_VarAccess);
+   ProtectedOperationKind POK = POK_VarAccess) {
+Analyzer->checkAccess(FSet, Exp, AK, POK);
+  }
   void checkPtAccess(const Expr *Exp, AccessKind AK,
- ProtectedOperationKind POK = POK_VarAccess);
+ ProtectedOperationKind POK = POK_VarAccess) {
+Analyzer->checkPtAccess(FSet, Exp, AK, POK);
+  }
 
   void handleCall(const Expr *Exp, const NamedDecl *D,
   til::LiteralPtr *Self = nullptr,
@@ -1571,17 +1583,14 @@ class BuildLockset : public 
ConstStmtVisitor {
 
 /// Warn if the LSet does not contain a lock sufficient to protect access
 /// of at least the passed in AccessKind.
-void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp,
-  AccessKind AK, Expr *MutexExp,
-  ProtectedOperationKind POK,
-  til::LiteralPtr *Self,
-  SourceLocation Loc) {
+void ThreadSafetyAnalyzer::warnIfMutexNotHeld(
+const FactSet &FSet, const NamedDecl *D, const Expr *Exp, AccessKind AK,
+Expr *MutexExp, ProtectedOperationKind POK, til::LiteralPtr *Self,
+SourceLocation Loc) {
   LockKind LK = getLockKindFromAccessKind(AK);
-
-  CapabilityExpr Cp =
-  Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp, Self);
+  CapabilityExpr Cp = SxBuilder.translateAttrExpr(MutexExp, D, Exp, Self);
   if (Cp.isInvalid()) {
-warnInvalidLock(Analyzer->Handler, MutexExp, D, Exp, Cp.getKind());
+warnInvalidLock(Handler, MutexExp, D, Exp, Cp.getKind());
 return;
   } else if (Cp.shouldIgnore()) {
 return;
@@ -1589,68 +1598,67 @@ void BuildLockset::warnIfMutexNotHeld(const NamedDecl 
*D, const Expr *Exp,
 
   if (Cp.negative()) {
 // Negative capabilities act like locks excluded
-const FactEntry *LDat = FSet.findLock(Analyzer->FactMan, !Cp);
+const FactEntry *LDat = FSet.findLock(FactMan, !Cp);
 if (LDat) {
-  Analyzer->Handler.handleFunExcludesLock(
-  Cp.getKind(), D->getNameAsString(), (!Cp).toString(), Loc);
-  return;
+Handler.handleFunExcludesLock(Cp.getKind(), D->getNameAsString(),
+  (!Cp).toString(), Loc);
+return;
 }
 
 // If this does not refer to a negative capability in the same class,
 // then stop here.
-if (!Analyzer->inCurrentScope(Cp))
-  return;
+if (!inCurrentScope(Cp))
+return;
 
 // Otherwise the negative requirement must be propagated to the caller.
-LDat = FSet.findLock(Analyzer->FactMan, Cp);
+LDat = FSet.findLo

[clang] [clang analysis][NFCI] Preparatory work for D153131. (PR #67420)

2023-09-26 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle closed 
https://github.com/llvm/llvm-project/pull/67420
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang analysis][thread-safety] Handle return-by-reference... (PR #67428)

2023-09-26 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle created 
https://github.com/llvm/llvm-project/pull/67428

...of guarded variables, when the function is not marked as requiring locks:

```
class Return {
  Mutex mu;
  Foo foo GUARDED_BY(mu);

  Foo &returns_ref_locked() {
MutexLock lock(&mu);
return foo;  // BAD
  }

  Foo &returns_ref_locks_required() SHARED_LOCKS_REQUIRED(mu) {
return foo;  // OK
  }
};
```

This is carried over from phabricator: https://reviews.llvm.org/D153131

>From c14b45843e0a72d96c4898fc7d7ee72bcd619988 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Tue, 26 Sep 2023 15:22:09 +0200
Subject: [PATCH] [clang analysis][thread-safety] Handle return-by-reference...

...of guarded variables, when the function is not marked as requiring locks:

```
class Return {
  Mutex mu;
  Foo foo GUARDED_BY(mu);

  Foo &returns_ref_locked() {
MutexLock lock(&mu);
return foo;  // BAD
  }

  Foo &returns_ref_locks_required() SHARED_LOCKS_REQUIRED(mu) {
return foo;  // OK
  }
};
```

This is carried over from phabricator: https://reviews.llvm.org/D153131
---
 .../clang/Analysis/Analyses/ThreadSafety.h|  8 +-
 .../clang/Basic/DiagnosticSemaKinds.td| 10 ++-
 clang/lib/Analysis/ThreadSafety.cpp   | 80 +--
 clang/lib/Sema/AnalysisBasedWarnings.cpp  | 12 +++
 .../SemaCXX/warn-thread-safety-analysis.cpp   | 79 ++
 5 files changed, 161 insertions(+), 28 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/ThreadSafety.h 
b/clang/include/clang/Analysis/Analyses/ThreadSafety.h
index 1808d1d71e05d2c..0866b09bab2995e 100644
--- a/clang/include/clang/Analysis/Analyses/ThreadSafety.h
+++ b/clang/include/clang/Analysis/Analyses/ThreadSafety.h
@@ -47,7 +47,13 @@ enum ProtectedOperationKind {
   POK_PassByRef,
 
   /// Passing a pt-guarded variable by reference.
-  POK_PtPassByRef
+  POK_PtPassByRef,
+
+  /// Returning a guarded variable by reference.
+  POK_ReturnByRef,
+
+  /// Returning a pt-guarded variable by reference.
+  POK_PtReturnByRef,
 };
 
 /// This enum distinguishes between different kinds of lock actions. For
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f4eb02fd9570c2f..8e423ea7691de88 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3858,7 +3858,7 @@ def warn_fun_requires_negative_cap : Warning<
   "calling function %0 requires negative capability '%1'">,
   InGroup, DefaultIgnore;
 
-// Thread safety warnings on pass by reference
+// Thread safety warnings on pass/return by reference
 def warn_guarded_pass_by_reference : Warning<
   "passing variable %1 by reference requires holding %0 "
   "%select{'%2'|'%2' exclusively}3">,
@@ -3867,6 +3867,14 @@ def warn_pt_guarded_pass_by_reference : Warning<
   "passing the value that %1 points to by reference requires holding %0 "
   "%select{'%2'|'%2' exclusively}3">,
   InGroup, DefaultIgnore;
+def warn_guarded_return_by_reference : Warning<
+  "returning variable %1 by reference requires holding %0 "
+  "%select{'%2'|'%2' exclusively}3">,
+  InGroup, DefaultIgnore;
+def warn_pt_guarded_return_by_reference : Warning<
+  "returning the value that %1 points to by reference requires holding %0 "
+  "%select{'%2'|'%2' exclusively}3">,
+  InGroup, DefaultIgnore;
 
 // Imprecise thread safety warnings
 def warn_variable_requires_lock : Warning<
diff --git a/clang/lib/Analysis/ThreadSafety.cpp 
b/clang/lib/Analysis/ThreadSafety.cpp
index f160cf4d013c78d..77b12f750e18a45 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -1008,7 +1008,7 @@ class ThreadSafetyAnalyzer {
   threadSafety::SExprBuilder SxBuilder;
 
   ThreadSafetyHandler &Handler;
-  const CXXMethodDecl *CurrentMethod = nullptr;
+  const FunctionDecl *CurrentFunction;
   LocalVariableMap LocalVarMap;
   FactManager FactMan;
   std::vector BlockInfo;
@@ -1243,10 +1243,10 @@ bool ThreadSafetyAnalyzer::inCurrentScope(const 
CapabilityExpr &CapE) {
 
   // Members are in scope from methods of the same class.
   if (const auto *P = dyn_cast(SExp)) {
-if (!CurrentMethod)
+if (!isa_and_nonnull(CurrentFunction))
   return false;
 const ValueDecl *VD = P->clangDecl();
-return VD->getDeclContext() == CurrentMethod->getDeclContext();
+return VD->getDeclContext() == CurrentFunction->getDeclContext();
   }
 
   return false;
@@ -1541,6 +1541,8 @@ class BuildLockset : public 
ConstStmtVisitor {
 
   ThreadSafetyAnalyzer *Analyzer;
   FactSet FSet;
+  // The fact set for the function on exit.
+  const FactSet &FunctionExitFSet;
   /// Maps constructed objects to `this` placeholder prior to initialization.
   llvm::SmallDenseMap ConstructedObjects;
   LocalVariableMap::Context LVarCtx;
@@ -1566,9 +1568,11 @@ class BuildLockset : public 
ConstStmtVisitor {
 bool SkipFirstParam = false);
 
 public:
-  BuildLock

[clang] Revert "[clang analysis][NFCI] Preparatory work for D153131. (#67420)" (PR #67523)

2023-09-27 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle created 
https://github.com/llvm/llvm-project/pull/67523

There was a misunderstanding as to whether we wanted those base NFC changes or 
not.

This reverts commit 166074eff2e9a5f79b791f1cc9b641a4e2968616.

>From c4904f5c3304d0117a21ec6650a260639901dcf9 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Wed, 27 Sep 2023 09:43:46 +0200
Subject: [PATCH] Revert "[clang analysis][NFCI] Preparatory work for D153131.
 (#67420)"

There was a misunderstanding as to whether we wanted those base NFC changes or 
not.

This reverts commit 166074eff2e9a5f79b791f1cc9b641a4e2968616.
---
 clang/lib/Analysis/ThreadSafety.cpp | 133 +---
 1 file changed, 61 insertions(+), 72 deletions(-)

diff --git a/clang/lib/Analysis/ThreadSafety.cpp 
b/clang/lib/Analysis/ThreadSafety.cpp
index f160cf4d013c78d..3e6ceb7d54c427a 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -1015,19 +1015,6 @@ class ThreadSafetyAnalyzer {
 
   BeforeSet *GlobalBeforeSet;
 
-  void warnIfMutexNotHeld(const FactSet &FSet, const NamedDecl *D,
-  const Expr *Exp, AccessKind AK, Expr *MutexExp,
-  ProtectedOperationKind POK, til::LiteralPtr *Self,
-  SourceLocation Loc);
-  void warnIfMutexHeld(const FactSet &FSet, const NamedDecl *D, const Expr 
*Exp,
-   Expr *MutexExp, til::LiteralPtr *Self,
-   SourceLocation Loc);
-
-  void checkAccess(const FactSet &FSet, const Expr *Exp, AccessKind AK,
-   ProtectedOperationKind POK);
-  void checkPtAccess(const FactSet &FSet, const Expr *Exp, AccessKind AK,
- ProtectedOperationKind POK);
-
 public:
   ThreadSafetyAnalyzer(ThreadSafetyHandler &H, BeforeSet* Bset)
   : Arena(&Bpa), SxBuilder(Arena), Handler(H), GlobalBeforeSet(Bset) {}
@@ -1547,15 +1534,16 @@ class BuildLockset : public 
ConstStmtVisitor {
   unsigned CtxIndex;
 
   // helper functions
+  void warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp, AccessKind AK,
+  Expr *MutexExp, ProtectedOperationKind POK,
+  til::LiteralPtr *Self, SourceLocation Loc);
+  void warnIfMutexHeld(const NamedDecl *D, const Expr *Exp, Expr *MutexExp,
+   til::LiteralPtr *Self, SourceLocation Loc);
 
   void checkAccess(const Expr *Exp, AccessKind AK,
-   ProtectedOperationKind POK = POK_VarAccess) {
-Analyzer->checkAccess(FSet, Exp, AK, POK);
-  }
+   ProtectedOperationKind POK = POK_VarAccess);
   void checkPtAccess(const Expr *Exp, AccessKind AK,
- ProtectedOperationKind POK = POK_VarAccess) {
-Analyzer->checkPtAccess(FSet, Exp, AK, POK);
-  }
+ ProtectedOperationKind POK = POK_VarAccess);
 
   void handleCall(const Expr *Exp, const NamedDecl *D,
   til::LiteralPtr *Self = nullptr,
@@ -1583,14 +1571,17 @@ class BuildLockset : public 
ConstStmtVisitor {
 
 /// Warn if the LSet does not contain a lock sufficient to protect access
 /// of at least the passed in AccessKind.
-void ThreadSafetyAnalyzer::warnIfMutexNotHeld(
-const FactSet &FSet, const NamedDecl *D, const Expr *Exp, AccessKind AK,
-Expr *MutexExp, ProtectedOperationKind POK, til::LiteralPtr *Self,
-SourceLocation Loc) {
+void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp,
+  AccessKind AK, Expr *MutexExp,
+  ProtectedOperationKind POK,
+  til::LiteralPtr *Self,
+  SourceLocation Loc) {
   LockKind LK = getLockKindFromAccessKind(AK);
-  CapabilityExpr Cp = SxBuilder.translateAttrExpr(MutexExp, D, Exp, Self);
+
+  CapabilityExpr Cp =
+  Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp, Self);
   if (Cp.isInvalid()) {
-warnInvalidLock(Handler, MutexExp, D, Exp, Cp.getKind());
+warnInvalidLock(Analyzer->Handler, MutexExp, D, Exp, Cp.getKind());
 return;
   } else if (Cp.shouldIgnore()) {
 return;
@@ -1598,67 +1589,68 @@ void ThreadSafetyAnalyzer::warnIfMutexNotHeld(
 
   if (Cp.negative()) {
 // Negative capabilities act like locks excluded
-const FactEntry *LDat = FSet.findLock(FactMan, !Cp);
+const FactEntry *LDat = FSet.findLock(Analyzer->FactMan, !Cp);
 if (LDat) {
-Handler.handleFunExcludesLock(Cp.getKind(), D->getNameAsString(),
-  (!Cp).toString(), Loc);
-return;
+  Analyzer->Handler.handleFunExcludesLock(
+  Cp.getKind(), D->getNameAsString(), (!Cp).toString(), Loc);
+  return;
 }
 
 // If this does not refer to a negative capability in the same class,
 // then stop here.
-if (!inCurrentScope(Cp))
-return;
+if (!Analyzer->inCurrentScope(Cp))
+  return;
 
 // Otherwise the nega

[clang] Revert "[clang analysis][NFCI] Preparatory work for D153131. (#67420)" (PR #67523)

2023-09-27 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle closed 
https://github.com/llvm/llvm-project/pull/67523
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Reland "[clang analysis][NFCI] Preparatory work for D153131. (#67420)… (PR #67775)

2023-09-29 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle created 
https://github.com/llvm/llvm-project/pull/67775

…" (#67523)

Discussion in https://reviews.llvm.org/D153132.

This reverts commit f70377471c990aa567584ae429e77adc9a55491b.

>From efc22cc97bbc0238f9ab066132ba434d41677599 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Fri, 29 Sep 2023 10:03:29 +0200
Subject: [PATCH] Reland "[clang analysis][NFCI] Preparatory work for D153131.
 (#67420)" (#67523)

Discussion in https://reviews.llvm.org/D153132.

This reverts commit f70377471c990aa567584ae429e77adc9a55491b.
---
 clang/lib/Analysis/ThreadSafety.cpp | 129 +++-
 1 file changed, 70 insertions(+), 59 deletions(-)

diff --git a/clang/lib/Analysis/ThreadSafety.cpp 
b/clang/lib/Analysis/ThreadSafety.cpp
index 3e6ceb7d54c427a..58dd7113665b132 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -1055,6 +1055,19 @@ class ThreadSafetyAnalyzer {
   }
 
   void runAnalysis(AnalysisDeclContext &AC);
+
+  void warnIfMutexNotHeld(const FactSet &FSet, const NamedDecl *D,
+  const Expr *Exp, AccessKind AK, Expr *MutexExp,
+  ProtectedOperationKind POK, til::LiteralPtr *Self,
+  SourceLocation Loc);
+  void warnIfMutexHeld(const FactSet &FSet, const NamedDecl *D, const Expr 
*Exp,
+   Expr *MutexExp, til::LiteralPtr *Self,
+   SourceLocation Loc);
+
+  void checkAccess(const FactSet &FSet, const Expr *Exp, AccessKind AK,
+   ProtectedOperationKind POK);
+  void checkPtAccess(const FactSet &FSet, const Expr *Exp, AccessKind AK,
+ ProtectedOperationKind POK);
 };
 
 } // namespace
@@ -1534,16 +1547,15 @@ class BuildLockset : public 
ConstStmtVisitor {
   unsigned CtxIndex;
 
   // helper functions
-  void warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp, AccessKind AK,
-  Expr *MutexExp, ProtectedOperationKind POK,
-  til::LiteralPtr *Self, SourceLocation Loc);
-  void warnIfMutexHeld(const NamedDecl *D, const Expr *Exp, Expr *MutexExp,
-   til::LiteralPtr *Self, SourceLocation Loc);
 
   void checkAccess(const Expr *Exp, AccessKind AK,
-   ProtectedOperationKind POK = POK_VarAccess);
+   ProtectedOperationKind POK = POK_VarAccess) {
+Analyzer->checkAccess(FSet, Exp, AK, POK);
+  }
   void checkPtAccess(const Expr *Exp, AccessKind AK,
- ProtectedOperationKind POK = POK_VarAccess);
+ ProtectedOperationKind POK = POK_VarAccess) {
+Analyzer->checkPtAccess(FSet, Exp, AK, POK);
+  }
 
   void handleCall(const Expr *Exp, const NamedDecl *D,
   til::LiteralPtr *Self = nullptr,
@@ -1571,17 +1583,14 @@ class BuildLockset : public 
ConstStmtVisitor {
 
 /// Warn if the LSet does not contain a lock sufficient to protect access
 /// of at least the passed in AccessKind.
-void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp,
-  AccessKind AK, Expr *MutexExp,
-  ProtectedOperationKind POK,
-  til::LiteralPtr *Self,
-  SourceLocation Loc) {
+void ThreadSafetyAnalyzer::warnIfMutexNotHeld(
+const FactSet &FSet, const NamedDecl *D, const Expr *Exp, AccessKind AK,
+Expr *MutexExp, ProtectedOperationKind POK, til::LiteralPtr *Self,
+SourceLocation Loc) {
   LockKind LK = getLockKindFromAccessKind(AK);
-
-  CapabilityExpr Cp =
-  Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp, Self);
+  CapabilityExpr Cp = SxBuilder.translateAttrExpr(MutexExp, D, Exp, Self);
   if (Cp.isInvalid()) {
-warnInvalidLock(Analyzer->Handler, MutexExp, D, Exp, Cp.getKind());
+warnInvalidLock(Handler, MutexExp, D, Exp, Cp.getKind());
 return;
   } else if (Cp.shouldIgnore()) {
 return;
@@ -1589,68 +1598,67 @@ void BuildLockset::warnIfMutexNotHeld(const NamedDecl 
*D, const Expr *Exp,
 
   if (Cp.negative()) {
 // Negative capabilities act like locks excluded
-const FactEntry *LDat = FSet.findLock(Analyzer->FactMan, !Cp);
+const FactEntry *LDat = FSet.findLock(FactMan, !Cp);
 if (LDat) {
-  Analyzer->Handler.handleFunExcludesLock(
-  Cp.getKind(), D->getNameAsString(), (!Cp).toString(), Loc);
+  Handler.handleFunExcludesLock(Cp.getKind(), D->getNameAsString(),
+(!Cp).toString(), Loc);
   return;
 }
 
 // If this does not refer to a negative capability in the same class,
 // then stop here.
-if (!Analyzer->inCurrentScope(Cp))
+if (!inCurrentScope(Cp))
   return;
 
 // Otherwise the negative requirement must be propagated to the caller.
-LDat = FSet.findLock(Analyzer->FactMan, Cp);
+LDat = FSet.findLock(FactMan, Cp);
 if (!LDat) {
-  Analyz

[clang] Reland "[clang analysis][NFCI] Preparatory work for D153131. (#67420)… (PR #67775)

2023-09-29 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle closed 
https://github.com/llvm/llvm-project/pull/67775
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang analysis][thread-safety] Handle return-by-reference... (PR #67776)

2023-09-29 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle created 
https://github.com/llvm/llvm-project/pull/67776

...of guarded variables, when the function is not marked as requiring locks:

```
class Return {
  Mutex mu;
  Foo foo GUARDED_BY(mu);

  Foo &returns_ref_locked() {
MutexLock lock(&mu);
return foo;  // BAD
  }

  Foo &returns_ref_locks_required() SHARED_LOCKS_REQUIRED(mu) {
return foo;  // OK
  }
};
```

Review on Phabricator: https://reviews.llvm.org/D153131

>From e5f03f5650038c8c6488960f7c158746e11da687 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Fri, 29 Sep 2023 10:39:58 +0200
Subject: [PATCH] [clang analysis][thread-safety] Handle return-by-reference...

...of guarded variables, when the function is not marked as requiring locks:

```
class Return {
  Mutex mu;
  Foo foo GUARDED_BY(mu);

  Foo &returns_ref_locked() {
MutexLock lock(&mu);
return foo;  // BAD
  }

  Foo &returns_ref_locks_required() SHARED_LOCKS_REQUIRED(mu) {
return foo;  // OK
  }
};
```

Review on Phabricator: https://reviews.llvm.org/D153131
---
 .../clang/Analysis/Analyses/ThreadSafety.h|  8 +-
 .../clang/Basic/DiagnosticSemaKinds.td| 10 ++-
 clang/lib/Analysis/ThreadSafety.cpp   | 80 +--
 clang/lib/Sema/AnalysisBasedWarnings.cpp  | 12 +++
 .../SemaCXX/warn-thread-safety-analysis.cpp   | 79 ++
 5 files changed, 161 insertions(+), 28 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/ThreadSafety.h 
b/clang/include/clang/Analysis/Analyses/ThreadSafety.h
index 1808d1d71e05d2c..0866b09bab2995e 100644
--- a/clang/include/clang/Analysis/Analyses/ThreadSafety.h
+++ b/clang/include/clang/Analysis/Analyses/ThreadSafety.h
@@ -47,7 +47,13 @@ enum ProtectedOperationKind {
   POK_PassByRef,
 
   /// Passing a pt-guarded variable by reference.
-  POK_PtPassByRef
+  POK_PtPassByRef,
+
+  /// Returning a guarded variable by reference.
+  POK_ReturnByRef,
+
+  /// Returning a pt-guarded variable by reference.
+  POK_PtReturnByRef,
 };
 
 /// This enum distinguishes between different kinds of lock actions. For
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 29362df68365350..39e6bc5a73e128c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3858,7 +3858,7 @@ def warn_fun_requires_negative_cap : Warning<
   "calling function %0 requires negative capability '%1'">,
   InGroup, DefaultIgnore;
 
-// Thread safety warnings on pass by reference
+// Thread safety warnings on pass/return by reference
 def warn_guarded_pass_by_reference : Warning<
   "passing variable %1 by reference requires holding %0 "
   "%select{'%2'|'%2' exclusively}3">,
@@ -3867,6 +3867,14 @@ def warn_pt_guarded_pass_by_reference : Warning<
   "passing the value that %1 points to by reference requires holding %0 "
   "%select{'%2'|'%2' exclusively}3">,
   InGroup, DefaultIgnore;
+def warn_guarded_return_by_reference : Warning<
+  "returning variable %1 by reference requires holding %0 "
+  "%select{'%2'|'%2' exclusively}3">,
+  InGroup, DefaultIgnore;
+def warn_pt_guarded_return_by_reference : Warning<
+  "returning the value that %1 points to by reference requires holding %0 "
+  "%select{'%2'|'%2' exclusively}3">,
+  InGroup, DefaultIgnore;
 
 // Imprecise thread safety warnings
 def warn_variable_requires_lock : Warning<
diff --git a/clang/lib/Analysis/ThreadSafety.cpp 
b/clang/lib/Analysis/ThreadSafety.cpp
index 58dd7113665b132..54d0e95c6bd79a2 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -1008,7 +1008,7 @@ class ThreadSafetyAnalyzer {
   threadSafety::SExprBuilder SxBuilder;
 
   ThreadSafetyHandler &Handler;
-  const CXXMethodDecl *CurrentMethod = nullptr;
+  const FunctionDecl *CurrentFunction;
   LocalVariableMap LocalVarMap;
   FactManager FactMan;
   std::vector BlockInfo;
@@ -1243,10 +1243,10 @@ bool ThreadSafetyAnalyzer::inCurrentScope(const 
CapabilityExpr &CapE) {
 
   // Members are in scope from methods of the same class.
   if (const auto *P = dyn_cast(SExp)) {
-if (!CurrentMethod)
+if (!isa_and_nonnull(CurrentFunction))
   return false;
 const ValueDecl *VD = P->clangDecl();
-return VD->getDeclContext() == CurrentMethod->getDeclContext();
+return VD->getDeclContext() == CurrentFunction->getDeclContext();
   }
 
   return false;
@@ -1541,6 +1541,8 @@ class BuildLockset : public 
ConstStmtVisitor {
 
   ThreadSafetyAnalyzer *Analyzer;
   FactSet FSet;
+  // The fact set for the function on exit.
+  const FactSet &FunctionExitFSet;
   /// Maps constructed objects to `this` placeholder prior to initialization.
   llvm::SmallDenseMap ConstructedObjects;
   LocalVariableMap::Context LVarCtx;
@@ -1566,9 +1568,11 @@ class BuildLockset : public 
ConstStmtVisitor {
 bool SkipFirstParam = false);
 
 public:
-  BuildLockset(ThreadSafetyAnalyzer *Anlzr,

[clang] [clang analysis][thread-safety] Handle return-by-reference... (PR #67776)

2023-09-29 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle updated 
https://github.com/llvm/llvm-project/pull/67776

>From 7212f4cff29784f9b874a2c52586792f02158200 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Fri, 29 Sep 2023 10:39:58 +0200
Subject: [PATCH] [clang analysis][thread-safety] Handle return-by-reference...

...of guarded variables, when the function is not marked as requiring locks:

```
class Return {
  Mutex mu;
  Foo foo GUARDED_BY(mu);

  Foo &returns_ref_locked() {
MutexLock lock(&mu);
return foo;  // BAD
  }

  Foo &returns_ref_locks_required() SHARED_LOCKS_REQUIRED(mu) {
return foo;  // OK
  }
};
```

Review on Phabricator: https://reviews.llvm.org/D153131
---
 .../clang/Analysis/Analyses/ThreadSafety.h|  8 +-
 .../clang/Basic/DiagnosticSemaKinds.td| 10 ++-
 clang/lib/Analysis/ThreadSafety.cpp   | 80 +--
 clang/lib/Sema/AnalysisBasedWarnings.cpp  | 12 +++
 .../SemaCXX/warn-thread-safety-analysis.cpp   | 79 ++
 5 files changed, 161 insertions(+), 28 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/ThreadSafety.h 
b/clang/include/clang/Analysis/Analyses/ThreadSafety.h
index 1808d1d71e05d2c..0866b09bab2995e 100644
--- a/clang/include/clang/Analysis/Analyses/ThreadSafety.h
+++ b/clang/include/clang/Analysis/Analyses/ThreadSafety.h
@@ -47,7 +47,13 @@ enum ProtectedOperationKind {
   POK_PassByRef,
 
   /// Passing a pt-guarded variable by reference.
-  POK_PtPassByRef
+  POK_PtPassByRef,
+
+  /// Returning a guarded variable by reference.
+  POK_ReturnByRef,
+
+  /// Returning a pt-guarded variable by reference.
+  POK_PtReturnByRef,
 };
 
 /// This enum distinguishes between different kinds of lock actions. For
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 29362df68365350..39e6bc5a73e128c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3858,7 +3858,7 @@ def warn_fun_requires_negative_cap : Warning<
   "calling function %0 requires negative capability '%1'">,
   InGroup, DefaultIgnore;
 
-// Thread safety warnings on pass by reference
+// Thread safety warnings on pass/return by reference
 def warn_guarded_pass_by_reference : Warning<
   "passing variable %1 by reference requires holding %0 "
   "%select{'%2'|'%2' exclusively}3">,
@@ -3867,6 +3867,14 @@ def warn_pt_guarded_pass_by_reference : Warning<
   "passing the value that %1 points to by reference requires holding %0 "
   "%select{'%2'|'%2' exclusively}3">,
   InGroup, DefaultIgnore;
+def warn_guarded_return_by_reference : Warning<
+  "returning variable %1 by reference requires holding %0 "
+  "%select{'%2'|'%2' exclusively}3">,
+  InGroup, DefaultIgnore;
+def warn_pt_guarded_return_by_reference : Warning<
+  "returning the value that %1 points to by reference requires holding %0 "
+  "%select{'%2'|'%2' exclusively}3">,
+  InGroup, DefaultIgnore;
 
 // Imprecise thread safety warnings
 def warn_variable_requires_lock : Warning<
diff --git a/clang/lib/Analysis/ThreadSafety.cpp 
b/clang/lib/Analysis/ThreadSafety.cpp
index 58dd7113665b132..54d0e95c6bd79a2 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -1008,7 +1008,7 @@ class ThreadSafetyAnalyzer {
   threadSafety::SExprBuilder SxBuilder;
 
   ThreadSafetyHandler &Handler;
-  const CXXMethodDecl *CurrentMethod = nullptr;
+  const FunctionDecl *CurrentFunction;
   LocalVariableMap LocalVarMap;
   FactManager FactMan;
   std::vector BlockInfo;
@@ -1243,10 +1243,10 @@ bool ThreadSafetyAnalyzer::inCurrentScope(const 
CapabilityExpr &CapE) {
 
   // Members are in scope from methods of the same class.
   if (const auto *P = dyn_cast(SExp)) {
-if (!CurrentMethod)
+if (!isa_and_nonnull(CurrentFunction))
   return false;
 const ValueDecl *VD = P->clangDecl();
-return VD->getDeclContext() == CurrentMethod->getDeclContext();
+return VD->getDeclContext() == CurrentFunction->getDeclContext();
   }
 
   return false;
@@ -1541,6 +1541,8 @@ class BuildLockset : public 
ConstStmtVisitor {
 
   ThreadSafetyAnalyzer *Analyzer;
   FactSet FSet;
+  // The fact set for the function on exit.
+  const FactSet &FunctionExitFSet;
   /// Maps constructed objects to `this` placeholder prior to initialization.
   llvm::SmallDenseMap ConstructedObjects;
   LocalVariableMap::Context LVarCtx;
@@ -1566,9 +1568,11 @@ class BuildLockset : public 
ConstStmtVisitor {
 bool SkipFirstParam = false);
 
 public:
-  BuildLockset(ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info)
+  BuildLockset(ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info,
+   const FactSet &FunctionExitFSet)
   : ConstStmtVisitor(), Analyzer(Anlzr), FSet(Info.EntrySet),
-LVarCtx(Info.EntryContext), CtxIndex(Info.EntryIndex) {}
+FunctionExitFSet(FunctionExitFSet), LVarCtx(Info.EntryContext),
+CtxIndex(Info.EntryIndex) 

[clang] [clang analysis][thread-safety] Handle return-by-reference... (PR #67776)

2023-09-29 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle closed 
https://github.com/llvm/llvm-project/pull/67776
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Revert "[clang analysis][thread-safety] Handle return-by-reference...… (PR #67795)

2023-09-29 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle created 
https://github.com/llvm/llvm-project/pull/67795

… (#67776)"

This detects issues in `scudo`. Reverting until these are fixed.

```
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd.h:74:12:
 error: returning variable 'QuarantineCache' by reference requires holding 
mutex 'Mutex' exclusively [-Werror,-Wthread-safety-reference]
   74 | return QuarantineCache;
  |^
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/combined.h:248:28:
 note: in instantiation of member function 
'scudo::TSD>::getQuarantineCache' requested here
  248 | Quarantine.drain(&TSD->getQuarantineCache(),
  |^
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd.h:57:15:
 note: in instantiation of member function 
'scudo::Allocator::commitBack' 
requested here
   57 | Instance->commitBack(this);
  |   ^
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd_exclusive.h:172:27:
 note: in instantiation of member function 
'scudo::TSD>::commitBack' requested here
  172 |   TSDRegistryT::ThreadTSD.commitBack(Instance);
  |   ^
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd_exclusive.h:33:46:
 note: in instantiation of function template specialization 
'scudo::teardownThread>' requested here
   33 | CHECK_EQ(pthread_key_create(&PThreadKey, 
teardownThread), 0);
  |  ^
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd_exclusive.h:42:5:
 note: in instantiation of member function 
'scudo::TSDRegistryExT>::init' requested here
   42 | init(Instance); // Sets Initialized.
  | ^
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd_exclusive.h:130:5:
 note: in instantiation of member function 
'scudo::TSDRegistryExT>::initOnceMaybe' requested here
  130 | initOnceMaybe(Instance);
  | ^
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd_exclusive.h:74:5:
 note: in instantiation of member function 
'scudo::TSDRegistryExT>::initThread' requested here
   74 | initThread(Instance, MinimalInit);
  | ^
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/combined.h:221:17:
 note: in instantiation of member function 
'scudo::TSDRegistryExT>::initThreadMaybe' requested here
  221 | TSDRegistry.initThreadMaybe(this, MinimalInit);
  | ^
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/combined.h:790:5:
 note: in instantiation of member function 
'scudo::Allocator::initThreadMaybe' 
requested here
  790 | initThreadMaybe();
  | ^
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/wrappers_c.inc:36:25:
 note: in instantiation of member function 
'scudo::Allocator::canReturnNull' 
requested here
   36 | if (SCUDO_ALLOCATOR.canReturnNull()) {
```

This reverts commit 6dd96d6e80e9b3679a6161c590c60e0e99549b89.

>From 462bdd5bf0861a27f451f7917802a954e2046bc7 Mon Sep 17 00:00:00 2001
From: Clement Courbet 
Date: Fri, 29 Sep 2023 14:12:17 +0200
Subject: [PATCH] Revert "[clang analysis][thread-safety] Handle
 return-by-reference... (#67776)"

This detects issues in `scudo`. Reverting until these are fixed.

```
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd.h:74:12:
 error: returning variable 'QuarantineCache' by reference requires holding 
mutex 'Mutex' exclusively [-Werror,-Wthread-safety-reference]
   74 | return QuarantineCache;
  |^
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/combined.h:248:28:
 note: in instantiation of member function 
'scudo::TSD>::getQuarantineCache' requested here
  248 | Quarantine.drain(&TSD->getQuarantineCache(),
  |^
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd.h:57:15:
 note: in instantiation of member function 
'scudo::Allocator::commitBack' 
requested here
   57 | Instance->commitBack(this);
  |   ^
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd_exclusive.h:172:27:
 note: in instantiation of member function 
'scudo::TSD>::commitBack' requested here
  172 |   TSDRegistryT::ThreadTSD.commitBack(Instance);
  |   ^
/b/sanitizer-x86_64-linux-autoconf/build/llvm-project/compiler-rt/lib/scudo/standalone/tsd_exclusive.h:33:46:
 note: in instantiation of function template specialization 
'scudo::teardownThread>' requested here
   33 | CHECK_EQ(pthread_key_create(&PThreadKey, 
teardo

[clang] Revert "[clang analysis][thread-safety] Handle return-by-reference...… (PR #67795)

2023-09-29 Thread Clement Courbet via cfe-commits

https://github.com/legrosbuffle closed 
https://github.com/llvm/llvm-project/pull/67795
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   3   4   >