[PATCH] D101790: [clang-tidy] Aliasing: Add support for passing the variable into a function by reference.

2021-05-04 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

In D101790#2734937 , @NoQ wrote:

> +Adam, the original author of bugprone-redundant-branch-condition. Adam, do 
> you have any thoughts regarding the tests regressed by this patch? Are they 
> something we should absolutely keep warning on?

Actually, this checker did not give any false positives whever I tested it on 
several open-source projects. I can agree with the one where the function 
starts another thread which changes its parameter, but the rest, where the 
local variable is mutated after or in the branch I cannot see any reason to 
disappear. Can you tell me an example where these are false positives? Why do 
these warnings disappear?


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

https://reviews.llvm.org/D101790

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


[PATCH] D89380: [clang-tidy] Fix for cppcoreguidelines-prefer-member-initializer to handle classes declared in macros

2020-11-19 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware marked an inline comment as done.
baloghadamsoftware added inline comments.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp:492
+
+#define MACRO1 struct InMacro1 { int i; InMacro1() { i = 0; } };
+// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: 'i' should be initialized in a 
member initializer of the constructor 
[cppcoreguidelines-prefer-member-initializer]

alexfh wrote:
> baloghadamsoftware wrote:
> > alexfh wrote:
> > > Could you add tests where the field name comes from a macro argument and 
> > > from token pasting? Something along the lines of:
> > > 
> > > ```
> > > #define MACRO4(field) struct InMacro1 { int field; InMacro1() { field = 
> > > 0; } }
> > > 
> > > MACRO4(q);
> > > 
> > > #define MACRO5(X) X
> > > 
> > > MACRO5(struct InMacro1 { int field; InMacro1() { field = 0; } });
> > > 
> > > #define MACRO6(field) struct InMacro1 { int qqq ## field; InMacro1() { 
> > > qqq ## field = 0; } }
> > > 
> > > MACRO6(q);
> > > ```
> > It seems that handling of macro parameters in the `SourceManager` is 
> > totally off. The location in these cases are the macro call itself, but the 
> > spelling location is not the real location inside the macro, but in 
> > `MACRO4` it is the location of the argument still in the macro call. The 
> > case with `MACRO6` is even worse, because its spelling location is 
> > erroneous. So I could only added some fixmes. However, it does not crash, 
> > at least. That is the main intention of this particular patch.
> It's impossible to correctly handle replacements in all cases involving 
> macros (apart from expanding all macros while applying fixes ;). The usual 
> strategy is to warn always, but only suggest replacements when we can be 
> sufficiently confident in their validity. In this case we can either disable 
> fixes when any part of the code being touched is in a macro or try to detect 
> that the whole range being modified is sort of "on the same level of macro 
> hell". The `Lexer::makeFileCharRange` is supposed to help with the latter 
> (see clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp for an 
> example of using it).
Actually, this is what the patch does: it does not suggest a fix in complex 
macro cases, only in the simplest ones. And most importantly, it prevents the 
crash mentioned in the //Bugzilla// bug report.


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

https://reviews.llvm.org/D89380

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


[PATCH] D90691: [analyzer] Add new checker for unchecked return value.

2020-11-06 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/UncheckedReturnValueChecker.cpp:41
+BugReporter ) const {
+auto FoundCall = callExpr().bind("call");
+auto CallInCompound = compoundStmt(forEach(FoundCall));

Please note that the `CallExpr` does not necessarily stands alone. It may be 
wrapped into an `ExprWithCleanUps`. We should consider these `CallExpr`s as 
unchecked too.



Comment at: clang/lib/StaticAnalyzer/Checkers/UncheckedReturnValueChecker.cpp:85
+private:
+  llvm::StringMap FunctionsToCheck = {
+  {"aligned_alloc", 2}, {"asctime_s", 3}, {"at_quick_exit", 1},

Hmm, why `StringMap<>`? Why not `CallDescriptionMap<>`?



Comment at: clang/test/Analysis/unchecked-return-value.cpp:10
+int f1(int X) {
+  scanf(""); // expected-warning {{Return value is not checked in call to 
'scanf' [security.UncheckedReturnValue]}}
+  std::scanf(""); // expected-warning {{Return value is not checked in call to 
'scanf' [security.UncheckedReturnValue]}}

Please use some valid format here. E.g. `scanf("%*c");`



Comment at: clang/test/Analysis/unchecked-return-value.cpp:16
+scanf(""); // expected-warning {{Return value is not checked in call to 
'scanf' [security.UncheckedReturnValue]}}
+  }
+

Please add such simple test case for all the functions we try to check. (One 
call is enough for every such function, either in `std::` or on the top 
namespace.)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90691

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


[PATCH] D89380: [clang-tidy] Fix for cppcoreguidelines-prefer-member-initializer to handle classes declared in macros

2020-10-20 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware marked an inline comment as done.
baloghadamsoftware added a comment.

In D89380#2330076 , @alexfh wrote:

> Thanks for the fix! However, I'm not sure it's possible to correctly rewrite 
> code in all cases where macros are involved. See a couple of motivating 
> examples in the comment.






Comment at: 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp:492
+
+#define MACRO1 struct InMacro1 { int i; InMacro1() { i = 0; } };
+// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: 'i' should be initialized in a 
member initializer of the constructor 
[cppcoreguidelines-prefer-member-initializer]

alexfh wrote:
> Could you add tests where the field name comes from a macro argument and from 
> token pasting? Something along the lines of:
> 
> ```
> #define MACRO4(field) struct InMacro1 { int field; InMacro1() { field = 0; } }
> 
> MACRO4(q);
> 
> #define MACRO5(X) X
> 
> MACRO5(struct InMacro1 { int field; InMacro1() { field = 0; } });
> 
> #define MACRO6(field) struct InMacro1 { int qqq ## field; InMacro1() { qqq ## 
> field = 0; } }
> 
> MACRO6(q);
> ```
It seems that handling of macro parameters in the `SourceManager` is totally 
off. The location in these cases are the macro call itself, but the spelling 
location is not the real location inside the macro, but in `MACRO4` it is the 
location of the argument still in the macro call. The case with `MACRO6` is 
even worse, because its spelling location is erroneous. So I could only added 
some fixmes. However, it does not crash, at least. That is the main intention 
of this particular patch.


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

https://reviews.llvm.org/D89380

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


[PATCH] D89380: [clang-tidy] Fix for cppcoreguidelines-prefer-member-initializer to handle classes declared in macros

2020-10-20 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 299378.
baloghadamsoftware added a comment.

Tests added, code reformatted.


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

https://reviews.llvm.org/D89380

Files:
  
clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
@@ -1,5 +1,11 @@
 // RUN: %check_clang_tidy %s cppcoreguidelines-prefer-member-initializer %t -- -- -fcxx-exceptions
 
+// CHECK-MESSAGES: warning: '' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// FIXME: The source location of the assignment in MACRO6 (see towards the end
+//of this test file) is the macro itself and the spelling location is
+//:6:1 for some strange reason. This results this warning
+//to be placed at the very beginning of the message list.
+
 extern void __assert_fail (__const char *__assertion, __const char *__file,
 unsigned int __line, __const char *__function)
  __attribute__ ((__noreturn__));
@@ -488,3 +494,39 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
 // CHECK-FIXES: {{^\ *$}}
 }
+
+#define MACRO1 struct InMacro1 { int i; InMacro1() { i = 0; } };
+// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: 'i' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: #define MACRO1 struct InMacro1 { int i; InMacro1() : i(0) { } };
+MACRO1
+
+#define MACRO2 struct InMacro2 { int i, j; InMacro2() : i(0) { j = 1; } };
+// CHECK-MESSAGES: :[[@LINE-1]]:64: warning: 'j' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: #define MACRO2 struct InMacro2 { int i, j; InMacro2() : i(0), j(1) { } };
+MACRO2
+
+#define MACRO3 struct InMacro3 { int i, j; InMacro3() : j(1) { i = 0; } };
+// CHECK-MESSAGES: :[[@LINE-1]]:64: warning: 'i' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: #define MACRO3 struct InMacro3 { int i, j; InMacro3() : i(0), j(1) { } };
+MACRO3
+
+#define MACRO4(field) struct InMacro4 { int field; InMacro4() { field = 0; } };
+// C_HECK-MESSAGES: :[[@LINE-1]]:65: warning: 'field' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// C_HECK-FIXES: #define MACRO4(field) struct InMacro4 { int field; InMacro4() : field(0) { } };
+MACRO4(q)
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'q' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// FIXME: The source location of the assignment is the macro itself and the
+//spelling location is the argument in the macro call, instead of the
+//place where it is used inside the macro.
+
+#define MACRO5(X) X
+MACRO5(struct InMacro5 { int field; InMacro5() { field = 0; } };)
+// CHECK-MESSAGES: :[[@LINE-1]]:50: warning: 'field' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: MACRO5(struct InMacro5 { int field; InMacro5() : field(0) { } };)
+
+#define MACRO6(field) struct InMacro6 { int qqq ## field; InMacro6() { \
+  qqq ## field = 0; } };
+// C_HECK-MESSAGES: :[[@LINE-1]]:3: warning: 'qqq ## field' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// C_HECK-FIXES: #define MACRO6(field) struct InMacro6 { int qqq ### field; InMacro6() : qqq ## field(0) { \
+// C_HECK-FIXES: } };
+MACRO6(q)
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
===
--- clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
@@ -123,9 +123,8 @@
 
   for (const Stmt *S : Body->body()) {
 if (S->getBeginLoc().isMacroID()) {
-  StringRef MacroName =
-Lexer::getImmediateMacroName(S->getBeginLoc(), *Result.SourceManager,
- getLangOpts());
+  StringRef MacroName = Lexer::getImmediateMacroName(
+  S->getBeginLoc(), *Result.SourceManager, getLangOpts());
   if (MacroName.contains_lower("assert"))
 return;
 }
@@ -144,99 +143,125 

[PATCH] D89380: [clang-tidy] Fix for cppcoreguidelines-prefer-member-initializer to handle classes declared in macros

2020-10-14 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware created this revision.
baloghadamsoftware added reviewers: aaron.ballman, gribozavr2.
baloghadamsoftware added a project: clang-tools-extra.
Herald added subscribers: martong, gamesh411, Szelethus, dkrupp, rnkovacs, 
kbarton, xazax.hun, whisperity, nemanjai.
Herald added a project: clang.
baloghadamsoftware requested review of this revision.

`cppcoreguidelines-prefer-member-initializer` crashes on classes declared 
inside macros (see bug 47778 ). 
This patch fixes this issue.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D89380

Files:
  
clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
@@ -488,3 +488,18 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
 // CHECK-FIXES: {{^\ *$}}
 }
+
+#define MACRO1 struct InMacro1 { int i; InMacro1() { i = 0; } };
+// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: 'i' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: #define MACRO1 struct InMacro1 { int i; InMacro1() : i(0) { } };
+MACRO1
+
+#define MACRO2 struct InMacro2 { int i, j; InMacro2() : i(0) { j = 1; } };
+// CHECK-MESSAGES: :[[@LINE-1]]:64: warning: 'j' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: #define MACRO2 struct InMacro2 { int i, j; InMacro2() : i(0), j(1) { } };
+MACRO2
+
+#define MACRO3 struct InMacro3 { int i, j; InMacro3() : j(1) { i = 0; } };
+// CHECK-MESSAGES: :[[@LINE-1]]:64: warning: 'i' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: #define MACRO3 struct InMacro3 { int i, j; InMacro3() : i(0), j(1) { } };
+MACRO3
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
===
--- clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
@@ -144,99 +144,132 @@
 const FieldDecl *Field;
 const Expr *InitValue;
 std::tie(Field, InitValue) = isAssignmentToMemberOf(Class, S);
-if (Field) {
-  if (IsUseDefaultMemberInitEnabled && getLangOpts().CPlusPlus11 &&
-  Ctor->isDefaultConstructor() &&
-  (getLangOpts().CPlusPlus20 || !Field->isBitField()) &&
-  (!isa(Class->getDeclContext()) ||
-   !cast(Class->getDeclContext())->isUnion()) &&
-  shouldBeDefaultMemberInitializer(InitValue)) {
-auto Diag =
-diag(S->getBeginLoc(), "%0 should be initialized in an in-class"
-   " default member initializer")
-<< Field;
-
-SourceLocation FieldEnd =
-Lexer::getLocForEndOfToken(Field->getSourceRange().getEnd(), 0,
-   *Result.SourceManager, getLangOpts());
-Diag << FixItHint::CreateInsertion(FieldEnd,
-   UseAssignment ? " = " : "{")
- << FixItHint::CreateInsertionFromRange(
-FieldEnd,
-CharSourceRange(InitValue->getSourceRange(), true))
- << FixItHint::CreateInsertion(FieldEnd, UseAssignment ? "" : "}");
-
-SourceLocation SemiColonEnd =
-Lexer::findNextToken(S->getEndLoc(), *Result.SourceManager,
- getLangOpts())
-->getEndLoc();
-CharSourceRange StmtRange =
-CharSourceRange::getCharRange(S->getBeginLoc(), SemiColonEnd);
-
-Diag << FixItHint::CreateRemoval(StmtRange);
+if (!Field)
+  continue;
+assert(InitValue && "An assigment to a field must also have an assigned"
+" value");
+
+SourceLocation BeginLoc = S->getBeginLoc();
+SourceLocation EndLoc = S->getEndLoc();
+SourceRange InitValueRange = InitValue->getSourceRange();
+if (BeginLoc.isMacroID()) {
+  BeginLoc = Result.SourceManager->getSpellingLoc(BeginLoc);
+  EndLoc = Result.SourceManager->getSpellingLoc(EndLoc);
+  InitValueRange = SourceRange(
+  Result.SourceManager->getSpellingLoc(InitValueRange.getBegin()),
+  Result.SourceManager->getSpellingLoc(InitValueRange.getEnd()));
+}
+
+if 

[PATCH] D88831: [clang-tidy] Remove obsolete checker google-runtime-references

2020-10-06 Thread Balogh , Ádám via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGd6c9dc3c17e4: [clang-tidy] Remove obsolete checker 
google-runtime-references (authored by baloghadamsoftware).

Changed prior to commit:
  https://reviews.llvm.org/D88831?vs=296170=296416#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D88831

Files:
  clang-tools-extra/clang-tidy/google/CMakeLists.txt
  clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp
  clang-tools-extra/clang-tidy/google/NonConstReferences.cpp
  clang-tools-extra/clang-tidy/google/NonConstReferences.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/google-runtime-references.rst
  clang-tools-extra/test/clang-tidy/checkers/google-runtime-references.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/google-runtime-references.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/google-runtime-references.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-// RUN: %check_clang_tidy %s google-runtime-references %t -- \
-// RUN:   -config="{CheckOptions: \
-// RUN: [{key: google-runtime-references.IncludedTypes, \
-// RUN:   value: 'included::A; included::B'}]}"
-
-int a;
-int  = a;
-int *c;
-void f1(int a);
-void f2(int *b);
-void f3(const int );
-void f4(int const );
-
-// Don't warn on implicit operator= in c++11 mode.
-class A {
-  virtual void f() {}
-};
-// Don't warn on rvalue-references.
-struct A2 {
-  A2(A2&&) = default;
-  void f(A2&&) {}
-};
-
-// Don't warn on iostream parameters.
-namespace xxx {
-class istream { };
-class ostringstream { };
-}
-void g1(xxx::istream );
-void g1(xxx::ostringstream );
-
-void g1(int );
-// CHECK-MESSAGES: [[@LINE-1]]:14: warning: non-const reference parameter 'a', make it const or use a pointer [google-runtime-references]
-
-struct s {};
-void g2(int a, int b, s c, s );
-// CHECK-MESSAGES: [[@LINE-1]]:31: warning: non-const reference parameter 'd', {{.*}}
-
-typedef int 
-void g3(ref a);
-// CHECK-MESSAGES: [[@LINE-1]]:13: warning: non-const reference {{.*}}
-
-void g4(int , int , int &);
-// CHECK-MESSAGES: [[@LINE-1]]:14: warning: non-const reference parameter 'a', {{.*}}
-// CHECK-MESSAGES: [[@LINE-2]]:22: warning: non-const reference parameter 'b', {{.*}}
-// CHECK-MESSAGES: [[@LINE-3]]:30: warning: non-const reference parameter at index 2, {{.*}}
-
-class B {
-  B(B& a) {}
-// CHECK-MESSAGES: [[@LINE-1]]:8: warning: non-const reference {{.*}}
-  virtual void f(int ) {}
-// CHECK-MESSAGES: [[@LINE-1]]:23: warning: non-const reference {{.*}}
-  void g(int );
-// CHECK-MESSAGES: [[@LINE-1]]:15: warning: non-const reference {{.*}}
-
-  // Don't warn on the parameter of stream extractors defined as members.
-  B& operator>>(int& val) { return *this; }
-};
-
-// Only warn on the first declaration of each function to reduce duplicate
-// warnings.
-void B::g(int ) {}
-
-// Don't warn on the first parameter of stream inserters.
-A& operator<<(A& s, int&) { return s; }
-// CHECK-MESSAGES: [[@LINE-1]]:25: warning: non-const reference parameter at index 1, {{.*}}
-
-// Don't warn on either parameter of stream extractors. Both need to be
-// non-const references by convention.
-A& operator>>(A& input, int& val) { return input; }
-
-// Don't warn on lambdas.
-auto lambda = [] (int&) {};
-
-// Don't warn on typedefs, as we'll warn on the function itself.
-typedef int (*fp)(int &);
-
-// Don't warn on function references.
-typedef void F();
-void g5(const F& func) {}
-void g6(F& func) {}
-
-template
-void g7(const T& t) {}
-
-template
-void g8(T t) {}
-
-void f5() {
-  g5(f5);
-  g6(f5);
-  g7(f5);
-  g7(f5);
-  g8(f5);
-  g8(f5);
-}
-
-// Don't warn on dependent types.
-template
-void g9(T& t) {}
-template
-void g10(T t) {}
-
-void f6() {
-  int i;
-  float f;
-  g9(i);
-  g9(i);
-  g9(i);
-  g10(i);
-  g10(f);
-}
-
-// Warn only on the overridden methods from the base class, as the child class
-// only implements the interface.
-class C : public B {
-  C();
-  virtual void f(int ) {}
-};
-
-// Don't warn on operator<< with streams-like interface.
-A& operator<<(A& s, int) { return s; }
-
-// Don't warn on swap().
-void swap(C& c1, C& c2) {}
-
-// Don't warn on standalone operator++, operator--, operator+=, operator-=,
-// operator*=, etc. that all need non-const references to be functional.
-A& operator++(A& a) { return a; }
-A operator++(A& a, int) { return a; }
-A& operator--(A& a) { return a; }
-A operator--(A& a, int) { return a; }
-A& operator+=(A& a, const A& b) { return a; }
-A& operator-=(A& a, const A& b) { return a; }
-A& operator*=(A& a, const A& b) { return a; }
-A& operator/=(A& a, const A& b) { return a; }
-A& operator%=(A& a, const A& b) { return a; }
-A& operator<<=(A& a, const A& b) { return a; }
-A& operator>>=(A& a, const A& b) { return a; }
-A& operator|=(A& a, const A& b) { return a; }

[PATCH] D88831: [clang-tidy] Remove obsolete checker google-runtime-references

2020-10-05 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

In D88831#2311802 , @lebedev.ri wrote:

> In D88831#2311800 , @Eugene.Zelenko 
> wrote:
>
>> Does this check make sense in content of other style guides?
>
> I'd +1 to moving it to `readability`.

IMHO this check never made any sense. There **was** a //Google//-specific rule 
for this, that is why it was placed in `google` not in `readability`. 
Generally, forcing programmers not to use non-const reference parameters and 
force them the old //C// way (pointers) does not make any sense. I wonder why 
this rule was there in //Google//, but outside of it I never saw such a rule. I 
would surely not place such check into `readability` because following such 
rule reduces the readability instead of improving it. However, the main point 
is that even for //Google// there is no such rule anymore thus I see no point 
to keep this check.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D88831

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


[PATCH] D88831: [clang-tidy] Remove obsolete checker google-runtime-references

2020-10-05 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware created this revision.
baloghadamsoftware added reviewers: alexfh, gribozavr2, aaron.ballman.
baloghadamsoftware added a project: clang-tools-extra.
Herald added subscribers: martong, Charusso, gamesh411, Szelethus, dkrupp, 
rnkovacs, xazax.hun, whisperity, mgorny.
Herald added a project: clang.
baloghadamsoftware requested review of this revision.

The rules which is the base of this checker is removed from the //Google C++ 
Style Guide// in May: Update C++ styleguide 
. Now this checker became 
obsolete.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D88831

Files:
  clang-tools-extra/clang-tidy/google/CMakeLists.txt
  clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp
  clang-tools-extra/clang-tidy/google/NonConstReferences.cpp
  clang-tools-extra/clang-tidy/google/NonConstReferences.h
  clang-tools-extra/docs/clang-tidy/checks/google-runtime-references.rst
  clang-tools-extra/test/clang-tidy/checkers/google-runtime-references.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/google-runtime-references.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/google-runtime-references.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-// RUN: %check_clang_tidy %s google-runtime-references %t -- \
-// RUN:   -config="{CheckOptions: \
-// RUN: [{key: google-runtime-references.IncludedTypes, \
-// RUN:   value: 'included::A; included::B'}]}"
-
-int a;
-int  = a;
-int *c;
-void f1(int a);
-void f2(int *b);
-void f3(const int );
-void f4(int const );
-
-// Don't warn on implicit operator= in c++11 mode.
-class A {
-  virtual void f() {}
-};
-// Don't warn on rvalue-references.
-struct A2 {
-  A2(A2&&) = default;
-  void f(A2&&) {}
-};
-
-// Don't warn on iostream parameters.
-namespace xxx {
-class istream { };
-class ostringstream { };
-}
-void g1(xxx::istream );
-void g1(xxx::ostringstream );
-
-void g1(int );
-// CHECK-MESSAGES: [[@LINE-1]]:14: warning: non-const reference parameter 'a', make it const or use a pointer [google-runtime-references]
-
-struct s {};
-void g2(int a, int b, s c, s );
-// CHECK-MESSAGES: [[@LINE-1]]:31: warning: non-const reference parameter 'd', {{.*}}
-
-typedef int 
-void g3(ref a);
-// CHECK-MESSAGES: [[@LINE-1]]:13: warning: non-const reference {{.*}}
-
-void g4(int , int , int &);
-// CHECK-MESSAGES: [[@LINE-1]]:14: warning: non-const reference parameter 'a', {{.*}}
-// CHECK-MESSAGES: [[@LINE-2]]:22: warning: non-const reference parameter 'b', {{.*}}
-// CHECK-MESSAGES: [[@LINE-3]]:30: warning: non-const reference parameter at index 2, {{.*}}
-
-class B {
-  B(B& a) {}
-// CHECK-MESSAGES: [[@LINE-1]]:8: warning: non-const reference {{.*}}
-  virtual void f(int ) {}
-// CHECK-MESSAGES: [[@LINE-1]]:23: warning: non-const reference {{.*}}
-  void g(int );
-// CHECK-MESSAGES: [[@LINE-1]]:15: warning: non-const reference {{.*}}
-
-  // Don't warn on the parameter of stream extractors defined as members.
-  B& operator>>(int& val) { return *this; }
-};
-
-// Only warn on the first declaration of each function to reduce duplicate
-// warnings.
-void B::g(int ) {}
-
-// Don't warn on the first parameter of stream inserters.
-A& operator<<(A& s, int&) { return s; }
-// CHECK-MESSAGES: [[@LINE-1]]:25: warning: non-const reference parameter at index 1, {{.*}}
-
-// Don't warn on either parameter of stream extractors. Both need to be
-// non-const references by convention.
-A& operator>>(A& input, int& val) { return input; }
-
-// Don't warn on lambdas.
-auto lambda = [] (int&) {};
-
-// Don't warn on typedefs, as we'll warn on the function itself.
-typedef int (*fp)(int &);
-
-// Don't warn on function references.
-typedef void F();
-void g5(const F& func) {}
-void g6(F& func) {}
-
-template
-void g7(const T& t) {}
-
-template
-void g8(T t) {}
-
-void f5() {
-  g5(f5);
-  g6(f5);
-  g7(f5);
-  g7(f5);
-  g8(f5);
-  g8(f5);
-}
-
-// Don't warn on dependent types.
-template
-void g9(T& t) {}
-template
-void g10(T t) {}
-
-void f6() {
-  int i;
-  float f;
-  g9(i);
-  g9(i);
-  g9(i);
-  g10(i);
-  g10(f);
-}
-
-// Warn only on the overridden methods from the base class, as the child class
-// only implements the interface.
-class C : public B {
-  C();
-  virtual void f(int ) {}
-};
-
-// Don't warn on operator<< with streams-like interface.
-A& operator<<(A& s, int) { return s; }
-
-// Don't warn on swap().
-void swap(C& c1, C& c2) {}
-
-// Don't warn on standalone operator++, operator--, operator+=, operator-=,
-// operator*=, etc. that all need non-const references to be functional.
-A& operator++(A& a) { return a; }
-A operator++(A& a, int) { return a; }
-A& operator--(A& a) { return a; }
-A operator--(A& a, int) { return a; }
-A& operator+=(A& a, const A& b) { return a; }
-A& operator-=(A& a, const A& b) { return a; }
-A& operator*=(A& a, const A& b) { return a; }
-A& operator/=(A& a, const A& b) { return a; }
-A& 

[PATCH] D86743: [analyzer] Ignore VLASizeChecker case that could cause crash

2020-09-30 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware requested changes to this revision.
baloghadamsoftware added a comment.
This revision now requires changes to proceed.

In D86743#2303922 , @NoQ wrote:

> One slightly redeeming thing about this crash is that it's assertion-only. 
> When built without assertions clang doesn't crash and this patch doesn't 
> really change its behavior (adding transition to a null state is equivalent 
> to adding no transitions at all). This means that the assertion did its job 
> and notified us of the serious issue but simply removing the assertion 
> doesn't bring *that* much benefit and we can probably afford to wait for a 
> more solid fix.

Yes, that is right. `CheckerContext::addTransition()` accepts `nullptr`, thus 
with assertions disabled it does exactly what this patch does. Thus I think 
that this patch could be abandoned now, and if the bug is not exactly the same 
as 28450  then a new bug report 
should be filed in //BugZilla//. And maybe the review on D69726 
 could be continued if that is part of the 
proper solution you suggested.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D86743

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


[PATCH] D86743: [analyzer] Ignore VLASizeChecker case that could cause crash

2020-09-30 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

@vabridgers Please try to apply D69726  and 
check whether it solves this crash!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D86743

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


[PATCH] D86743: [analyzer] Ignore VLASizeChecker case that could cause crash

2020-09-30 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

In D86743#2303910 , @NoQ wrote:

>> The last comment for that bug is D69726 , 
>> but the bug is not closed to it seems to me that D69726 
>>  does not solve it, just takes a single 
>> step towards the solution.
>
> It might as well be that the patch isn't, well, committed.

Oh! I mislooked that. I saw `DynamicSize.cpp` already in the repository, but 
that is a prerequisite, not that one. Sorry!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D86743

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


[PATCH] D86743: [analyzer] Ignore VLASizeChecker case that could cause crash

2020-09-30 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

Yes, @NoQ is right. If the constraint manager cannot reason about a value, then 
then `ProgramState::assume()` will return the same state with the new 
assumption in the constraints. Whenever `ProgramState::assume()` returns 
`nullptr` it means that the assumption is impossible. Thus in this case 
`DynSize` and `*ArraySizeNL` cannot be equal. To me this really seems to be a 
similar issue to Bug 28450 . The 
last comment for that bug is D69726 , but the 
bug is not closed to it seems to me that D69726 
 does not solve it, just takes a single step 
towards the solution.

I see that proper solution is somewhat more complicated and requires deep 
knowledge and takes probably much time. However, this one is a core checker, 
and not even //alpha//. Even //alpha// checkers should not crash at all (for me 
//alpha// means many false positives), but a crashing core checker, that is no 
even alpha completely undermines the users' trust towards the Analyzer. Bug 
28450  is open for almost one and 
half years. Thus something quick should be done even before someone implements 
the proper solution (from @NOQ's suggestions the second one is implemented by 
D69726 , but not the first one). A //FIXME// 
must be added in either case, and the misleading comment deleted. Or if this 
solution is completely unacceptable for the community then `VLASizeChecker` 
should be degraded to //alpha//.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D86743

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


[PATCH] D87519: [analyzer][Liveness][NFC] Enqueue the CFGBlocks post-order

2020-09-28 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang/lib/Analysis/LiveVariables.cpp:522
 
-  // FIXME: we should enqueue using post order.
-  for (const CFGBlock *B : cfg->nodes()) {
+  for (const CFGBlock *B : *AC.getAnalysis()) {
 worklist.enqueueBlock(B);

martong wrote:
> xazax.hun wrote:
> > With `BackwardDataflowWorklist`, each  `enqueueBlock` will insert the block 
> > into a `llvm::PriorityQueue`. So regardless of the insertion order, 
> > `dequeue` will return the nodes in the reverse post order. 
> > 
> > Inserting elements in the right order into the heap might be beneficial is 
> > we need to to less work to "heapify". But on the other hand, we did more 
> > work to insert them in the right order, in the first place. All in all, I 
> > am not sure whether the comment is still valid and whether this patch would 
> > provide any benefit over the original code. 
> > 
> Yes, what Gabor says makes sense. On the other hand I don't see any overhead 
> - I might be wrong though - in the post order visitation. And it makes the 
> code more consistent IMHO.
> 
> Well, it would be important to know why the original author put the 
> ```
> // FIXME: we should enqueue using post order.
> ```
> there. The blamed commit 77ff930fff15c3fc76101b38199dad355be0866b is not 
> saying much.
Please compare the execution time with and without this patch. I think it is 
difficult do decide in theory which one costs more: the heapification during 
insertion or the reverse ordering before the insertion.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87519

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


[PATCH] D77229: [Analyzer][NFC] Avoid handling of LazyCompundVals in IteratorModeling

2020-09-28 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

Now I completely know what the source of our misunderstanding is. You thought 
that this patch will **fix** an issue, namely that we store iterator positions 
for both the iterator values and the locations of the iterator variables. While 
this is definitely a wrong approach, it could not be fixed until we got rid 
from the hack with `LazyCompoundVal`s. These functions **keep this existing 
issue** unfixed. However, I could not understand you because I was completely 
focusing on how these functions could **introduce a new issue** and I could not 
find it. No wonder. Thus all my efforts were focused on finding a test cases 
which passed in the earlier versions but fail in this one because of these 
functions. Of course I could not find any and I was continuously proving that 
my patch is correct in the sense that it does not make things worse than they 
were. That is why I implemented the pointer-based iterators (it would have been 
better after this patch and a subsequent one that fixes this issue) where I was 
facing problems because of this wrong approach. In the same time you 
continuously came with new examples which tried to prove the issue, but I could 
not understand it because all these new test cases failed in the master version 
as well. We talked about two very different things because we had very 
different perceptions about the goal of this patch. That was all.


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

https://reviews.llvm.org/D77229

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


[PATCH] D87449: [clang-tidy] Add new check for SEI CERT rule SIG30-C.

2020-09-25 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang-tools-extra/clang-tidy/cert/SignalHandlerCheck.cpp:31
+static bool isSystemCall(const FunctionDecl *FD) {
+  // This check does not work with function calls in std namespace.
+  if (!FD->isGlobal() || FD->isInStdNamespace())

Why? In //C++// we have everything in `std` namespace, such as `std::signal()`, 
`std::abort()` or `std::_Exit()`. In `C++` the general rule is to use them 
instead of the global //C// variants.



Comment at: clang-tools-extra/clang-tidy/cert/SignalHandlerCheck.cpp:35
+  // It is assumed that the function has no other re-declaration that is not
+  // in a system header. Otherwise this may produce wrong result.
+  return FD->getASTContext().getSourceManager().isInSystemHeader(

The assumption is basically right, we do not repeat declarations from system 
headers but maybe we could loop over the redeclaration chain.



Comment at: clang-tools-extra/clang-tidy/cert/SignalHandlerCheck.cpp:40
+
+static bool isAllowedSystemCall(const FunctionDecl *FD) {
+  if (!FD->getIdentifier())

The name suggests that this function checks for both //system call// and 
//allowed call//. I would either rename this function to simply 
`isAllowedCall()` or at least put an assertion to the beginning: 
`assert(isSystemCall(FD));`.



Comment at: clang-tools-extra/clang-tidy/cert/SignalHandlerCheck.cpp:44
+  const StringRef N = FD->getName();
+  if (N == AbortFun || N == ExitFun || N == QuickExitFun || N == SignalFun)
+return true;

Maybe you could use `IdentifierInfo` instead of string comparisons.



Comment at: clang-tools-extra/clang-tidy/cert/SignalHandlerCheck.cpp:81
+  callExpr(IsSignalFunction, HandlerAsSecondArg).bind("register_call"),
+  this);
+}

More readable would be this way:
```
const auto HandlerExpr = 
declRefExpr(hasDeclaration(functionDecl().bind("handler_decl")),
   unless(isExpandedFromMacro("SIG_IGN")),
   unless(isExpandedFromMacro("SIG_DFL")))
  .bind("handler_expr");
Finder->addMatcher(
   callExpr(IsSignalFunction, hasArgument(1, 
HandlerExpr)).bind("register_call"),
   this);
```



Comment at: clang-tools-extra/clang-tidy/cert/SignalHandlerCheck.cpp:95
+  std::deque> CalledFunctions{
+  {HandlerDecl, HandlerExpr}};
+

Do we really need to store `FunctionDecl` in the map? The whole code would be 
much simpler if you only store the call expression and the retrieve the callee 
declaration once at the beginning of the loop body. Beside simplicity this 
would also reduce the memory footprint and surely not increase the execution 
time.



Comment at: clang-tools-extra/docs/clang-tidy/checks/cert-sig30-c.rst:1-17
+.. title:: clang-tidy - cert-sig30-c
+
+cert-sig30-c
+
+
+Finds functions registered as signal handlers that call non asynchronous-safe
+functions. User functions called from the handlers are checked too, as far as

Please add at least one minimal code example. (E.g. from the tests.)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87449

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


[PATCH] D87146: [analyzer] Implement shared semantics checks for XNU functions in PthreadLockChecker

2020-09-25 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

In D87146#2294514 , 
@baloghadamsoftware wrote:

> In D87146#2294423 , @ASDenysPetrov 
> wrote:
>
>> It would be nice if someone had time to look at this. Thanks.
>
> I am just looking, but I am not a `pthread` expert.

Sorry, absolutely no competence.


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

https://reviews.llvm.org/D87146

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


[PATCH] D85351: [Analyzer] Fix for `ExprEngine::computeObjectUnderConstruction()` for base and delegating consturctor initializers

2020-09-25 Thread Balogh , Ádám via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
baloghadamsoftware marked an inline comment as done.
Closed by commit rGfacad21b2983: [Analyzer] Fix for 
`ExprEngine::computeObjectUnderConstruction()` for base and… (authored by 
baloghadamsoftware).

Changed prior to commit:
  https://reviews.llvm.org/D85351?vs=290917=294273#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D85351

Files:
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp

Index: clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
===
--- clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
+++ clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
@@ -23,8 +23,8 @@
   : public Checker {
 public:
   void checkPostCall(const CallEvent , CheckerContext ) const {
-// Only calls with origin expression are checked. These are `returnC()`
-// and C::C().
+// Only calls with origin expression are checked. These are `returnC()`,
+// `returnD()`, C::C() and D::D().
 if (!Call.getOriginExpr())
   return;
 
@@ -35,6 +35,10 @@
 Optional RetVal = Call.getReturnValueUnderConstruction();
 ASSERT_TRUE(RetVal);
 ASSERT_TRUE(RetVal->getAsRegion());
+
+const auto *RetReg = cast(RetVal->getAsRegion());
+const Expr *OrigExpr = Call.getOriginExpr();
+ASSERT_EQ(OrigExpr->getType(), RetReg->getValueType());
   }
 };
 
@@ -51,22 +55,65 @@
 TEST(TestReturnValueUnderConstructionChecker,
  ReturnValueUnderConstructionChecker) {
   EXPECT_TRUE(runCheckerOnCode(
-  R"(class C {
- public:
-   C(int nn): n(nn) {}
-   virtual ~C() {}
- private:
-   int n;
- };
-
- C returnC(int m) {
-   C c(m);
-   return c;
- }
-
- void foo() {
-   C c = returnC(1); 
- })"));
+  R"(class C {
+ public:
+   C(int nn): n(nn) {}
+   virtual ~C() {}
+ private:
+   int n;
+ };
+
+ C returnC(int m) {
+   C c(m);
+   return c;
+ }
+
+ void foo() {
+   C c = returnC(1);
+ })"));
+
+  EXPECT_TRUE(runCheckerOnCode(
+  R"(class C {
+ public:
+   C(int nn): n(nn) {}
+   explicit C(): C(0) {}
+   virtual ~C() {}
+ private:
+   int n;
+ };
+
+ C returnC() {
+   C c;
+   return c;
+ }
+
+ void foo() {
+   C c = returnC();
+ })"));
+
+  EXPECT_TRUE(runCheckerOnCode(
+  R"(class C {
+ public:
+   C(int nn): n(nn) {}
+   virtual ~C() {}
+ private:
+   int n;
+ };
+
+ class D: public C {
+ public:
+   D(int nn): C(nn) {}
+   virtual ~D() {}
+ };
+
+ D returnD(int m) {
+   D d(m);
+   return d;
+ }
+
+ void foo() {
+   D d = returnD(1); 
+ })"));
 }
 
 } // namespace
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -132,10 +132,20 @@
 case ConstructionContext::SimpleConstructorInitializerKind: {
   const auto *ICC = cast(CC);
   const auto *Init = ICC->getCXXCtorInitializer();
-  assert(Init->isAnyMemberInitializer());
   const CXXMethodDecl *CurCtor = cast(LCtx->getDecl());
   Loc ThisPtr = SVB.getCXXThis(CurCtor, LCtx->getStackFrame());
   SVal ThisVal = State->getSVal(ThisPtr);
+  if (Init->isBaseInitializer()) {
+const auto *ThisReg = cast(ThisVal.getAsRegion());
+const CXXRecordDecl *BaseClass =
+  Init->getBaseClass()->getAsCXXRecordDecl();
+const auto *BaseReg =
+  MRMgr.getCXXBaseObjectRegion(BaseClass, ThisReg,
+   Init->isBaseVirtual());
+return SVB.makeLoc(BaseReg);
+  }
+  if (Init->isDelegatingInitializer())
+return ThisVal;
 
   const ValueDecl *Field;
   SVal FieldVal;
@@ -364,6 +374,11 @@
 case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind:
 case ConstructionContext::SimpleConstructorInitializerKind: {
   const auto *ICC = cast(CC);
+  const auto *Init = ICC->getCXXCtorInitializer();
+  // Base and delegating initializers handled above
+  assert(Init->isAnyMemberInitializer() &&
+ "Base and delegating initializers should have been handled by"
+ 

[PATCH] D87146: [analyzer] Implement shared semantics checks for XNU functions in PthreadLockChecker

2020-09-25 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

In D87146#2294423 , @ASDenysPetrov 
wrote:

> It would be nice if someone had time to look at this. Thanks.

I am just looking, but I am not a `pthread` expert.


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

https://reviews.llvm.org/D87146

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


[PATCH] D77229: [Analyzer][NFC] Avoid handling of LazyCompundVals in IteratorModeling

2020-09-25 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

@gamesh411, @whisperity, @martong and others, please suggest me new test cases 
if you think the current ones are not enough.


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

https://reviews.llvm.org/D77229

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


[PATCH] D77229: [Analyzer][NFC] Avoid handling of LazyCompundVals in IteratorModeling

2020-09-25 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

Oh, I think now what do you mean: iterators stored in containers, thus 
iterators iterating over iterators. Yes, the current working of the checker 
does not support it because it stores iterator positions for both the prvalues 
and the glvalues. This is so from the beginning and this patch does not change 
anything about this behavior. Of course, this design concept is questionable, 
we can change it in the future. But not in this patch, this one is purely an 
NFC: it has exactly the same functionality as the previous versions, the only 
difference is that it does not hamper anymore with `LazyCompoundVal`s but 
reaches the real region of the objects (and only in case of objects by value, I 
check the AST type for paramters), exactly as you requested.

Anyway, to me storing iterators in containers sounds dangerous. Iterators are 
like lighted matches which you use and then extinguish. You do not put them 
into the drawer on into a paper box. If you store iterators in a container, how 
can you track which one of them is invalidated? This sounds a very bad practice 
to me.

Anyway, we can change the whole iterator modeling and checking in the future to 
support even this bad practice, but in their current state it is much more 
beneficial for the users to reduce the huge number of false positives and add 
note tags for the reported bugs, I think. Maybe we could better explain the 
current working in the comments at the beginning, and put FIXME-s there. 
Eventually we can also add such test cases, but with the current functionality 
even that cannot be done, because we currently do not keep track the content of 
the containers.


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

https://reviews.llvm.org/D77229

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


[PATCH] D77229: [Analyzer] Avoid handling of LazyCompundVals in IteratorModeling

2020-09-24 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 294156.
baloghadamsoftware added a comment.

Test coverage was hugely increased by rebasing this patch to D88216 
. Two kind of tests failed. This last update 
addreses them:

1. Handle the assignment operator of iterator objects. This is necessary for 
assignments more complex than an assignment to a variable (which is handled by 
`checkBind()`), such as an assignment to a structure/class member.

2. Put back post-checking of `MaterializeTemporaryExpr`. This special kind of 
expression is not only used to materialize temporary expressions from 
`LazyCompoundVal`s but also for temporaries as return values.

Furthermore I added some comments explaining the functions which retrieve an 
iterator argument and iterator return value.

Now all tests pass again with the increased coverage. @NoQ if you are still in 
doubt, please suggest me further test cases to explore. I understand your 
concerns but cannot address them without some suggestions where my solution 
could fail.


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

https://reviews.llvm.org/D77229

Files:
  clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.h
  clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
  clang/test/Analysis/iterator-modeling.cpp

Index: clang/test/Analysis/iterator-modeling.cpp
===
--- clang/test/Analysis/iterator-modeling.cpp
+++ clang/test/Analysis/iterator-modeling.cpp
@@ -42,7 +42,7 @@
 
   if (i != v.begin()) {
 clang_analyzer_warnIfReached();
-  }
+}
 }
 
 void end(const std::vector ) {
@@ -1034,6 +1034,7 @@
 
   clang_analyzer_express(clang_analyzer_iterator_position(i0)); // expected-warning-re {{$V.begin(){{$
   // clang_analyzer_express(clang_analyzer_iterator_position(i3)); FIXME: expecte warning $i1 - 1
+
 }
 
 void vector_insert_ahead_of_end(std::vector , int n) {
@@ -1942,6 +1943,55 @@
   clang_analyzer_eval(clang_analyzer_iterator_container(j) == ); // expected-warning{{TRUE}}
 }
 
+template 
+struct delegated_ctor_iterator {
+  delegated_ctor_iterator(const T&, int);
+  delegated_ctor_iterator(const T& t) : delegated_ctor_iterator(t, 0) {}
+  delegated_ctor_iterator operator++();
+  delegated_ctor_iterator operator++(int);
+  T& operator*();
+};
+
+template 
+struct container_with_delegated_ctor_iterator {
+  typedef delegated_ctor_iterator iterator;
+  iterator begin() const { return delegated_ctor_iterator(T()); }
+};
+
+void
+test_delegated_ctor_iterator(
+const container_with_delegated_ctor_iterator ) {
+  auto i = c.begin(); // no-crash
+  clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()");
+  clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.begin()}}
+}
+
+template 
+struct base_ctor_iterator {
+  base_ctor_iterator(const T&);
+  base_ctor_iterator operator++();
+  base_ctor_iterator operator++(int);
+  T& operator*();
+};
+
+template 
+struct derived_ctor_iterator: public base_ctor_iterator {
+  derived_ctor_iterator(const T& t) : base_ctor_iterator(t) {}
+};
+
+template 
+struct container_with_derived_ctor_iterator {
+  typedef derived_ctor_iterator iterator;
+  iterator begin() const { return derived_ctor_iterator(T()); }
+};
+
+void
+test_derived_ctor_iterator(const container_with_derived_ctor_iterator ) {
+  auto i = c.begin();
+  clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()");
+  clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.begin()}}
+}
+
 void clang_analyzer_printState();
 
 void print_state(std::vector ) {
Index: clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
@@ -24,12 +24,12 @@
 namespace {
 
 class STLAlgorithmModeling : public Checker {
-  bool evalFind(CheckerContext , const CallExpr *CE) const;
+  void evalFind(CheckerContext , const CallExpr *CE, SVal Begin,
+SVal End) const;
 
-  void Find(CheckerContext , const CallExpr *CE, unsigned paramNum) const;
-
-  using FnCheck = bool (STLAlgorithmModeling::*)(CheckerContext &,
-const CallExpr *) const;
+  using FnCheck = void (STLAlgorithmModeling::*)(CheckerContext &,
+ const CallExpr *, SVal Begin,
+   

[PATCH] D77229: [Analyzer] Avoid handling of LazyCompundVals in IteratorModeling

2020-09-24 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/Iterator.cpp:330-336
+SVal getReturnIterator(const CallEvent ) {
+  Optional RetValUnderConstr = Call.getReturnValueUnderConstruction();
+  if (RetValUnderConstr.hasValue())
+return *RetValUnderConstr;
+
+  return Call.getReturnValue();
+}

baloghadamsoftware wrote:
> baloghadamsoftware wrote:
> > NoQ wrote:
> > > baloghadamsoftware wrote:
> > > > baloghadamsoftware wrote:
> > > > > NoQ wrote:
> > > > > > baloghadamsoftware wrote:
> > > > > > > NoQ wrote:
> > > > > > > > NoQ wrote:
> > > > > > > > > NoQ wrote:
> > > > > > > > > > I still believe you have not addressed the problem while 
> > > > > > > > > > moving the functions from D81718 to this patch. The caller 
> > > > > > > > > > of this function has no way of knowing whether the return 
> > > > > > > > > > value is the prvalue of the iterator or the glvalue of the 
> > > > > > > > > > iterator.
> > > > > > > > > > 
> > > > > > > > > > Looks like most callers are safe because they expect the 
> > > > > > > > > > object of interest to also be already tracked. But it's 
> > > > > > > > > > quite possible that both are tracked, say:
> > > > > > > > > > 
> > > > > > > > > > ```lang=c++
> > > > > > > > > >   Container1 container1 = ...;
> > > > > > > > > >   Container2 container2 = { 
> > > > > > > > > > container1.begin() };
> > > > > > > > > >   container2.begin(); // ???
> > > > > > > > > > ```
> > > > > > > > > > 
> > > > > > > > > > Suppose `Container1::iterator` is implemented as an object 
> > > > > > > > > > and `Container2::iterator` is implemented as a pointer. In 
> > > > > > > > > > this case `getIteratorPosition(getReturnIterator())` would 
> > > > > > > > > > yield the position of `container1.begin()` whereas the 
> > > > > > > > > > correct answer is the position of `container2.begin()`.
> > > > > > > > > > 
> > > > > > > > > > This problem may seem artificial but it is trivial to avoid 
> > > > > > > > > > if you simply stop defending your convoluted solution of 
> > > > > > > > > > looking at value classes instead of AST types.
> > > > > > > > > Ugh, the problem is much worse. D82185 is entirely broken for 
> > > > > > > > > the exact reason i described above and you only didn't notice 
> > > > > > > > > it because you wrote almost no tests.
> > > > > > > > > 
> > > > > > > > > Consider the test you've added in D82185:
> > > > > > > > > 
> > > > > > > > > ```lang=c++
> > > > > > > > > void begin_ptr_iterator(const cont_with_ptr_iterator ) 
> > > > > > > > > {
> > > > > > > > >   auto i = c.begin();
> > > > > > > > > 
> > > > > > > > >   clang_analyzer_eval(clang_analyzer_iterator_container(i) == 
> > > > > > > > > ); // expected-warning{{TRUE}}
> > > > > > > > > }
> > > > > > > > > ```
> > > > > > > > > 
> > > > > > > > > It breaks very easily if you modify it slightly:
> > > > > > > > > ```lang=c++
> > > > > > > > > void begin_ptr_iterator(const cont_with_ptr_iterator ) 
> > > > > > > > > {
> > > > > > > > >   auto i = c.begin();
> > > > > > > > >   ++i; // <==
> > > > > > > > > 
> > > > > > > > >   clang_analyzer_eval(clang_analyzer_iterator_container(i) == 
> > > > > > > > > ); // Says FALSE!
> > > > > > > > > }
> > > > > > > > > ```
> > > > > > > > > The iterator obviously still points to the same container, so 
> > > > > > > > > why does the test fail? Because you're tracking the wrong 
> > > > > > > > > iterator: you treated your `{conj_$3}` as a glvalue 
> > > > > > > > > whereas you should have treated it as a prvalue. In other 
> > > > > > > > > words, your checker thinks that `{conj_$3}` is the 
> > > > > > > > > location of an iterator object rather than the iterator 
> > > > > > > > > itself, and after you increment the pointer it thinks that 
> > > > > > > > > it's a completely unrelated iterator.
> > > > > > > > > 
> > > > > > > > > There's a separate concern about why does it say `FALSE` 
> > > > > > > > > (should be `UNKNOWN`) but you get the point.
> > > > > > > > The better way to test D82185 would be to make all existing 
> > > > > > > > tests with iterator objects pass with iterator pointers as 
> > > > > > > > well. Like, make existing container mocks use either iterator 
> > > > > > > > objects or iterator pointers depending on a macro and make two 
> > > > > > > > run-lines in each test file, one with `-D` and one without it. 
> > > > > > > > Most of the old tests should have worked out of the box if you 
> > > > > > > > did it right; the few that don't pass would be hidden under 
> > > > > > > > #ifdef for future investigation.
> > > > > > > Thank you for your review and especially for this tip! It is 
> > > > > > > really a good idea. I changed it now and it indeed shows the 
> > > > > > > problem you reported. It seems that my checker mixes up the 
> > > > > > > region of the pointer-typed variable (`` and ``) with the 
> > > > > > > region they point to (`{reg_$1 > > > > > > 

[PATCH] D77229: [Analyzer] Avoid handling of LazyCompundVals in IteratorModeling

2020-09-24 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/Iterator.cpp:330-336
+SVal getReturnIterator(const CallEvent ) {
+  Optional RetValUnderConstr = Call.getReturnValueUnderConstruction();
+  if (RetValUnderConstr.hasValue())
+return *RetValUnderConstr;
+
+  return Call.getReturnValue();
+}

baloghadamsoftware wrote:
> NoQ wrote:
> > baloghadamsoftware wrote:
> > > baloghadamsoftware wrote:
> > > > NoQ wrote:
> > > > > baloghadamsoftware wrote:
> > > > > > NoQ wrote:
> > > > > > > NoQ wrote:
> > > > > > > > NoQ wrote:
> > > > > > > > > I still believe you have not addressed the problem while 
> > > > > > > > > moving the functions from D81718 to this patch. The caller of 
> > > > > > > > > this function has no way of knowing whether the return value 
> > > > > > > > > is the prvalue of the iterator or the glvalue of the iterator.
> > > > > > > > > 
> > > > > > > > > Looks like most callers are safe because they expect the 
> > > > > > > > > object of interest to also be already tracked. But it's quite 
> > > > > > > > > possible that both are tracked, say:
> > > > > > > > > 
> > > > > > > > > ```lang=c++
> > > > > > > > >   Container1 container1 = ...;
> > > > > > > > >   Container2 container2 = { 
> > > > > > > > > container1.begin() };
> > > > > > > > >   container2.begin(); // ???
> > > > > > > > > ```
> > > > > > > > > 
> > > > > > > > > Suppose `Container1::iterator` is implemented as an object 
> > > > > > > > > and `Container2::iterator` is implemented as a pointer. In 
> > > > > > > > > this case `getIteratorPosition(getReturnIterator())` would 
> > > > > > > > > yield the position of `container1.begin()` whereas the 
> > > > > > > > > correct answer is the position of `container2.begin()`.
> > > > > > > > > 
> > > > > > > > > This problem may seem artificial but it is trivial to avoid 
> > > > > > > > > if you simply stop defending your convoluted solution of 
> > > > > > > > > looking at value classes instead of AST types.
> > > > > > > > Ugh, the problem is much worse. D82185 is entirely broken for 
> > > > > > > > the exact reason i described above and you only didn't notice 
> > > > > > > > it because you wrote almost no tests.
> > > > > > > > 
> > > > > > > > Consider the test you've added in D82185:
> > > > > > > > 
> > > > > > > > ```lang=c++
> > > > > > > > void begin_ptr_iterator(const cont_with_ptr_iterator ) {
> > > > > > > >   auto i = c.begin();
> > > > > > > > 
> > > > > > > >   clang_analyzer_eval(clang_analyzer_iterator_container(i) == 
> > > > > > > > ); // expected-warning{{TRUE}}
> > > > > > > > }
> > > > > > > > ```
> > > > > > > > 
> > > > > > > > It breaks very easily if you modify it slightly:
> > > > > > > > ```lang=c++
> > > > > > > > void begin_ptr_iterator(const cont_with_ptr_iterator ) {
> > > > > > > >   auto i = c.begin();
> > > > > > > >   ++i; // <==
> > > > > > > > 
> > > > > > > >   clang_analyzer_eval(clang_analyzer_iterator_container(i) == 
> > > > > > > > ); // Says FALSE!
> > > > > > > > }
> > > > > > > > ```
> > > > > > > > The iterator obviously still points to the same container, so 
> > > > > > > > why does the test fail? Because you're tracking the wrong 
> > > > > > > > iterator: you treated your `{conj_$3}` as a glvalue 
> > > > > > > > whereas you should have treated it as a prvalue. In other 
> > > > > > > > words, your checker thinks that `{conj_$3}` is the 
> > > > > > > > location of an iterator object rather than the iterator itself, 
> > > > > > > > and after you increment the pointer it thinks that it's a 
> > > > > > > > completely unrelated iterator.
> > > > > > > > 
> > > > > > > > There's a separate concern about why does it say `FALSE` 
> > > > > > > > (should be `UNKNOWN`) but you get the point.
> > > > > > > The better way to test D82185 would be to make all existing tests 
> > > > > > > with iterator objects pass with iterator pointers as well. Like, 
> > > > > > > make existing container mocks use either iterator objects or 
> > > > > > > iterator pointers depending on a macro and make two run-lines in 
> > > > > > > each test file, one with `-D` and one without it. Most of the old 
> > > > > > > tests should have worked out of the box if you did it right; the 
> > > > > > > few that don't pass would be hidden under #ifdef for future 
> > > > > > > investigation.
> > > > > > Thank you for your review and especially for this tip! It is really 
> > > > > > a good idea. I changed it now and it indeed shows the problem you 
> > > > > > reported. It seems that my checker mixes up the region of the 
> > > > > > pointer-typed variable (`` and ``) with the region they point 
> > > > > > to (`{reg_$1 > > > > > std::vector & v>}._start>}` for `i` before the increment and 
> > > > > > `{SymRegion{reg_$1 > > > > > std::vector & v>}._start>},1 S64b,int}` for both `i` and `j` 
> > > > > > after the increment).
> > > > > > 
> > > > > > What I fail to see and I am asking you 

[PATCH] D88216: [Analyzer] Fix handling of pointer-based iterator increments and decrements

2020-09-24 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware created this revision.
baloghadamsoftware added a reviewer: NoQ.
baloghadamsoftware added a project: clang.
Herald added subscribers: ASDenysPetrov, martong, steakhal, Charusso, 
gamesh411, dkrupp, donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, 
szepet, xazax.hun, whisperity.
Herald added a reviewer: Szelethus.
baloghadamsoftware requested review of this revision.

The handling of iterators implemented as pointers were incorrectly handled in 
the increment and decrement operations because these operations did not handle 
the lvalue of the iterator correctly. This patch fixes that issue and extends 
the test coverage for such kind of iterators by adding an option to the 
simulated `std::vector` to implement its iterator as a pointer.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D88216

Files:
  clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/diagnostics/explicit-suppression.cpp
  clang/test/Analysis/invalidated-iterator.cpp
  clang/test/Analysis/iterator-modeling.cpp
  clang/test/Analysis/iterator-range.cpp
  clang/test/Analysis/mismatched-iterator.cpp
  clang/test/Analysis/smart-ptr-text-output.cpp

Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -80,7 +80,7 @@
 void derefOnStdSwappedNullPtr() {
   std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
   std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
-  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:979 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
+  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:993 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
   // expected-note@-1 {{Calling 'swap'}}
   // expected-note@-2 {{Returning from 'swap'}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
Index: clang/test/Analysis/mismatched-iterator.cpp
===
--- clang/test/Analysis/mismatched-iterator.cpp
+++ clang/test/Analysis/mismatched-iterator.cpp
@@ -1,5 +1,7 @@
 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.MismatchedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -verify
 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.MismatchedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.MismatchedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false -DSTD_VECTOR_ITERATOR_PTR %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.MismatchedIterator -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 -DSTD_VECTOR_ITERATOR_PTR %s -verify
 
 #include "Inputs/system-header-simulator-cxx.h"
 
Index: clang/test/Analysis/iterator-range.cpp
===
--- clang/test/Analysis/iterator-range.cpp
+++ clang/test/Analysis/iterator-range.cpp
@@ -1,5 +1,7 @@
 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false -analyzer-output=text %s -verify
 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 -analyzer-output=text %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false -DSTD_VECTOR_ITERATOR_PTR -analyzer-output=text %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 -DSTD_VECTOR_ITERATOR_PTR -analyzer-output=text %s -verify
 
 #include "Inputs/system-header-simulator-cxx.h"
 
@@ -9,30 +11,30 @@
 
 void deref_begin(const std::vector ) {
   auto i = V.begin();
-  *i; // no-warning
+  int n = *i; // no-warning
 }
 
 void deref_begind_begin(const std::vector ) {
-  auto i = 

[PATCH] D77229: [Analyzer] Avoid handling of LazyCompundVals in IteratorModeling

2020-09-24 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/Iterator.cpp:330-336
+SVal getReturnIterator(const CallEvent ) {
+  Optional RetValUnderConstr = Call.getReturnValueUnderConstruction();
+  if (RetValUnderConstr.hasValue())
+return *RetValUnderConstr;
+
+  return Call.getReturnValue();
+}

NoQ wrote:
> baloghadamsoftware wrote:
> > baloghadamsoftware wrote:
> > > NoQ wrote:
> > > > baloghadamsoftware wrote:
> > > > > NoQ wrote:
> > > > > > NoQ wrote:
> > > > > > > NoQ wrote:
> > > > > > > > I still believe you have not addressed the problem while moving 
> > > > > > > > the functions from D81718 to this patch. The caller of this 
> > > > > > > > function has no way of knowing whether the return value is the 
> > > > > > > > prvalue of the iterator or the glvalue of the iterator.
> > > > > > > > 
> > > > > > > > Looks like most callers are safe because they expect the object 
> > > > > > > > of interest to also be already tracked. But it's quite possible 
> > > > > > > > that both are tracked, say:
> > > > > > > > 
> > > > > > > > ```lang=c++
> > > > > > > >   Container1 container1 = ...;
> > > > > > > >   Container2 container2 = { 
> > > > > > > > container1.begin() };
> > > > > > > >   container2.begin(); // ???
> > > > > > > > ```
> > > > > > > > 
> > > > > > > > Suppose `Container1::iterator` is implemented as an object and 
> > > > > > > > `Container2::iterator` is implemented as a pointer. In this 
> > > > > > > > case `getIteratorPosition(getReturnIterator())` would yield the 
> > > > > > > > position of `container1.begin()` whereas the correct answer is 
> > > > > > > > the position of `container2.begin()`.
> > > > > > > > 
> > > > > > > > This problem may seem artificial but it is trivial to avoid if 
> > > > > > > > you simply stop defending your convoluted solution of looking 
> > > > > > > > at value classes instead of AST types.
> > > > > > > Ugh, the problem is much worse. D82185 is entirely broken for the 
> > > > > > > exact reason i described above and you only didn't notice it 
> > > > > > > because you wrote almost no tests.
> > > > > > > 
> > > > > > > Consider the test you've added in D82185:
> > > > > > > 
> > > > > > > ```lang=c++
> > > > > > > void begin_ptr_iterator(const cont_with_ptr_iterator ) {
> > > > > > >   auto i = c.begin();
> > > > > > > 
> > > > > > >   clang_analyzer_eval(clang_analyzer_iterator_container(i) == 
> > > > > > > ); // expected-warning{{TRUE}}
> > > > > > > }
> > > > > > > ```
> > > > > > > 
> > > > > > > It breaks very easily if you modify it slightly:
> > > > > > > ```lang=c++
> > > > > > > void begin_ptr_iterator(const cont_with_ptr_iterator ) {
> > > > > > >   auto i = c.begin();
> > > > > > >   ++i; // <==
> > > > > > > 
> > > > > > >   clang_analyzer_eval(clang_analyzer_iterator_container(i) == 
> > > > > > > ); // Says FALSE!
> > > > > > > }
> > > > > > > ```
> > > > > > > The iterator obviously still points to the same container, so why 
> > > > > > > does the test fail? Because you're tracking the wrong iterator: 
> > > > > > > you treated your `{conj_$3}` as a glvalue whereas you 
> > > > > > > should have treated it as a prvalue. In other words, your checker 
> > > > > > > thinks that `{conj_$3}` is the location of an iterator 
> > > > > > > object rather than the iterator itself, and after you increment 
> > > > > > > the pointer it thinks that it's a completely unrelated iterator.
> > > > > > > 
> > > > > > > There's a separate concern about why does it say `FALSE` (should 
> > > > > > > be `UNKNOWN`) but you get the point.
> > > > > > The better way to test D82185 would be to make all existing tests 
> > > > > > with iterator objects pass with iterator pointers as well. Like, 
> > > > > > make existing container mocks use either iterator objects or 
> > > > > > iterator pointers depending on a macro and make two run-lines in 
> > > > > > each test file, one with `-D` and one without it. Most of the old 
> > > > > > tests should have worked out of the box if you did it right; the 
> > > > > > few that don't pass would be hidden under #ifdef for future 
> > > > > > investigation.
> > > > > Thank you for your review and especially for this tip! It is really a 
> > > > > good idea. I changed it now and it indeed shows the problem you 
> > > > > reported. It seems that my checker mixes up the region of the 
> > > > > pointer-typed variable (`` and ``) with the region they point to 
> > > > > (`{reg_$1 & 
> > > > > v>}._start>}` for `i` before the increment and 
> > > > > `{SymRegion{reg_$1 > > > > std::vector & v>}._start>},1 S64b,int}` for both `i` and `j` 
> > > > > after the increment).
> > > > > 
> > > > > What I fail to see and I am asking you help in it is that the 
> > > > > relation between this problem and the `getReturnIterator()` function. 
> > > > > This function retrieves the object from the construction context if 
> > > > > there is one, but for plain 

[PATCH] D77229: [Analyzer] Avoid handling of LazyCompundVals in IteratorModeling

2020-09-23 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/Iterator.cpp:330-336
+SVal getReturnIterator(const CallEvent ) {
+  Optional RetValUnderConstr = Call.getReturnValueUnderConstruction();
+  if (RetValUnderConstr.hasValue())
+return *RetValUnderConstr;
+
+  return Call.getReturnValue();
+}

baloghadamsoftware wrote:
> NoQ wrote:
> > baloghadamsoftware wrote:
> > > NoQ wrote:
> > > > NoQ wrote:
> > > > > NoQ wrote:
> > > > > > I still believe you have not addressed the problem while moving the 
> > > > > > functions from D81718 to this patch. The caller of this function 
> > > > > > has no way of knowing whether the return value is the prvalue of 
> > > > > > the iterator or the glvalue of the iterator.
> > > > > > 
> > > > > > Looks like most callers are safe because they expect the object of 
> > > > > > interest to also be already tracked. But it's quite possible that 
> > > > > > both are tracked, say:
> > > > > > 
> > > > > > ```lang=c++
> > > > > >   Container1 container1 = ...;
> > > > > >   Container2 container2 = { 
> > > > > > container1.begin() };
> > > > > >   container2.begin(); // ???
> > > > > > ```
> > > > > > 
> > > > > > Suppose `Container1::iterator` is implemented as an object and 
> > > > > > `Container2::iterator` is implemented as a pointer. In this case 
> > > > > > `getIteratorPosition(getReturnIterator())` would yield the position 
> > > > > > of `container1.begin()` whereas the correct answer is the position 
> > > > > > of `container2.begin()`.
> > > > > > 
> > > > > > This problem may seem artificial but it is trivial to avoid if you 
> > > > > > simply stop defending your convoluted solution of looking at value 
> > > > > > classes instead of AST types.
> > > > > Ugh, the problem is much worse. D82185 is entirely broken for the 
> > > > > exact reason i described above and you only didn't notice it because 
> > > > > you wrote almost no tests.
> > > > > 
> > > > > Consider the test you've added in D82185:
> > > > > 
> > > > > ```lang=c++
> > > > > void begin_ptr_iterator(const cont_with_ptr_iterator ) {
> > > > >   auto i = c.begin();
> > > > > 
> > > > >   clang_analyzer_eval(clang_analyzer_iterator_container(i) == ); // 
> > > > > expected-warning{{TRUE}}
> > > > > }
> > > > > ```
> > > > > 
> > > > > It breaks very easily if you modify it slightly:
> > > > > ```lang=c++
> > > > > void begin_ptr_iterator(const cont_with_ptr_iterator ) {
> > > > >   auto i = c.begin();
> > > > >   ++i; // <==
> > > > > 
> > > > >   clang_analyzer_eval(clang_analyzer_iterator_container(i) == ); // 
> > > > > Says FALSE!
> > > > > }
> > > > > ```
> > > > > The iterator obviously still points to the same container, so why 
> > > > > does the test fail? Because you're tracking the wrong iterator: you 
> > > > > treated your `{conj_$3}` as a glvalue whereas you should 
> > > > > have treated it as a prvalue. In other words, your checker thinks 
> > > > > that `{conj_$3}` is the location of an iterator object 
> > > > > rather than the iterator itself, and after you increment the pointer 
> > > > > it thinks that it's a completely unrelated iterator.
> > > > > 
> > > > > There's a separate concern about why does it say `FALSE` (should be 
> > > > > `UNKNOWN`) but you get the point.
> > > > The better way to test D82185 would be to make all existing tests with 
> > > > iterator objects pass with iterator pointers as well. Like, make 
> > > > existing container mocks use either iterator objects or iterator 
> > > > pointers depending on a macro and make two run-lines in each test file, 
> > > > one with `-D` and one without it. Most of the old tests should have 
> > > > worked out of the box if you did it right; the few that don't pass 
> > > > would be hidden under #ifdef for future investigation.
> > > Thank you for your review and especially for this tip! It is really a 
> > > good idea. I changed it now and it indeed shows the problem you reported. 
> > > It seems that my checker mixes up the region of the pointer-typed 
> > > variable (`` and ``) with the region they point to 
> > > (`{reg_$1 & 
> > > v>}._start>}` for `i` before the increment and 
> > > `{SymRegion{reg_$1 
> > > & v>}._start>},1 S64b,int}` for both `i` and `j` after the increment).
> > > 
> > > What I fail to see and I am asking you help in it is that the relation 
> > > between this problem and the `getReturnIterator()` function. This 
> > > function retrieves the object from the construction context if there is 
> > > one, but for plain pointers there is never one. Thus this function is 
> > > always `Call.getReturnValue()` like before this patch.
> > > I am asking you help
> > 
> > I spent way more time on that already than i find reasonable. Please figure 
> > this out on your own by fixing the bug.
> I do not see why I got so a rude answer. I was just asking help in //seeing 
> the relation between the bug and this function//. Because I do not see 

[PATCH] D77229: [Analyzer] Avoid handling of LazyCompundVals in IteratorModeling

2020-09-23 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/Iterator.cpp:330-336
+SVal getReturnIterator(const CallEvent ) {
+  Optional RetValUnderConstr = Call.getReturnValueUnderConstruction();
+  if (RetValUnderConstr.hasValue())
+return *RetValUnderConstr;
+
+  return Call.getReturnValue();
+}

NoQ wrote:
> baloghadamsoftware wrote:
> > NoQ wrote:
> > > NoQ wrote:
> > > > NoQ wrote:
> > > > > I still believe you have not addressed the problem while moving the 
> > > > > functions from D81718 to this patch. The caller of this function has 
> > > > > no way of knowing whether the return value is the prvalue of the 
> > > > > iterator or the glvalue of the iterator.
> > > > > 
> > > > > Looks like most callers are safe because they expect the object of 
> > > > > interest to also be already tracked. But it's quite possible that 
> > > > > both are tracked, say:
> > > > > 
> > > > > ```lang=c++
> > > > >   Container1 container1 = ...;
> > > > >   Container2 container2 = { container1.begin() 
> > > > > };
> > > > >   container2.begin(); // ???
> > > > > ```
> > > > > 
> > > > > Suppose `Container1::iterator` is implemented as an object and 
> > > > > `Container2::iterator` is implemented as a pointer. In this case 
> > > > > `getIteratorPosition(getReturnIterator())` would yield the position 
> > > > > of `container1.begin()` whereas the correct answer is the position of 
> > > > > `container2.begin()`.
> > > > > 
> > > > > This problem may seem artificial but it is trivial to avoid if you 
> > > > > simply stop defending your convoluted solution of looking at value 
> > > > > classes instead of AST types.
> > > > Ugh, the problem is much worse. D82185 is entirely broken for the exact 
> > > > reason i described above and you only didn't notice it because you 
> > > > wrote almost no tests.
> > > > 
> > > > Consider the test you've added in D82185:
> > > > 
> > > > ```lang=c++
> > > > void begin_ptr_iterator(const cont_with_ptr_iterator ) {
> > > >   auto i = c.begin();
> > > > 
> > > >   clang_analyzer_eval(clang_analyzer_iterator_container(i) == ); // 
> > > > expected-warning{{TRUE}}
> > > > }
> > > > ```
> > > > 
> > > > It breaks very easily if you modify it slightly:
> > > > ```lang=c++
> > > > void begin_ptr_iterator(const cont_with_ptr_iterator ) {
> > > >   auto i = c.begin();
> > > >   ++i; // <==
> > > > 
> > > >   clang_analyzer_eval(clang_analyzer_iterator_container(i) == ); // 
> > > > Says FALSE!
> > > > }
> > > > ```
> > > > The iterator obviously still points to the same container, so why does 
> > > > the test fail? Because you're tracking the wrong iterator: you treated 
> > > > your `{conj_$3}` as a glvalue whereas you should have treated 
> > > > it as a prvalue. In other words, your checker thinks that 
> > > > `{conj_$3}` is the location of an iterator object rather than 
> > > > the iterator itself, and after you increment the pointer it thinks that 
> > > > it's a completely unrelated iterator.
> > > > 
> > > > There's a separate concern about why does it say `FALSE` (should be 
> > > > `UNKNOWN`) but you get the point.
> > > The better way to test D82185 would be to make all existing tests with 
> > > iterator objects pass with iterator pointers as well. Like, make existing 
> > > container mocks use either iterator objects or iterator pointers 
> > > depending on a macro and make two run-lines in each test file, one with 
> > > `-D` and one without it. Most of the old tests should have worked out of 
> > > the box if you did it right; the few that don't pass would be hidden 
> > > under #ifdef for future investigation.
> > Thank you for your review and especially for this tip! It is really a good 
> > idea. I changed it now and it indeed shows the problem you reported. It 
> > seems that my checker mixes up the region of the pointer-typed variable 
> > (`` and ``) with the region they point to (`{reg_$1 > SymRegion{reg_$0 & v>}._start>}` for `i` before the 
> > increment and `{SymRegion{reg_$1 > std::vector & v>}._start>},1 S64b,int}` for both `i` and `j` after the 
> > increment).
> > 
> > What I fail to see and I am asking you help in it is that the relation 
> > between this problem and the `getReturnIterator()` function. This function 
> > retrieves the object from the construction context if there is one, but for 
> > plain pointers there is never one. Thus this function is always 
> > `Call.getReturnValue()` like before this patch.
> > I am asking you help
> 
> I spent way more time on that already than i find reasonable. Please figure 
> this out on your own by fixing the bug.
I do not see why I got so a rude answer. I was just asking help in //seeing the 
relation between the bug and this function//. Because I do not see any. I think 
the bug is somewhere in handling unary and binary operators for pointers. I 
struggled with that part for this same reason and I thought I solved it but now 
I see that I 

[PATCH] D77229: [Analyzer] Avoid handling of LazyCompundVals in IteratorModeling

2020-09-22 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware marked an inline comment as done.
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/Iterator.cpp:330-336
+SVal getReturnIterator(const CallEvent ) {
+  Optional RetValUnderConstr = Call.getReturnValueUnderConstruction();
+  if (RetValUnderConstr.hasValue())
+return *RetValUnderConstr;
+
+  return Call.getReturnValue();
+}

NoQ wrote:
> NoQ wrote:
> > NoQ wrote:
> > > I still believe you have not addressed the problem while moving the 
> > > functions from D81718 to this patch. The caller of this function has no 
> > > way of knowing whether the return value is the prvalue of the iterator or 
> > > the glvalue of the iterator.
> > > 
> > > Looks like most callers are safe because they expect the object of 
> > > interest to also be already tracked. But it's quite possible that both 
> > > are tracked, say:
> > > 
> > > ```lang=c++
> > >   Container1 container1 = ...;
> > >   Container2 container2 = { container1.begin() };
> > >   container2.begin(); // ???
> > > ```
> > > 
> > > Suppose `Container1::iterator` is implemented as an object and 
> > > `Container2::iterator` is implemented as a pointer. In this case 
> > > `getIteratorPosition(getReturnIterator())` would yield the position of 
> > > `container1.begin()` whereas the correct answer is the position of 
> > > `container2.begin()`.
> > > 
> > > This problem may seem artificial but it is trivial to avoid if you simply 
> > > stop defending your convoluted solution of looking at value classes 
> > > instead of AST types.
> > Ugh, the problem is much worse. D82185 is entirely broken for the exact 
> > reason i described above and you only didn't notice it because you wrote 
> > almost no tests.
> > 
> > Consider the test you've added in D82185:
> > 
> > ```lang=c++
> > void begin_ptr_iterator(const cont_with_ptr_iterator ) {
> >   auto i = c.begin();
> > 
> >   clang_analyzer_eval(clang_analyzer_iterator_container(i) == ); // 
> > expected-warning{{TRUE}}
> > }
> > ```
> > 
> > It breaks very easily if you modify it slightly:
> > ```lang=c++
> > void begin_ptr_iterator(const cont_with_ptr_iterator ) {
> >   auto i = c.begin();
> >   ++i; // <==
> > 
> >   clang_analyzer_eval(clang_analyzer_iterator_container(i) == ); // Says 
> > FALSE!
> > }
> > ```
> > The iterator obviously still points to the same container, so why does the 
> > test fail? Because you're tracking the wrong iterator: you treated your 
> > `{conj_$3}` as a glvalue whereas you should have treated it as a 
> > prvalue. In other words, your checker thinks that `{conj_$3}` is 
> > the location of an iterator object rather than the iterator itself, and 
> > after you increment the pointer it thinks that it's a completely unrelated 
> > iterator.
> > 
> > There's a separate concern about why does it say `FALSE` (should be 
> > `UNKNOWN`) but you get the point.
> The better way to test D82185 would be to make all existing tests with 
> iterator objects pass with iterator pointers as well. Like, make existing 
> container mocks use either iterator objects or iterator pointers depending on 
> a macro and make two run-lines in each test file, one with `-D` and one 
> without it. Most of the old tests should have worked out of the box if you 
> did it right; the few that don't pass would be hidden under #ifdef for future 
> investigation.
Thank you for your review and especially for this tip! It is really a good 
idea. I changed it now and it indeed shows the problem you reported. It seems 
that my checker mixes up the region of the pointer-typed variable (`` and 
``) with the region they point to (`{reg_$1 & v>}._start>}` for `i` before the 
increment and `{SymRegion{reg_$1 & v>}._start>},1 S64b,int}` for both `i` and `j` after the 
increment).

What I fail to see and I am asking you help in it is that the relation between 
this problem and the `getReturnIterator()` function. This function retrieves 
the object from the construction context if there is one, but for plain 
pointers there is never one. Thus this function is always 
`Call.getReturnValue()` like before this patch.


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

https://reviews.llvm.org/D77229

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


[PATCH] D76604: [Analyzer] Model `size()` member function of containers

2020-09-21 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 293183.
baloghadamsoftware added a comment.

New test cases added.


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

https://reviews.llvm.org/D76604

Files:
  clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.h
  clang/test/Analysis/container-modeling.cpp

Index: clang/test/Analysis/container-modeling.cpp
===
--- clang/test/Analysis/container-modeling.cpp
+++ clang/test/Analysis/container-modeling.cpp
@@ -14,6 +14,7 @@
 void clang_analyzer_denote(long, const char*);
 void clang_analyzer_express(long);
 void clang_analyzer_eval(bool);
+void clang_analyzer_dump(std::size_t);
 void clang_analyzer_warnIfReached();
 
 extern void __assert_fail (__const char *__assertion, __const char *__file,
@@ -104,6 +105,125 @@
   // expected-note@-3   {{FALSE}}
 }
 
+// size()
+
+void size0(const std::vector& V) {
+  assert(V.size() == 0); // expected-note 2{{'?' condition is true}}
+ // expected-note@-1 2{{Assuming the condition is true}}
+
+  clang_analyzer_eval(clang_analyzer_container_end(V) ==
+  clang_analyzer_container_begin(V));
+  // expected-warning@-2{{TRUE}}
+  // expected-note@-3   {{TRUE}}
+
+  clang_analyzer_dump(V.size()); // expected-warning{{0}}
+ // expected-note@-1{{0}}
+}
+
+void size1(const std::vector& V) {
+  assert(V.size() == 1); // expected-note 2{{'?' condition is true}}
+ // expected-note@-1 2{{Assuming the condition is true}}
+
+  clang_analyzer_eval(clang_analyzer_container_end(V) ==
+  clang_analyzer_container_begin(V) + 1);
+  // expected-warning@-2{{TRUE}}
+  // expected-note@-3   {{TRUE}}
+
+  clang_analyzer_dump(V.size()); // expected-warning{{1}}
+ // expected-note@-1{{1}}
+}
+
+void size2(std::vector& V) {
+  assert(V.size() == 1); // expected-note 2{{'?' condition is true}}
+ // expected-note@-1 2{{Assuming the condition is true}}
+
+  V.push_back(1);
+
+  clang_analyzer_eval(clang_analyzer_container_end(V) ==
+  clang_analyzer_container_begin(V) + 2);
+  // expected-warning@-2{{TRUE}}
+  // expected-note@-3   {{TRUE}}
+
+  clang_analyzer_dump(V.size()); // expected-warning{{2}}
+ // expected-note@-1{{2}}
+}
+
+void size3(std::vector& V) {
+  assert(V.size() <= 10); // expected-note 6{{'?' condition is true}}
+ // expected-note@-1 6{{Assuming the condition is true}}
+
+  clang_analyzer_eval(clang_analyzer_container_end(V) + 1 ==
+  clang_analyzer_container_begin(V));
+  // expected-warning@-2{{FALSE}}
+  // expected-note@-3   {{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_container_end(V) ==
+  clang_analyzer_container_begin(V));
+  // expected-warning@-2{{TRUE}} expected-warning@-2{{FALSE}}
+  // expected-note@-3   {{TRUE}} expected-note@-3   {{FALSE}}
+  // expected-note@-4  {{Assuming the condition is true}}
+  // expected-note@-5 4{{Assuming the condition is false}}
+
+  clang_analyzer_eval(clang_analyzer_container_end(V) ==
+  clang_analyzer_container_begin(V) + 10);
+  // expected-warning@-2{{TRUE}} expected-warning@-2{{FALSE}}
+  // expected-note@-3   {{TRUE}} expected-note@-3   {{FALSE}}
+  // expected-note@-4  {{Assuming the condition is true}}
+  // expected-note@-5 2{{Assuming the condition is false}}
+
+  clang_analyzer_eval(clang_analyzer_container_end(V) ==
+  clang_analyzer_container_begin(V) + 11);
+  // expected-warning@-2{{FALSE}}
+  // expected-note@-3   {{FALSE}}
+}
+
+void size4(std::vector& V) {
+  assert(V.size() >= 10); // expected-note 6{{'?' condition is true}}
+ // expected-note@-1 6{{Assuming the condition is true}}
+
+  clang_analyzer_eval(clang_analyzer_container_end(V) + 1 ==
+  clang_analyzer_container_begin(V));
+  // expected-warning@-2{{FALSE}}
+  // expected-note@-3   {{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_container_end(V) ==
+  clang_analyzer_container_begin(V));
+  // expected-warning@-2{{FALSE}}
+  // expected-note@-3   {{FALSE}}
+
+  clang_analyzer_eval(clang_analyzer_container_end(V) ==
+  clang_analyzer_container_begin(V) + 10);
+  // expected-warning@-2{{TRUE}} expected-warning@-2{{FALSE}}
+  // expected-note@-3   {{TRUE}} expected-note@-3   {{FALSE}}
+  // expected-note@-4  {{Assuming the condition is true}}
+  // expected-note@-5 3{{Assuming the condition is false}}
+
+  clang_analyzer_eval(clang_analyzer_container_end(V) ==
+  clang_analyzer_container_begin(V) + 11);
+  // expected-warning@-2{{TRUE}} expected-warning@-2{{FALSE}}
+  // expected-note@-3   {{TRUE}} 

[PATCH] D71199: [clang-tidy] New check cppcoreguidelines-prefer-member-initializer

2020-09-21 Thread Balogh , Ádám via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG4fc0214a1014: [clang-tidy] New check 
cppcoreguidelines-prefer-member-initializer (authored by baloghadamsoftware).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D71199

Files:
  clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
  clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  
clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
  clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-prefer-member-initializer.rst
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer-modernize-use-default-member-init-assignment.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer-modernize-use-default-member-init.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
@@ -0,0 +1,490 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-prefer-member-initializer %t -- -- -fcxx-exceptions
+
+extern void __assert_fail (__const char *__assertion, __const char *__file,
+unsigned int __line, __const char *__function)
+ __attribute__ ((__noreturn__));
+#define assert(expr) \
+  ((expr)  ? (void)(0)  : __assert_fail (#expr, __FILE__, __LINE__, __func__))
+
+class Simple1 {
+  int n;
+  double x;
+
+public:
+  Simple1() {
+// CHECK-FIXES: Simple1() : n(0), x(0.0) {
+n = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+x = 0.0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple1(int nn, double xx) {
+// CHECK-FIXES: Simple1(int nn, double xx) : n(nn), x(xx) {
+n = nn;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+x = xx;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple1() = default;
+};
+
+class Simple2 {
+  int n;
+  double x;
+
+public:
+  Simple2() : n(0) {
+// CHECK-FIXES: Simple2() : n(0), x(0.0) {
+x = 0.0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple2(int nn, double xx) : n(nn) {
+// CHECK-FIXES: Simple2(int nn, double xx) : n(nn), x(xx) {
+x = xx;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple2() = default;
+};
+
+class Simple3 {
+  int n;
+  double x;
+
+public:
+  Simple3() : x(0.0) {
+// CHECK-FIXES: Simple3() : n(0), x(0.0) {
+n = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple3(int nn, double xx) : x(xx) {
+// CHECK-FIXES: Simple3(int nn, double xx) : n(nn), x(xx) {
+n = nn;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple3() = default;
+};
+
+int something_int();
+double something_double();
+
+class Simple4 {
+  int n;
+
+public:
+  Simple4() {
+// CHECK-FIXES: Simple4() : n(something_int()) {
+n = something_int();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple4() = default;
+};
+
+static bool dice();
+
+class Complex1 {
+  int n;
+  int m;
+
+public:
+  Complex1() : n(0) {
+if (dice())
+  m = 1;
+// NO-MESSAGES: initialization of 'm' is nested in a conditional expression
+  }
+
+  ~Complex1() = default;
+};
+
+class Complex2 {
+  int n;
+  int m;
+

[PATCH] D71199: [clang-tidy] New check cppcoreguidelines-prefer-member-initializer

2020-09-21 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

Prerequeisite patch is committed, the check is tested now on the //LLVM 
Project//. @lebedev.ri, @aaron.ballman can I recommit it?


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

https://reviews.llvm.org/D71199

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


[PATCH] D71199: [clang-tidy] New check cppcoreguidelines-prefer-member-initializer

2020-09-21 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 293139.
baloghadamsoftware added a comment.

Updated according to the comments.


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

https://reviews.llvm.org/D71199

Files:
  clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
  clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  
clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
  clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-prefer-member-initializer.rst
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer-modernize-use-default-member-init-assignment.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer-modernize-use-default-member-init.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
@@ -0,0 +1,490 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-prefer-member-initializer %t -- -- -fcxx-exceptions
+
+extern void __assert_fail (__const char *__assertion, __const char *__file,
+unsigned int __line, __const char *__function)
+ __attribute__ ((__noreturn__));
+#define assert(expr) \
+  ((expr)  ? (void)(0)  : __assert_fail (#expr, __FILE__, __LINE__, __func__))
+
+class Simple1 {
+  int n;
+  double x;
+
+public:
+  Simple1() {
+// CHECK-FIXES: Simple1() : n(0), x(0.0) {
+n = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+x = 0.0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple1(int nn, double xx) {
+// CHECK-FIXES: Simple1(int nn, double xx) : n(nn), x(xx) {
+n = nn;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+x = xx;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple1() = default;
+};
+
+class Simple2 {
+  int n;
+  double x;
+
+public:
+  Simple2() : n(0) {
+// CHECK-FIXES: Simple2() : n(0), x(0.0) {
+x = 0.0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple2(int nn, double xx) : n(nn) {
+// CHECK-FIXES: Simple2(int nn, double xx) : n(nn), x(xx) {
+x = xx;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple2() = default;
+};
+
+class Simple3 {
+  int n;
+  double x;
+
+public:
+  Simple3() : x(0.0) {
+// CHECK-FIXES: Simple3() : n(0), x(0.0) {
+n = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple3(int nn, double xx) : x(xx) {
+// CHECK-FIXES: Simple3(int nn, double xx) : n(nn), x(xx) {
+n = nn;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple3() = default;
+};
+
+int something_int();
+double something_double();
+
+class Simple4 {
+  int n;
+
+public:
+  Simple4() {
+// CHECK-FIXES: Simple4() : n(something_int()) {
+n = something_int();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple4() = default;
+};
+
+static bool dice();
+
+class Complex1 {
+  int n;
+  int m;
+
+public:
+  Complex1() : n(0) {
+if (dice())
+  m = 1;
+// NO-MESSAGES: initialization of 'm' is nested in a conditional expression
+  }
+
+  ~Complex1() = default;
+};
+
+class Complex2 {
+  int n;
+  int m;
+
+public:
+  Complex2() : n(0) {
+if (!dice())
+  return;
+m = 1;
+// NO-MESSAGES: initialization of 'm' 

[PATCH] D77792: [analyzer] Extend constraint manager to be able to compare simple SymSymExprs

2020-09-21 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 293111.
baloghadamsoftware added a comment.

Tests updated: some execution paths merged by refactoring assertions.


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

https://reviews.llvm.org/D77792

Files:
  
clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
  clang/test/Analysis/constraint-manager-sym-sym.c

Index: clang/test/Analysis/constraint-manager-sym-sym.c
===
--- /dev/null
+++ clang/test/Analysis/constraint-manager-sym-sym.c
@@ -0,0 +1,205 @@
+// RUN: %clang_analyze_cc1 -verify -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -analyzer-config eagerly-assume=false %s
+
+void clang_analyzer_eval(int);
+
+extern void __assert_fail(__const char *__assertion, __const char *__file,
+  unsigned int __line, __const char *__function)
+__attribute__((__noreturn__));
+#define assert(expr) \
+  ((expr) ? (void)(0) : __assert_fail(#expr, __FILE__, __LINE__, __func__))
+
+// Given [a1,a2] and [b1,b2] intervals.
+// Pin the [b1,b2] interval to eg. [5,10]
+// Choose the a1,a2 points from 0,2,5,7,10,12 where a1 < a2.
+// There will be 5+4+3+2+1 cases.
+
+// [0,2] and [5,10]
+void test_range1(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(0 <= l && l <= 2);
+  clang_analyzer_eval(l < r);  // expected-warning{{TRUE}}
+  clang_analyzer_eval(l <= r); // expected-warning{{TRUE}}
+  clang_analyzer_eval(l > r);  // expected-warning{{FALSE}}
+  clang_analyzer_eval(l >= r); // expected-warning{{FALSE}}
+}
+
+// [0,5] and [5,10]
+void test_range2(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(0 <= l && l <= 5);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{TRUE}}
+  clang_analyzer_eval(l > r);  // expected-warning{{FALSE}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [0,7] and [5,10]
+void test_range3(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(0 <= l && l <= 7);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l > r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [0,10] and [5,10]
+void test_range4(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(0 <= l && l <= 10);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l > r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [0,12] and [5,10]
+void test_range5(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(0 <= l && l <= 12);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l > r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [2,5] and [5,10] omitted because it is the same as the '[0,5] and [5,10]'
+
+// [2,7] and [5,10]
+void test_range7(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(2 <= l && l <= 7);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l > r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [2,10] and [5,10]
+void test_range8(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(2 <= l && l <= 10);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l > r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [2,12] and [5,10]
+void test_range9(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(2 <= l && l <= 12);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l > r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [5,7] and [5,10]
+void test_range10(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(5 <= l && l <= 7);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l > r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [5,10] and [5,10]
+void test_range11(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(5 <= l && l <= 10);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= 

[PATCH] D81272: [clang-tidy] New check `bugprone-redundant-branch-condition`

2020-09-21 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

In D81272#2276342 , @sylvestre.ledru 
wrote:

> Thanks for this checker. FYI, it found (at least) 3 defects in Firefox code 
> (fixed with the autofix):
> https://hg.mozilla.org/mozilla-central/rev/651e68f628d0
>
> https://bugzilla.mozilla.org/show_bug.cgi?id=1664747
> (unlikely that it was causing any actual bugs in the product)

Thank you for your info. These defects do not cause any bug directly, but they 
make code understanding harder which may cause bugs in the future.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D81272

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


[PATCH] D77792: [analyzer] Extend constraint manager to be able to compare simple SymSymExprs

2020-09-18 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h:103-110
+  enum class CompareResult {
+unknown,
+identical,
+less,
+less_equal,
+greater,
+greater_equal

ASDenysPetrov wrote:
> Can we use `Optional` instead, to reduce similar enums? 
> Or you want to separate the meaning in a such way?
Good question. @NoQ?



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:30-33
+  const int LMaxRMin =
+  llvm::APSInt::compareValues(getMaxValue(), other.getMinValue());
+  const int LMinRMax =
+  llvm::APSInt::compareValues(getMinValue(), other.getMaxValue());

ASDenysPetrov wrote:
> As you use here `getMaxValue` twice which is not O(1), it'd better to use a 
> buffer variable.
`getMaxValue()` for the current and `other.getMaxValue()` are different.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:106-113
+const llvm::APSInt ::getMaxValue() const {
+  assert(!isEmpty());
+  auto last = ranges.begin();
+  for (auto it = std::next(ranges.begin()); it != ranges.end(); ++it)
+last = it;
+  return last->To();
+}

ASDenysPetrov wrote:
> Can we improve `llvm::ImmutableSet` this to make `getMaxValue` complexity 
> O(1)?
`llvm::ImmutableSet` seems to me a //heap//-like structure, a tree optimized 
for minimum-search: the mininum is in the root of the tree. Maximum is linear.



Comment at: clang/test/Analysis/constraint-manager-sym-sym.c:181
+// {[0,1],[20,20]} and {[9,9],[11,42],[44,44]}
+void test_range18(int l, int r) {
+  assert((9 <= r && r <= 9) || (11 <= r && r <= 42) || (44 <= r && r <= 44));

ASDenysPetrov wrote:
> Could you add some tests for `unsigned, unsigned` and `signed, unsigned`?
I will do it.


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

https://reviews.llvm.org/D77792

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


[PATCH] D77792: [analyzer] Extend constraint manager to be able to compare simple SymSymExprs

2020-09-18 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:814
 
+Optional RangeConstraintManager::tryAssumeSymSymOp(
+ProgramStateRef State, BinaryOperator::Opcode Op, SymbolRef LHSSym,

NoQ wrote:
> I believe you don't need to return an optional here. The method simply 
> acknowledges any assumptions it could make in the existing state and returns 
> the updated state. Therefore, if it wasn't able to record any assumptions, it 
> returns the existing state. Because the only reasonable behavior the caller 
> could implement when the current implementation returns `None` is to roll 
> back to the existing state anyway.
Actually, `tryAssumeSymSymOp()` does not assume anything and therefore it does 
not return a new state. What it actually returns is a ternary logical value: 
the assumption is either valid, invalid or we cannot reason about it. Maybe 
Optional would be better here and we should also chose a less misleading 
name, because it does not "try to assume" anything, but tries to reason about 
the existing assumption.


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

https://reviews.llvm.org/D77792

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


[PATCH] D77792: [analyzer] Extend constraint manager to be able to compare simple SymSymExprs

2020-09-18 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 292755.
baloghadamsoftware added a comment.

Crash fixed and new tests added.


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

https://reviews.llvm.org/D77792

Files:
  
clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
  clang/test/Analysis/constraint-manager-sym-sym.c

Index: clang/test/Analysis/constraint-manager-sym-sym.c
===
--- /dev/null
+++ clang/test/Analysis/constraint-manager-sym-sym.c
@@ -0,0 +1,206 @@
+// RUN: %clang_analyze_cc1 -verify -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -analyzer-config eagerly-assume=false %s
+
+void clang_analyzer_eval(int);
+
+extern void __assert_fail(__const char *__assertion, __const char *__file,
+  unsigned int __line, __const char *__function)
+__attribute__((__noreturn__));
+#define assert(expr) \
+  ((expr) ? (void)(0) : __assert_fail(#expr, __FILE__, __LINE__, __func__))
+
+// Given [a1,a2] and [b1,b2] intervals.
+// Pin the [b1,b2] interval to eg. [5,10]
+// Choose the a1,a2 points from 0,2,5,7,10,12 where a1 < a2.
+// There will be 5+4+3+2+1 cases.
+
+// [0,2] and [5,10]
+void test_range1(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(0 <= l && l <= 2);
+  clang_analyzer_eval(l < r);  // expected-warning{{TRUE}}
+  clang_analyzer_eval(l <= r); // expected-warning{{TRUE}}
+  clang_analyzer_eval(l > r);  // expected-warning{{FALSE}}
+  clang_analyzer_eval(l >= r); // expected-warning{{FALSE}}
+}
+
+// [0,5] and [5,10]
+void test_range2(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(0 <= l && l <= 5);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{TRUE}}
+  clang_analyzer_eval(l > r);  // expected-warning{{FALSE}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [0,7] and [5,10]
+void test_range3(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(0 <= l && l <= 7);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l > r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [0,10] and [5,10]
+void test_range4(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(0 <= l && l <= 10);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l > r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [0,12] and [5,10]
+void test_range5(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(0 <= l && l <= 12);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l > r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [2,5] and [5,10] omitted because it is the same as the '[0,5] and [5,10]'
+
+// [2,7] and [5,10]
+void test_range7(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(2 <= l && l <= 7);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l > r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [2,10] and [5,10]
+void test_range8(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(2 <= l && l <= 10);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l > r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [2,12] and [5,10]
+void test_range9(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(2 <= l && l <= 12);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l > r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [5,7] and [5,10]
+void test_range10(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(5 <= l && l <= 7);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l > r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l >= r); // expected-warning{{UNKNOWN}}
+}
+
+// [5,10] and [5,10]
+void test_range11(int l, int r) {
+  assert(5 <= r && r <= 10);
+  assert(5 <= l && l <= 10);
+  clang_analyzer_eval(l < r);  // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(l <= r); // expected-warning{{UNKNOWN}}
+  

[PATCH] D77792: [analyzer] Extend constraint manager to be able to compare simple SymSymExprs

2020-09-18 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware commandeered this revision.
baloghadamsoftware edited reviewers, added: steakhal; removed: 
baloghadamsoftware.
baloghadamsoftware added a comment.
Herald added a subscriber: gamesh411.

We found use cases which can be solved using this improvement. That is why I 
commandeer this patch now.


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

https://reviews.llvm.org/D77792

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


[PATCH] D87527: [ASTMatchers] Fix `hasBody` for the descendants of `FunctionDecl`

2020-09-16 Thread Balogh , Ádám via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGdbd45b2db8e0: [ASTMatchers] Fix `hasBody` for the 
descendants of `FunctionDecl` (authored by baloghadamsoftware).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87527

Files:
  clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.cpp
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/include/clang/ASTMatchers/ASTMatchersInternal.h
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1612,10 +1612,49 @@
   doStmt(hasBody(compoundStmt();
   EXPECT_TRUE(matches("void f() { int p[2]; for (auto x : p) {} }",
   cxxForRangeStmt(hasBody(compoundStmt();
+}
+
+TEST(HasBody, FindsBodyOfFunctions) {
   EXPECT_TRUE(matches("void f() {}", functionDecl(hasBody(compoundStmt();
   EXPECT_TRUE(notMatches("void f();", functionDecl(hasBody(compoundStmt();
-  EXPECT_TRUE(matches("void f(); void f() {}",
-  functionDecl(hasBody(compoundStmt();
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "void f(); void f() {}",
+  functionDecl(hasBody(compoundStmt())).bind("func"),
+  std::make_unique>("func", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { void f(); }; void C::f() {}",
+  cxxMethodDecl(hasBody(compoundStmt())).bind("met"),
+  std::make_unique>("met", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { C(); }; C::C() {}",
+  cxxConstructorDecl(hasBody(compoundStmt())).bind("ctr"),
+  std::make_unique>("ctr", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { ~C(); }; C::~C() {}",
+  cxxDestructorDecl(hasBody(compoundStmt())).bind("dtr"),
+  std::make_unique>("dtr", 1)));
+}
+
+TEST(HasAnyBody, FindsAnyBodyOfFunctions) {
+  EXPECT_TRUE(matches("void f() {}", functionDecl(hasAnyBody(compoundStmt();
+  EXPECT_TRUE(notMatches("void f();",
+ functionDecl(hasAnyBody(compoundStmt();
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "void f(); void f() {}",
+  functionDecl(hasAnyBody(compoundStmt())).bind("func"),
+  std::make_unique>("func", 2)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { void f(); }; void C::f() {}",
+  cxxMethodDecl(hasAnyBody(compoundStmt())).bind("met"),
+  std::make_unique>("met", 2)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { C(); }; C::C() {}",
+  cxxConstructorDecl(hasAnyBody(compoundStmt())).bind("ctr"),
+  std::make_unique>("ctr", 2)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { ~C(); }; C::~C() {}",
+  cxxDestructorDecl(hasAnyBody(compoundStmt())).bind("dtr"),
+  std::make_unique>("dtr", 2)));
 }
 
 TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) {
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1835,18 +1835,18 @@
   DynTypedNode Node;
 };
 
+template  struct GetBodyMatcher {
+  static const Stmt *get(const Ty ) { return Node.getBody(); }
+};
+
 template 
-struct GetBodyMatcher {
+struct GetBodyMatcher::value>::type> {
   static const Stmt *get(const Ty ) {
-return Node.getBody();
+return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr;
   }
 };
 
-template <>
-inline const Stmt *GetBodyMatcher::get(const FunctionDecl ) {
-  return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr;
-}
-
 template 
 struct HasSizeMatcher {
   static bool hasSize(const Ty , unsigned int N) {
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -4879,7 +4879,9 @@
 }
 
 /// Matches a 'for', 'while', 'do while' statement or a function
-/// definition that has a given body.
+/// definition that has a given body. Note that in case of functions
+/// this matcher only matches the definition itself and not the other
+/// declarations of the same function.
 ///
 /// Given
 /// \code
@@ -4889,6 +4891,18 @@
 ///   matches 'for (;;) {}'
 /// with compoundStmt()
 ///   matching '{}'
+///
+/// Given
+/// \code
+///   void f();
+///   void f() {}
+/// \endcode
+/// hasBody(functionDecl())
+///   matches 'void f() {}'
+/// with compoundStmt()
+///   matching '{}'
+///   but does not match 'void f();'
+
 AST_POLYMORPHIC_MATCHER_P(hasBody,
   AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, 

[PATCH] D87683: [clang-tidy] Crash fix for bugprone-misplaced-pointer-arithmetic-in-alloc

2020-09-16 Thread Balogh , Ádám via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG779a2a2edcea: [clang-tidy] Crash fix for 
bugprone-misplaced-pointer-arithmetic-in-alloc (authored by baloghadamsoftware).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87683

Files:
  
clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
@@ -51,3 +51,14 @@
   // CHECK-FIXES: p = new char[n - m] + 10;
   // FIXME: should be p = new char[n - m + 10];
 }
+
+namespace std {
+typedef decltype(sizeof(void*)) size_t;
+}
+
+void* operator new(std::size_t, void*);
+
+void placement_new_ptr(void *buf, C *old) {
+  C **p = new (buf) C*(old) + 1;
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:11: warning: arithmetic operation is 
applied to the result of operator new() instead of its size-like argument
+}
Index: 
clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
===
--- 
clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
+++ 
clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
@@ -77,9 +77,9 @@
   CallName = "operator new[]";
 } else {
   const auto *CtrE = New->getConstructExpr();
-  if (!CtrE->getArg(CtrE->getNumArgs() - 1)
-   ->getType()
-   ->isIntegralOrEnumerationType())
+  if (!CtrE || !CtrE->getArg(CtrE->getNumArgs() - 1)
+ ->getType()
+ ->isIntegralOrEnumerationType())
 return;
   CallName = "operator new";
 }


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
@@ -51,3 +51,14 @@
   // CHECK-FIXES: p = new char[n - m] + 10;
   // FIXME: should be p = new char[n - m + 10];
 }
+
+namespace std {
+typedef decltype(sizeof(void*)) size_t;
+}
+
+void* operator new(std::size_t, void*);
+
+void placement_new_ptr(void *buf, C *old) {
+  C **p = new (buf) C*(old) + 1;
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:11: warning: arithmetic operation is applied to the result of operator new() instead of its size-like argument
+}
Index: clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
@@ -77,9 +77,9 @@
   CallName = "operator new[]";
 } else {
   const auto *CtrE = New->getConstructExpr();
-  if (!CtrE->getArg(CtrE->getNumArgs() - 1)
-   ->getType()
-   ->isIntegralOrEnumerationType())
+  if (!CtrE || !CtrE->getArg(CtrE->getNumArgs() - 1)
+ ->getType()
+ ->isIntegralOrEnumerationType())
 return;
   CallName = "operator new";
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D87527: [ASTMatchers] Fix `hasBody` for the descendants of `FunctionDecl`

2020-09-16 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 292170.
baloghadamsoftware added a comment.

Checker `modernize-use-equals-delete` adjusted.


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

https://reviews.llvm.org/D87527

Files:
  clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.cpp
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/include/clang/ASTMatchers/ASTMatchersInternal.h
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1454,10 +1454,49 @@
   doStmt(hasBody(compoundStmt();
   EXPECT_TRUE(matches("void f() { int p[2]; for (auto x : p) {} }",
   cxxForRangeStmt(hasBody(compoundStmt();
+}
+
+TEST(HasBody, FindsBodyOfFunctions) {
   EXPECT_TRUE(matches("void f() {}", functionDecl(hasBody(compoundStmt();
   EXPECT_TRUE(notMatches("void f();", functionDecl(hasBody(compoundStmt();
-  EXPECT_TRUE(matches("void f(); void f() {}",
-  functionDecl(hasBody(compoundStmt();
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "void f(); void f() {}",
+  functionDecl(hasBody(compoundStmt())).bind("func"),
+  std::make_unique>("func", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { void f(); }; void C::f() {}",
+  cxxMethodDecl(hasBody(compoundStmt())).bind("met"),
+  std::make_unique>("met", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { C(); }; C::C() {}",
+  cxxConstructorDecl(hasBody(compoundStmt())).bind("ctr"),
+  std::make_unique>("ctr", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { ~C(); }; C::~C() {}",
+  cxxDestructorDecl(hasBody(compoundStmt())).bind("dtr"),
+  std::make_unique>("dtr", 1)));
+}
+
+TEST(HasAnyBody, FindsAnyBodyOfFunctions) {
+  EXPECT_TRUE(matches("void f() {}", functionDecl(hasAnyBody(compoundStmt();
+  EXPECT_TRUE(notMatches("void f();",
+ functionDecl(hasAnyBody(compoundStmt();
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "void f(); void f() {}",
+  functionDecl(hasAnyBody(compoundStmt())).bind("func"),
+  std::make_unique>("func", 2)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { void f(); }; void C::f() {}",
+  cxxMethodDecl(hasAnyBody(compoundStmt())).bind("met"),
+  std::make_unique>("met", 2)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { C(); }; C::C() {}",
+  cxxConstructorDecl(hasAnyBody(compoundStmt())).bind("ctr"),
+  std::make_unique>("ctr", 2)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { ~C(); }; C::~C() {}",
+  cxxDestructorDecl(hasAnyBody(compoundStmt())).bind("dtr"),
+  std::make_unique>("dtr", 2)));
 }
 
 TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) {
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1835,18 +1835,18 @@
   DynTypedNode Node;
 };
 
+template  struct GetBodyMatcher {
+  static const Stmt *get(const Ty ) { return Node.getBody(); }
+};
+
 template 
-struct GetBodyMatcher {
+struct GetBodyMatcher::value>::type> {
   static const Stmt *get(const Ty ) {
-return Node.getBody();
+return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr;
   }
 };
 
-template <>
-inline const Stmt *GetBodyMatcher::get(const FunctionDecl ) {
-  return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr;
-}
-
 template 
 struct HasSizeMatcher {
   static bool hasSize(const Ty , unsigned int N) {
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -4769,7 +4769,9 @@
 }
 
 /// Matches a 'for', 'while', 'do while' statement or a function
-/// definition that has a given body.
+/// definition that has a given body. Note that in case of functions
+/// this matcher only matches the definition itself and not the other
+/// declarations of the same function.
 ///
 /// Given
 /// \code
@@ -4779,6 +4781,18 @@
 ///   matches 'for (;;) {}'
 /// with compoundStmt()
 ///   matching '{}'
+///
+/// Given
+/// \code
+///   void f();
+///   void f() {}
+/// \endcode
+/// hasBody(functionDecl())
+///   matches 'void f() {}'
+/// with compoundStmt()
+///   matching '{}'
+///   but does not match 'void f();'
+
 AST_POLYMORPHIC_MATCHER_P(hasBody,
   AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt,
   WhileStmt,
@@ -4790,6 +4804,30 @@
 

[PATCH] D87683: [clang-tidy] Crash fix for bugprone-misplaced-pointer-arithmetic-in-alloc

2020-09-16 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 292151.
baloghadamsoftware added a comment.

`std::size_t` defined correctly in the tests.


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

https://reviews.llvm.org/D87683

Files:
  
clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
@@ -51,3 +51,14 @@
   // CHECK-FIXES: p = new char[n - m] + 10;
   // FIXME: should be p = new char[n - m + 10];
 }
+
+namespace std {
+typedef decltype(sizeof(void*)) size_t;
+}
+
+void* operator new(std::size_t, void*);
+
+void placement_new_ptr(void *buf, C *old) {
+  C **p = new (buf) C*(old) + 1;
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:11: warning: arithmetic operation is 
applied to the result of operator new() instead of its size-like argument
+}
Index: 
clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
===
--- 
clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
+++ 
clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
@@ -77,9 +77,9 @@
   CallName = "operator new[]";
 } else {
   const auto *CtrE = New->getConstructExpr();
-  if (!CtrE->getArg(CtrE->getNumArgs() - 1)
-   ->getType()
-   ->isIntegralOrEnumerationType())
+  if (!CtrE || !CtrE->getArg(CtrE->getNumArgs() - 1)
+ ->getType()
+ ->isIntegralOrEnumerationType())
 return;
   CallName = "operator new";
 }


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
@@ -51,3 +51,14 @@
   // CHECK-FIXES: p = new char[n - m] + 10;
   // FIXME: should be p = new char[n - m + 10];
 }
+
+namespace std {
+typedef decltype(sizeof(void*)) size_t;
+}
+
+void* operator new(std::size_t, void*);
+
+void placement_new_ptr(void *buf, C *old) {
+  C **p = new (buf) C*(old) + 1;
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:11: warning: arithmetic operation is applied to the result of operator new() instead of its size-like argument
+}
Index: clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
@@ -77,9 +77,9 @@
   CallName = "operator new[]";
 } else {
   const auto *CtrE = New->getConstructExpr();
-  if (!CtrE->getArg(CtrE->getNumArgs() - 1)
-   ->getType()
-   ->isIntegralOrEnumerationType())
+  if (!CtrE || !CtrE->getArg(CtrE->getNumArgs() - 1)
+ ->getType()
+ ->isIntegralOrEnumerationType())
 return;
   CallName = "operator new";
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D87683: [clang-tidy] Crash fix for bugprone-misplaced-pointer-arithmetic-in-alloc

2020-09-15 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

In D87683#2274569 , @njames93 wrote:

> Please fix the test case first, can't call `operator new(unsigned long, 
> void*)` with an argument of type `void*`
> The other failures the pre merge bot detected can safely be disregarded

Placement new is defined per standard:

  void* operator new  ( std::size_t count, void* ptr );

Here, the problem is that `size_t` is `unsigned long` on //Linux// and it seems 
that it is `unsigned long long` on //Windows//. How should I overcome this?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87683

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


[PATCH] D87527: [ASTMatchers] Fix `hasBody` for the descendants of `FunctionDecl`

2020-09-15 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 291901.
baloghadamsoftware added a comment.

Created another matcher `hasAnyBody`, and updated the documentation of the 
matchers.


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

https://reviews.llvm.org/D87527

Files:
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/include/clang/ASTMatchers/ASTMatchersInternal.h
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1454,10 +1454,49 @@
   doStmt(hasBody(compoundStmt();
   EXPECT_TRUE(matches("void f() { int p[2]; for (auto x : p) {} }",
   cxxForRangeStmt(hasBody(compoundStmt();
+}
+
+TEST(HasBody, FindsBodyOfFunctions) {
   EXPECT_TRUE(matches("void f() {}", functionDecl(hasBody(compoundStmt();
   EXPECT_TRUE(notMatches("void f();", functionDecl(hasBody(compoundStmt();
-  EXPECT_TRUE(matches("void f(); void f() {}",
-  functionDecl(hasBody(compoundStmt();
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "void f(); void f() {}",
+  functionDecl(hasBody(compoundStmt())).bind("func"),
+  std::make_unique>("func", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { void f(); }; void C::f() {}",
+  cxxMethodDecl(hasBody(compoundStmt())).bind("met"),
+  std::make_unique>("met", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { C(); }; C::C() {}",
+  cxxConstructorDecl(hasBody(compoundStmt())).bind("ctr"),
+  std::make_unique>("ctr", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { ~C(); }; C::~C() {}",
+  cxxDestructorDecl(hasBody(compoundStmt())).bind("dtr"),
+  std::make_unique>("dtr", 1)));
+}
+
+TEST(HasAnyBody, FindsAnyBodyOfFunctions) {
+  EXPECT_TRUE(matches("void f() {}", functionDecl(hasAnyBody(compoundStmt();
+  EXPECT_TRUE(notMatches("void f();",
+ functionDecl(hasAnyBody(compoundStmt();
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "void f(); void f() {}",
+  functionDecl(hasAnyBody(compoundStmt())).bind("func"),
+  std::make_unique>("func", 2)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { void f(); }; void C::f() {}",
+  cxxMethodDecl(hasAnyBody(compoundStmt())).bind("met"),
+  std::make_unique>("met", 2)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { C(); }; C::C() {}",
+  cxxConstructorDecl(hasAnyBody(compoundStmt())).bind("ctr"),
+  std::make_unique>("ctr", 2)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { ~C(); }; C::~C() {}",
+  cxxDestructorDecl(hasAnyBody(compoundStmt())).bind("dtr"),
+  std::make_unique>("dtr", 2)));
 }
 
 TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) {
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1835,18 +1835,18 @@
   DynTypedNode Node;
 };
 
+template  struct GetBodyMatcher {
+  static const Stmt *get(const Ty ) { return Node.getBody(); }
+};
+
 template 
-struct GetBodyMatcher {
+struct GetBodyMatcher::value>::type> {
   static const Stmt *get(const Ty ) {
-return Node.getBody();
+return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr;
   }
 };
 
-template <>
-inline const Stmt *GetBodyMatcher::get(const FunctionDecl ) {
-  return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr;
-}
-
 template 
 struct HasSizeMatcher {
   static bool hasSize(const Ty , unsigned int N) {
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -4769,7 +4769,9 @@
 }
 
 /// Matches a 'for', 'while', 'do while' statement or a function
-/// definition that has a given body.
+/// definition that has a given body. Note that in case of functions
+/// this matcher only matches the definition itself and not the other
+/// declarations of the same function.
 ///
 /// Given
 /// \code
@@ -4779,6 +4781,18 @@
 ///   matches 'for (;;) {}'
 /// with compoundStmt()
 ///   matching '{}'
+///
+/// Given
+/// \code
+///   void f();
+///   void f() {}
+/// \endcode
+/// hasBody(functionDecl())
+///   matches 'void f() {}'
+/// with compoundStmt()
+///   matching '{}'
+///   but does not match 'void f();'
+
 AST_POLYMORPHIC_MATCHER_P(hasBody,
   AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt,
   WhileStmt,
@@ -4790,6 +4804,30 @@
   

[PATCH] D87683: [clang-tidy] Crash fix for bugprone-misplaced-pointer-arithmetic-in-alloc

2020-09-15 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware created this revision.
baloghadamsoftware added reviewers: gribozavr2, aaron.ballman.
baloghadamsoftware added a project: clang-tools-extra.
Herald added subscribers: martong, steakhal, gamesh411, Szelethus, dkrupp, 
rnkovacs, xazax.hun, whisperity.
Herald added a project: clang.
baloghadamsoftware requested review of this revision.

Placement new operators on non-object types cause crash in 
`bugprone-misplaced-pointer-arithmetic-in-alloc`. This patch fixes this issue.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D87683

Files:
  
clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
@@ -51,3 +51,10 @@
   // CHECK-FIXES: p = new char[n - m] + 10;
   // FIXME: should be p = new char[n - m + 10];
 }
+
+void* operator new(unsigned long, void*);
+
+void placement_new_ptr(void *buf, C *old) {
+  C **p = new (buf) C*(old) + 1;
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:11: warning: arithmetic operation is 
applied to the result of operator new() instead of its size-like argument
+}
Index: 
clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
===
--- 
clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
+++ 
clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
@@ -77,9 +77,9 @@
   CallName = "operator new[]";
 } else {
   const auto *CtrE = New->getConstructExpr();
-  if (!CtrE->getArg(CtrE->getNumArgs() - 1)
-   ->getType()
-   ->isIntegralOrEnumerationType())
+  if (!CtrE || !CtrE->getArg(CtrE->getNumArgs() - 1)
+ ->getType()
+ ->isIntegralOrEnumerationType())
 return;
   CallName = "operator new";
 }


Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-misplaced-pointer-arithmetic-in-alloc.cpp
@@ -51,3 +51,10 @@
   // CHECK-FIXES: p = new char[n - m] + 10;
   // FIXME: should be p = new char[n - m + 10];
 }
+
+void* operator new(unsigned long, void*);
+
+void placement_new_ptr(void *buf, C *old) {
+  C **p = new (buf) C*(old) + 1;
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:11: warning: arithmetic operation is applied to the result of operator new() instead of its size-like argument
+}
Index: clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/MisplacedPointerArithmeticInAllocCheck.cpp
@@ -77,9 +77,9 @@
   CallName = "operator new[]";
 } else {
   const auto *CtrE = New->getConstructExpr();
-  if (!CtrE->getArg(CtrE->getNumArgs() - 1)
-   ->getType()
-   ->isIntegralOrEnumerationType())
+  if (!CtrE || !CtrE->getArg(CtrE->getNumArgs() - 1)
+ ->getType()
+ ->isIntegralOrEnumerationType())
 return;
   CallName = "operator new";
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D71199: [clang-tidy] New check cppcoreguidelines-prefer-member-initializer

2020-09-14 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 291562.
baloghadamsoftware added a comment.

No crash, no hang, no false positives on the LLVM Project.


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

https://reviews.llvm.org/D71199

Files:
  clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
  clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  
clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
  clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-prefer-member-initializer.rst
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer-modernize-use-default-member-init-assignment.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer-modernize-use-default-member-init.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
@@ -0,0 +1,474 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-prefer-member-initializer %t -- -- -fcxx-exceptions
+
+extern void __assert_fail (__const char *__assertion, __const char *__file,
+unsigned int __line, __const char *__function)
+ __attribute__ ((__noreturn__));
+#define assert(expr) \
+  ((expr)  ? (void)(0)  : __assert_fail (#expr, __FILE__, __LINE__, __func__))
+
+class Simple1 {
+  int n;
+  double x;
+
+public:
+  Simple1() {
+// CHECK-FIXES: Simple1() : n(0), x(0.0) {
+n = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+x = 0.0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple1(int nn, double xx) {
+// CHECK-FIXES: Simple1(int nn, double xx) : n(nn), x(xx) {
+n = nn;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+x = xx;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple1() = default;
+};
+
+class Simple2 {
+  int n;
+  double x;
+
+public:
+  Simple2() : n(0) {
+// CHECK-FIXES: Simple2() : n(0), x(0.0) {
+x = 0.0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple2(int nn, double xx) : n(nn) {
+// CHECK-FIXES: Simple2(int nn, double xx) : n(nn), x(xx) {
+x = xx;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple2() = default;
+};
+
+class Simple3 {
+  int n;
+  double x;
+
+public:
+  Simple3() : x(0.0) {
+// CHECK-FIXES: Simple3() : n(0), x(0.0) {
+n = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple3(int nn, double xx) : x(xx) {
+// CHECK-FIXES: Simple3(int nn, double xx) : n(nn), x(xx) {
+n = nn;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple3() = default;
+};
+
+int something_int();
+double something_double();
+
+class Simple4 {
+  int n;
+
+public:
+  Simple4() {
+// CHECK-FIXES: Simple4() : n(something_int()) {
+n = something_int();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple4() = default;
+};
+
+static bool dice();
+
+class Complex1 {
+  int n;
+  int m;
+
+public:
+  Complex1() : n(0) {
+if (dice())
+  m = 1;
+// NO-MESSAGES: initialization of 'm' is nested in a conditional expression
+  }
+
+  ~Complex1() = default;
+};
+
+class Complex2 {
+  int n;
+  int m;
+
+public:
+  Complex2() : n(0) {
+if (!dice())
+  return;
+m = 1;
+// NO-MESSAGES: 

[PATCH] D87527: [ASTMatchers] Fix `hasBody` for the descendants of `FunctionDecl`

2020-09-14 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

> Thank you for clarifying. I might nitpick that it's not "obviously wrong": 
> I'm actually writing code now that depends on exactly that behavior -- I 
> don't care where the method decl body is, as long as it's visible in the 
> current TU.  That said, I think you're right in wanting `FunctionDecl`'s 
> behavior to align with that of its derived classes and I think it better to 
> behave that way than how it currently behaves.  But, we should have an 
> alternative available in case this change breaks anyone else depending on the 
> current behavior.  Is there a different matcher with the semantics I've 
> described?
>
> Also, please clarify the comments in the header for this matcher. The current 
> description is quite unclear for functions: "Matches a 'for', 'while', 'do 
> while' statement or a function
> definition that has a given body."

We must decide about the namings. If we want to be in sync with the methods in 
`FunctionDecl`, then we keep `hasBody()` as is, but remove the template 
specialization, and create a new `doesThisDeclarationHaveABody()`. However, 
this involves changing existing checks. The other solution is to fix 
`hasBody()` like in this patch, and find a new name for the other behavior, 
such as e.g. `hasBodySomewhere()` or something similar.

The comments in the header are really poorly written, but there is the word 
//definition// which means that the matcher matches function definitions and 
not declarations. This is surely to be rephrased.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87527

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


[PATCH] D87527: [ASTMatchers] Fix `hasBody` for the descendants of `FunctionDecl`

2020-09-14 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

In D87527#2270939 , @ymandel wrote:

> Can you expand on what is wrong currently for `FunctionDecl` descendants? 
> Would the new test `FindsBodyOfFunctionChildren` fail with the current 
> implementation?

Yes, exactly. They return 2 findings instead of 1 because the matcher matches 
both the forward declaration and the definition. The cause for this is that 
template specializations do not work for the descendants of the class for which 
is template specialized. Instead, the generic version is used. Thus for the 
children of `FunctionDecl` the original `GetBodyMatcher` is instantiated which 
does not check whether `doesThisDeclarationHaveABody()` but returns a body 
instead which may be bound to another declaration of the same function in the 
declaration chain. This is obviously wrong.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87527

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


[PATCH] D87527: [ASTMatchers] Fix `hasBody` for the descendants of `FunctionDecl`

2020-09-11 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

In D87527#2268348 , @whisperity wrote:

> What about http://clang.llvm.org/doxygen/classclang_1_1CXXConversionDecl.html 
> ?

That is part of "etc.". It works for all current and future descendants of 
`FunctionDecl` now.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87527

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


[PATCH] D71199: [clang-tidy] New check cppcoreguidelines-prefer-member-initializer

2020-09-11 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

It looks like it was not entirely my fault: D87527 
.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D71199

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


[PATCH] D87527: [ASTMatchers] Fix `hasBody` for the descendants of `FunctionDecl`

2020-09-11 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware created this revision.
baloghadamsoftware added reviewers: klimek, sbenza.
baloghadamsoftware added a project: clang.
Herald added subscribers: martong, gamesh411, Szelethus, dkrupp, rnkovacs.
baloghadamsoftware requested review of this revision.

//AST Matcher// `hasBody` is a polymorphic matcher that behaves differently for 
loop statements and function declarations. The main difference is the for 
functions declarations it does not only call `FunctionDecl::getBody()` but 
first checks whether the declaration in question is that specific declaration 
which has the body by calling `FunctionDecl::doesThisDeclarationHaveABody()`. 
This is achieved by specialization of the template `GetBodyMatcher`. 
Unfortunately template specializations do not catch the descendants of the 
class for which the template is specialized. Therefore it does not work 
correcly for the descendants of `FunctionDecl`, such as `CXXMethodDecl`, 
`CXXConstructorDecl`, `CXXDestructorDecl` etc. This patch fixes this issue by 
using a template metaprogram.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D87527

Files:
  clang/include/clang/ASTMatchers/ASTMatchersInternal.h
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp


Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1454,10 +1454,30 @@
   doStmt(hasBody(compoundStmt();
   EXPECT_TRUE(matches("void f() { int p[2]; for (auto x : p) {} }",
   cxxForRangeStmt(hasBody(compoundStmt();
+}
+
+TEST(HasBody, FindsBodyOfFunctions) {
   EXPECT_TRUE(matches("void f() {}", functionDecl(hasBody(compoundStmt();
   EXPECT_TRUE(notMatches("void f();", functionDecl(hasBody(compoundStmt();
-  EXPECT_TRUE(matches("void f(); void f() {}",
-  functionDecl(hasBody(compoundStmt();
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "void f(); void f() {}",
+  functionDecl(hasBody(compoundStmt())).bind("func"),
+  std::make_unique>("func", 1)));
+}
+
+TEST(HasBody, FindsBodyOfFunctionChildren) {
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { void f(); }; void C::f() {}",
+  cxxMethodDecl(hasBody(compoundStmt())).bind("met"),
+  std::make_unique>("met", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { C(); }; C::C() {}",
+  cxxConstructorDecl(hasBody(compoundStmt())).bind("ctr"),
+  std::make_unique>("ctr", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { ~C(); }; C::~C() {}",
+  cxxDestructorDecl(hasBody(compoundStmt())).bind("dtr"),
+  std::make_unique>("dtr", 1)));
 }
 
 TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) {
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1835,18 +1835,18 @@
   DynTypedNode Node;
 };
 
+template  struct GetBodyMatcher {
+  static const Stmt *get(const Ty ) { return Node.getBody(); }
+};
+
 template 
-struct GetBodyMatcher {
+struct GetBodyMatcher::value>::type> 
{
   static const Stmt *get(const Ty ) {
-return Node.getBody();
+return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr;
   }
 };
 
-template <>
-inline const Stmt *GetBodyMatcher::get(const FunctionDecl ) 
{
-  return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr;
-}
-
 template 
 struct HasSizeMatcher {
   static bool hasSize(const Ty , unsigned int N) {


Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1454,10 +1454,30 @@
   doStmt(hasBody(compoundStmt();
   EXPECT_TRUE(matches("void f() { int p[2]; for (auto x : p) {} }",
   cxxForRangeStmt(hasBody(compoundStmt();
+}
+
+TEST(HasBody, FindsBodyOfFunctions) {
   EXPECT_TRUE(matches("void f() {}", functionDecl(hasBody(compoundStmt();
   EXPECT_TRUE(notMatches("void f();", functionDecl(hasBody(compoundStmt();
-  EXPECT_TRUE(matches("void f(); void f() {}",
-  functionDecl(hasBody(compoundStmt();
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "void f(); void f() {}",
+  functionDecl(hasBody(compoundStmt())).bind("func"),
+  std::make_unique>("func", 1)));
+}
+
+TEST(HasBody, FindsBodyOfFunctionChildren) {
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+  "class C { void f(); }; void C::f() {}",
+  cxxMethodDecl(hasBody(compoundStmt())).bind("met"),
+  std::make_unique>("met", 1)));
+  

[PATCH] D71199: [clang-tidy] New check cppcoreguidelines-prefer-member-initializer

2020-09-10 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

OK, I reversed the matcher expression now, it seems to work, but I will check 
it on the //LLVM/Clang// codebase first.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D71199

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


[PATCH] D71199: [clang-tidy] New check cppcoreguidelines-prefer-member-initializer

2020-09-10 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

I found the problem: `hasBody()` always returns true if the function has 
//somewhere// a body. This means that also the `hasBody` matcher matches 
forward declarations. However, I only need the definition. This far I could not 
find any method to achieve that: `isDefinition()` also returns true for forward 
declarations, as well as comparing with the `CanonicalDecl`. I am looking 
further...


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D71199

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


[PATCH] D85424: [Analyzer] Crash fix for alpha.cplusplus.IteratorRange

2020-09-10 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

In D85424#2258886 , @steakhal wrote:

> void foo(int x) {
>
>   int uninit;
>   x - uninit; // will-crash
>
> }

This is not even related to the iterators. We could check first whether `LHS` 
is an iterator and early exit if not. However, that does not help, the checker 
crashes if we try to add or subtract an unitialized value to/from an iterator.


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

https://reviews.llvm.org/D85424

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


[PATCH] D85424: [Analyzer] Crash fix for alpha.cplusplus.IteratorRange

2020-09-10 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 290967.
baloghadamsoftware added a comment.

Test added. Thank you for the test @steakhal!


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

https://reviews.llvm.org/D85424

Files:
  clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
  clang/test/Analysis/iterator-range.cpp


Index: clang/test/Analysis/iterator-range.cpp
===
--- clang/test/Analysis/iterator-range.cpp
+++ clang/test/Analysis/iterator-range.cpp
@@ -939,3 +939,9 @@
   auto i0 = c.begin(), i1 = c.end();
   ptrdiff_t len = i1 - i0; // no-crash
 }
+
+int uninit_var(int n) {
+  int uninit; // expected-note{{'uninit' declared without an initial value}}
+  return n - uninit; // expected-warning{{The right operand of '-' is a 
garbage value}}
+ // expected-note@-1{{The right operand of '-' is a 
garbage value}}
+}
Index: clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
@@ -228,7 +228,8 @@
 Value = State->getRawSVal(*ValAsLoc);
   }
 
-  if (Value.isUnknown())
+  if (Value.isUnknownOrUndef())
+//  if (Value.isUnknownOrUndef())
 return;
 
   // Incremention or decremention by 0 is never a bug.


Index: clang/test/Analysis/iterator-range.cpp
===
--- clang/test/Analysis/iterator-range.cpp
+++ clang/test/Analysis/iterator-range.cpp
@@ -939,3 +939,9 @@
   auto i0 = c.begin(), i1 = c.end();
   ptrdiff_t len = i1 - i0; // no-crash
 }
+
+int uninit_var(int n) {
+  int uninit; // expected-note{{'uninit' declared without an initial value}}
+  return n - uninit; // expected-warning{{The right operand of '-' is a garbage value}}
+ // expected-note@-1{{The right operand of '-' is a garbage value}}
+}
Index: clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
@@ -228,7 +228,8 @@
 Value = State->getRawSVal(*ValAsLoc);
   }
 
-  if (Value.isUnknown())
+  if (Value.isUnknownOrUndef())
+//  if (Value.isUnknownOrUndef())
 return;
 
   // Incremention or decremention by 0 is never a bug.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D71199: [clang-tidy] New check cppcoreguidelines-prefer-member-initializer

2020-09-10 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

In D71199#2265594 , @lebedev.ri wrote:

> So i've just reverted this in rGebf496d805521b53022a351f35854de977fee844 
> .
>
> @aaron.ballman @baloghadamsoftware how's QC going on nowadays here?
> Was this evaluated on anything other than it's tests?

Surely. After I commit a patch, lots of buildbots verify it. They passed so far.

> It appears to be either unacceptably slow, or subtly broken, because it takes 
> at least 100x time more than all of the other clang-tidy checks enabled, and 
> e.g.
> `clang-tidy-12 --checks="-*,cppcoreguidelines-prefer-member-initializer" -p . 
> /repositories/llvm-project/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp`
> never finishes (minutes and counting).

I see nothing there that could be slow, thus this is probably some hang. I will 
investigate it.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D71199

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


[PATCH] D85351: [Analyzer] Fix for `ExprEngine::computeObjectUnderConstruction()` for base and delegating consturctor initializers

2020-09-10 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware marked an inline comment as done.
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp:138-139
   SVal ThisVal = State->getSVal(ThisPtr);
+  if (Init->isBaseInitializer() || Init->isDelegatingInitializer())
+return ThisVal;
 

NoQ wrote:
> For base initializer you probably want the base class region. It may have a 
> non-trivial offset and it also has the correct type and extent.
Thank you for noticing this! You are completely right! Now I extended the tests 
with comparing the type of the returned region with the type of the expression. 
It failed when I just returned `ThisVal` but it passes with the fixed code.


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

https://reviews.llvm.org/D85351

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


[PATCH] D85351: [Analyzer] Fix for `ExprEngine::computeObjectUnderConstruction()` for base and delegating consturctor initializers

2020-09-10 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 290917.
baloghadamsoftware added a comment.

Fix for base constructors, test extended.


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

https://reviews.llvm.org/D85351

Files:
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp

Index: clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
===
--- clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
+++ clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
@@ -23,8 +23,8 @@
   : public Checker {
 public:
   void checkPostCall(const CallEvent , CheckerContext ) const {
-// Only calls with origin expression are checked. These are `returnC()`
-// and C::C().
+// Only calls with origin expression are checked. These are `returnC()`,
+// `returnD()`, C::C() and D::D().
 if (!Call.getOriginExpr())
   return;
 
@@ -35,6 +35,10 @@
 Optional RetVal = Call.getReturnValueUnderConstruction();
 ASSERT_TRUE(RetVal);
 ASSERT_TRUE(RetVal->getAsRegion());
+
+const auto *RetReg = cast(RetVal->getAsRegion());
+const Expr *OrigExpr = Call.getOriginExpr();
+ASSERT_EQ(OrigExpr->getType(), RetReg->getValueType());
   }
 };
 
@@ -51,22 +55,65 @@
 TEST(TestReturnValueUnderConstructionChecker,
  ReturnValueUnderConstructionChecker) {
   EXPECT_TRUE(runCheckerOnCode(
-  R"(class C {
- public:
-   C(int nn): n(nn) {}
-   virtual ~C() {}
- private:
-   int n;
- };
-
- C returnC(int m) {
-   C c(m);
-   return c;
- }
-
- void foo() {
-   C c = returnC(1); 
- })"));
+  R"(class C {
+ public:
+   C(int nn): n(nn) {}
+   virtual ~C() {}
+ private:
+   int n;
+ };
+
+ C returnC(int m) {
+   C c(m);
+   return c;
+ }
+
+ void foo() {
+   C c = returnC(1);
+ })"));
+
+  EXPECT_TRUE(runCheckerOnCode(
+  R"(class C {
+ public:
+   C(int nn): n(nn) {}
+   explicit C(): C(0) {}
+   virtual ~C() {}
+ private:
+   int n;
+ };
+
+ C returnC() {
+   C c;
+   return c;
+ }
+
+ void foo() {
+   C c = returnC();
+ })"));
+
+  EXPECT_TRUE(runCheckerOnCode(
+  R"(class C {
+ public:
+   C(int nn): n(nn) {}
+   virtual ~C() {}
+ private:
+   int n;
+ };
+
+ class D: public C {
+ public:
+   D(int nn): C(nn) {}
+   virtual ~D() {}
+ };
+
+ D returnD(int m) {
+   D d(m);
+   return d;
+ }
+
+ void foo() {
+   D d = returnD(1); 
+ })"));
 }
 
 } // namespace
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -132,10 +132,20 @@
 case ConstructionContext::SimpleConstructorInitializerKind: {
   const auto *ICC = cast(CC);
   const auto *Init = ICC->getCXXCtorInitializer();
-  assert(Init->isAnyMemberInitializer());
   const CXXMethodDecl *CurCtor = cast(LCtx->getDecl());
   Loc ThisPtr = SVB.getCXXThis(CurCtor, LCtx->getStackFrame());
   SVal ThisVal = State->getSVal(ThisPtr);
+  if (Init->isBaseInitializer()) {
+const auto *ThisReg = cast(ThisVal.getAsRegion());
+const CXXRecordDecl *BaseClass =
+  Init->getBaseClass()->getAsCXXRecordDecl();
+const auto *BaseReg =
+  MRMgr.getCXXBaseObjectRegion(BaseClass, ThisReg,
+   Init->isBaseVirtual());
+return SVB.makeLoc(BaseReg);
+}
+  if (Init->isDelegatingInitializer())
+return ThisVal;
 
   const ValueDecl *Field;
   SVal FieldVal;
@@ -364,6 +374,8 @@
 case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind:
 case ConstructionContext::SimpleConstructorInitializerKind: {
   const auto *ICC = cast(CC);
+  const auto *Init = ICC->getCXXCtorInitializer();
+  assert(Init->isAnyMemberInitializer());
   return addObjectUnderConstruction(State, ICC->getCXXCtorInitializer(),
 LCtx, V);
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D87388: [Analyzer] Model default constructors of containers

2020-09-09 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware created this revision.
baloghadamsoftware added reviewers: NoQ, vsavchenko, gamesh411.
baloghadamsoftware added a project: clang.
Herald added subscribers: ASDenysPetrov, martong, steakhal, Charusso, dkrupp, 
donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, xazax.hun, 
whisperity.
Herald added a reviewer: Szelethus.
baloghadamsoftware requested review of this revision.

Model default constructors of containers by setting their abstract `begin()` 
and `end()` symbols to equal.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D87388

Files:
  clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.h
  clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
  clang/test/Analysis/container-modeling.cpp

Index: clang/test/Analysis/container-modeling.cpp
===
--- clang/test/Analysis/container-modeling.cpp
+++ clang/test/Analysis/container-modeling.cpp
@@ -32,6 +32,23 @@
// expected-note@-1{{$V.end()}}
 }
 
+
+///
+/// C O N T A I N E R   C O N S T R U C T O R S
+///
+
+
+// Default Constructor
+
+void default_constructor() {
+  std::vector V;
+
+  clang_analyzer_eval(clang_analyzer_container_begin(V) ==
+  clang_analyzer_container_end(V));
+  // expected-warning@-2{{TRUE}}
+  // expected-note@-3   {{TRUE}}
+}
+
 
 ///
 /// C O N T A I N E R   A S S I G N M E N T S
Index: clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -157,8 +157,6 @@
 bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
 bool isSimpleComparisonOperator(BinaryOperatorKind OK);
 ProgramStateRef removeIteratorPosition(ProgramStateRef State, SVal Val);
-ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
-  SymbolRef Sym2, bool Equal);
 const ExplodedNode *findCallEnter(const ExplodedNode *Node, const Expr *Call);
 
 } // namespace
@@ -777,38 +775,6 @@
   return State;
 }
 
-ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
-  SymbolRef Sym2, bool Equal) {
-  auto  = State->getStateManager().getSValBuilder();
-
-  // FIXME: This code should be reworked as follows:
-  // 1. Subtract the operands using evalBinOp().
-  // 2. Assume that the result doesn't overflow.
-  // 3. Compare the result to 0.
-  // 4. Assume the result of the comparison.
-  const auto comparison =
-SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Sym1),
-  nonloc::SymbolVal(Sym2), SVB.getConditionType());
-
-  assert(comparison.getAs() &&
-"Symbol comparison must be a `DefinedSVal`");
-
-  auto NewState = State->assume(comparison.castAs(), Equal);
-  if (!NewState)
-return nullptr;
-
-  if (const auto CompSym = comparison.getAsSymbol()) {
-assert(isa(CompSym) &&
-   "Symbol comparison must be a `SymIntExpr`");
-assert(BinaryOperator::isComparisonOp(
-   cast(CompSym)->getOpcode()) &&
-   "Symbol comparison must be a comparison");
-return assumeNoOverflow(NewState, cast(CompSym)->getLHS(), 2);
-  }
-
-  return NewState;
-}
-
 const ExplodedNode *findCallEnter(const ExplodedNode *Node, const Expr *Call) {
   while (Node) {
 ProgramPoint PP = Node->getLocation();
Index: clang/lib/StaticAnalyzer/Checkers/Iterator.h
===
--- clang/lib/StaticAnalyzer/Checkers/Iterator.h
+++ clang/lib/StaticAnalyzer/Checkers/Iterator.h
@@ -144,7 +144,8 @@
 
 namespace iterator {
 
-bool isIteratorType(const QualType );
+bool isIteratorType(const QualType );
+bool isIteratorType(const Type* Typ);
 bool isIterator(const CXXRecordDecl *CRD);
 bool isComparisonOperator(OverloadedOperatorKind OK);
 bool isInsertCall(const FunctionDecl *Func);
@@ -179,6 +180,8 @@
 const SVal );
 ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
  long Scale);
+ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
+  SymbolRef Sym2, bool Equal);
 bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
  BinaryOperator::Opcode Opc);
 bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
Index: clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
===
--- 

[PATCH] D76604: [Analyzer] Model `size()` member function of containers

2020-09-08 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp:456
+   SVal RetVal) const {
+  const auto *ContReg = Cont.getAsRegion();
+  if (!ContReg)

Szelethus wrote:
> martong wrote:
> > Just out of curiosity: How do we handle containers that do not have a 
> > contiguous memory region? Balanced trees, bucketed hash-maps, etc.
> I suspect that this is referring to the memory address of the container 
> object, not the storage of the elements.
Yes. The region just serves to identify the container. It is not necessarily 
the region where the data is stored.



Comment at: clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp:482-483
+// of the container (the difference between its `begin()` and `end()` to
+// this size. Function `relateSymbols()` returns null if it contradits
+// the current size.
+const auto CalcEnd =

martong wrote:
> How? I don't see how does it access the `size`.
As explained between the parenthesis, the actual size of the container is the 
difference between its `begin()` and its `end()`. If we have this difference, 
then we know the actual size. The other value we may have is the return value 
of the `size()` function. We either have one of them, both or none. If we have 
one, then we adjust the other. If we have both, then we check for consistency, 
and generated a sink if they are inconsistent. If we have none, then we do 
nothing.



Comment at: clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp:492
+  } else {
+if (CalcSize) {
+  // If the current size is a concrete integer, bind this to the return

martong wrote:
> What if we have both `RetSize` and `CalcSize`? Should we check their values 
> for consistency? (And perhaps adding another sink node if we have 
> inconsistency?)
This is handled in the `if` branch: having `CalcSize` means that we know the 
difference between the `begin()` and the `end()`, thus inconsistency between 
`RetSize` and `CalcSize` is the same as inconstistency between `CalcEnd` and 
`EndSym`. The comment above explains that if there is such inconsistency, then 
`relateSymbols()` returns a null pointer which we assign to `State`. At the end 
of this functions we generate a sink whenever `State` is a null pointer.


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

https://reviews.llvm.org/D76604

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


[PATCH] D76604: [Analyzer] Model `size()` member function of containers

2020-09-08 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 290413.
baloghadamsoftware added a comment.

Fixes.


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

https://reviews.llvm.org/D76604

Files:
  clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.h
  clang/test/Analysis/container-modeling.cpp

Index: clang/test/Analysis/container-modeling.cpp
===
--- clang/test/Analysis/container-modeling.cpp
+++ clang/test/Analysis/container-modeling.cpp
@@ -96,6 +96,40 @@
   // expected-note@-3   {{FALSE}}
 }
 
+// size()
+
+void size0(const std::vector& V) {
+  assert(V.size() == 0); // expected-note{{'?' condition is true}}
+ // expected-note@-1{{Assuming the condition is true}}
+
+  clang_analyzer_eval(clang_analyzer_container_end(V) ==
+  clang_analyzer_container_begin(V));
+  // expected-warning@-2{{TRUE}}
+  // expected-note@-3   {{TRUE}}
+}
+
+void size1(const std::vector& V) {
+  assert(V.size() == 1); // expected-note{{'?' condition is true}}
+ // expected-note@-1{{Assuming the condition is true}}
+
+  clang_analyzer_eval(clang_analyzer_container_end(V) ==
+  clang_analyzer_container_begin(V) + 1);
+  // expected-warning@-2{{TRUE}}
+  // expected-note@-3   {{TRUE}}
+}
+
+void size12(std::vector& V) {
+  assert(V.size() == 1); // expected-note{{'?' condition is true}}
+ // expected-note@-1{{Assuming the condition is true}}
+
+  V.push_back(1);
+
+  clang_analyzer_eval(clang_analyzer_container_end(V) ==
+  clang_analyzer_container_begin(V) + 2);
+  // expected-warning@-2{{TRUE}}
+  // expected-note@-3   {{TRUE}}
+}
+
 
 ///
 /// C O N T A I N E R   M O D I F I E R S
Index: clang/lib/StaticAnalyzer/Checkers/Iterator.h
===
--- clang/lib/StaticAnalyzer/Checkers/Iterator.h
+++ clang/lib/StaticAnalyzer/Checkers/Iterator.h
@@ -187,6 +187,8 @@
 assumeComparison(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
  DefinedSVal RetVal, OverloadedOperatorKind Op);
 
+ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
+  SymbolRef Sym2, bool Equal);
 bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
  BinaryOperator::Opcode Opc);
 bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
Index: clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
+++ clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
@@ -18,9 +18,6 @@
 namespace ento {
 namespace iterator {
 
-ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
-  SymbolRef Sym2, bool Equal);
-
 bool isIteratorType(const QualType ) {
   if (Type->isPointerType())
 return true;
Index: clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
@@ -47,6 +47,8 @@
  SVal Cont, SVal RetVal) const;
   void handleEmpty(CheckerContext , const Expr *CE, const Expr *ContE,
SVal Cont, SVal RetVal) const;
+  void handleSize(CheckerContext , const Expr *CE, const Expr *ContE,
+  SVal Cont, SVal RetVal) const;
   void handleAssign(CheckerContext , const Expr *CE, const Expr *ContE,
 SVal Cont, SVal RetVal) const;
   void handleClear(CheckerContext , const Expr *CE, const Expr *ContE,
@@ -102,6 +104,7 @@
 
 // Capacity
 {{0, "empty", 0}, ::handleEmpty},
+{{0, "size", 0}, ::handleSize},
 
 // Modifiers
 {{0, "clear", 0}, ::handleClear},
@@ -170,6 +173,8 @@
 SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder , SymbolRef Expr,
 SymbolRef OldSym, SymbolRef NewSym);
 bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont);
+const llvm::APSInt* calculateSize(ProgramStateRef State, SymbolRef Begin,
+  SymbolRef End);
 
 } // namespace
 
@@ -446,6 +451,72 @@
   }
 }
 
+void ContainerModeling::handleSize(CheckerContext , const Expr *CE,
+   const Expr *, SVal Cont, SVal RetVal) const {
+  const auto *ContReg = Cont.getAsRegion();
+  if (!ContReg)
+return;
+
+  ContReg = ContReg->getMostDerivedObjectRegion();
+
+  auto State = C.getState();
+
+  State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy,
+   C.getLocationContext(), C.blockCount());
+  auto BeginSym = 

[PATCH] D76590: [Analyzer] Model `empty()` member function of containers

2020-09-07 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware marked an inline comment as done.
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp:36
+  void handleAssignment(CheckerContext , const Expr *CE, SVal Cont,
+Optional = None) const;
+

Szelethus wrote:
> Hmm, this was changed to an optional, unnamed parameter without docs... Might 
> be a bit cryptic :) Also, this seems to be orthogonal to the patch, is it 
> not? Does the modeling of `empty()` change something that affects this 
> function?
We discussed with @NoQ a few patches earlier that `UnknownVal` is not a 
`nullptr`-like value for `SVal`s. That time I changed this bad practice in my 
code everywhere, only forgot this particular place. I do not think that this 
deserves its own patch, it is really a tiny thing.



Comment at: clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp:420-427
+  // We cannot make assumpotions on `UnknownVal`. Let us conjure a symbol
+  // instead.
+  if (RetVal.isUnknown()) {
+auto  = C.getSymbolManager();
+RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol(
+CE, LCtx, C.getASTContext().BoolTy, C.blockCount()));
+State = State->BindExpr(CE, LCtx, RetVal);

Szelethus wrote:
> Szelethus wrote:
> > assumpotions > assumptions
> You will have to help me out here -- if the analyzer couldn't return a 
> sensible symbol, is it okay to just create one? When does `UnknownVal` even 
> happen, does it ever happen? Also, if we're doing this anyways, wouldn't 
> using `evalCall` be more appropriate?
Actually, both `UnknownVal` and `SymbolVal` containing a `SymbolConjured` 
without constraints are unknown. The main difference (for us) is that we cannot 
assign constraints to `UnknownVal` but we can for `SymbolConjured`. This is the 
reason for replacing it. However, this is not new. We do it in comparison too. 
The best would be to change the infrastructure to never return `UnknownVal` but 
conjure a new symbol instead if we known nothing about the return value. Maybe 
I will put a `FIXME` there. `evalCall()` is not an option, because we do not 
want to lose the possibility that the implementation of `empty()` is inlined by 
the engine.



Comment at: 
clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp:71
+
+  EXPECT_TRUE(runCheckerOnCode(
+  R"(class C {

Szelethus wrote:
> Did you mean to upload changed to this file from D85351 to this patch as well?
No, I just uploaded the wrong diff here.


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

https://reviews.llvm.org/D76590

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


[PATCH] D76590: [Analyzer] Model `empty()` member function of containers

2020-09-07 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 290248.
baloghadamsoftware added a comment.

Wrong diff uploaded previously. (Accidentally compared to //master// instead of 
the prerequisite.)


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

https://reviews.llvm.org/D76590

Files:
  clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.h
  clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/container-modeling.cpp
  clang/test/Analysis/diagnostics/explicit-suppression.cpp
  clang/test/Analysis/smart-ptr-text-output.cpp

Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -80,7 +80,7 @@
 void derefOnStdSwappedNullPtr() {
   std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
   std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
-  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:979 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
+  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:987 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
   // expected-note@-1 {{Calling 'swap'}}
   // expected-note@-2 {{Returning from 'swap'}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
Index: clang/test/Analysis/diagnostics/explicit-suppression.cpp
===
--- clang/test/Analysis/diagnostics/explicit-suppression.cpp
+++ clang/test/Analysis/diagnostics/explicit-suppression.cpp
@@ -19,6 +19,6 @@
 void testCopyNull(C *I, C *E) {
   std::copy(I, E, (C *)0);
 #ifndef SUPPRESSED
-  // expected-warning@../Inputs/system-header-simulator-cxx.h:709 {{Called C++ object pointer is null}}
+  // expected-warning@../Inputs/system-header-simulator-cxx.h:717 {{Called C++ object pointer is null}}
 #endif
 }
Index: clang/test/Analysis/container-modeling.cpp
===
--- clang/test/Analysis/container-modeling.cpp
+++ clang/test/Analysis/container-modeling.cpp
@@ -16,6 +16,12 @@
 void clang_analyzer_eval(bool);
 void clang_analyzer_warnIfReached();
 
+extern void __assert_fail (__const char *__assertion, __const char *__file,
+unsigned int __line, __const char *__function)
+ __attribute__ ((__noreturn__));
+#define assert(expr) \
+  ((expr)  ? (void)(0)  : __assert_fail (#expr, __FILE__, __LINE__, __func__))
+
 void begin(const std::vector ) {
   V.begin();
 
@@ -56,6 +62,40 @@
// expected-note@-1{{TRUE}}
 }
 
+
+///
+/// C O N T A I N E R   C A P A C I T Y
+///
+
+
+/// empty()
+
+void empty(const std::vector ) {
+  for (auto n: V) {}
+  clang_analyzer_eval(clang_analyzer_container_begin(V) ==
+  clang_analyzer_container_end(V));
+  // expected-warning@-2{{TRUE}} expected-warning@-2{{FALSE}}
+  // expected-note@-3   {{TRUE}} expected-note@-3   {{FALSE}}
+}
+
+void non_empty1(const std::vector ) {
+  assert(!V.empty()); // expected-note{{'?' condition is true}}
+  for (auto n: V) {}
+  clang_analyzer_eval(clang_analyzer_container_begin(V) ==
+  clang_analyzer_container_end(V));
+  // expected-warning@-2{{FALSE}}
+  // expected-note@-3   {{FALSE}}
+}
+
+void non_empty2(const std::vector ) {
+  for (auto n: V) {}
+  assert(!V.empty()); // expected-note{{'?' condition is true}}
+  clang_analyzer_eval(clang_analyzer_container_begin(V) ==
+  clang_analyzer_container_end(V));
+  // expected-warning@-2{{FALSE}}
+  // expected-note@-3   {{FALSE}}
+}
+
 
 ///
 /// C O N T A I N E R   M O D I F I E R S
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -344,6 +344,8 @@
 const T& front() const { return *begin(); }
 T& back() { return *(end() - 1); }
 const T& back() const { return *(end() - 1); }
+
+bool empty() const;
   };
   
   template
@@ -415,6 +417,8 @@
 const T& front() const { return *begin(); }
 T& back() { return *--end(); }
 const T& back() const { return *--end(); }
+
+bool empty() const;
   };
 
   template
@@ -496,6 +500,8 @@
 const T& front() const { 

[PATCH] D76590: [Analyzer] Model `empty()` member function of containers

2020-09-04 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 289981.
baloghadamsoftware added a comment.

`isIterator()` updated because it did not work perfectly with the refactored 
`handleBegin()` after rebase. (Why did it work before the rebase?) The problem 
was that it only looked for the necessary operators in the actual class but not 
in its bases.


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

https://reviews.llvm.org/D76590

Files:
  clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.h
  clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/container-modeling.cpp
  clang/test/Analysis/diagnostics/explicit-suppression.cpp
  clang/test/Analysis/iterator-modeling.cpp
  clang/test/Analysis/smart-ptr-text-output.cpp
  clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp

Index: clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
===
--- clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
+++ clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
@@ -51,22 +51,65 @@
 TEST(TestReturnValueUnderConstructionChecker,
  ReturnValueUnderConstructionChecker) {
   EXPECT_TRUE(runCheckerOnCode(
-  R"(class C {
- public:
-   C(int nn): n(nn) {}
-   virtual ~C() {}
- private:
-   int n;
- };
-
- C returnC(int m) {
-   C c(m);
-   return c;
- }
-
- void foo() {
-   C c = returnC(1); 
- })"));
+  R"(class C {
+ public:
+   C(int nn): n(nn) {}
+   virtual ~C() {}
+ private:
+   int n;
+ };
+
+ C returnC(int m) {
+   C c(m);
+   return c;
+ }
+
+ void foo() {
+   C c = returnC(1);
+ })"));
+
+  EXPECT_TRUE(runCheckerOnCode(
+  R"(class C {
+ public:
+   C(int nn): n(nn) {}
+   explicit C(): C(0) {}
+   virtual ~C() {}
+ private:
+   int n;
+ };
+
+ C returnC() {
+   C c;
+   return c;
+ }
+
+ void foo() {
+   C c = returnC();
+ })"));
+
+  EXPECT_TRUE(runCheckerOnCode(
+  R"(class C {
+ public:
+   C(int nn): n(nn) {}
+   virtual ~C() {}
+ private:
+   int n;
+ };
+
+ class D: public C {
+ public:
+   D(int nn): C(nn) {}
+   virtual ~D() {}
+ };
+
+ D returnD(int m) {
+   D d(m);
+   return d;
+ }
+
+ void foo() {
+   D d = returnD(1); 
+ })"));
 }
 
 } // namespace
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -80,7 +80,7 @@
 void derefOnStdSwappedNullPtr() {
   std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
   std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
-  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:979 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
+  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:987 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
   // expected-note@-1 {{Calling 'swap'}}
   // expected-note@-2 {{Returning from 'swap'}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
Index: clang/test/Analysis/iterator-modeling.cpp
===
--- clang/test/Analysis/iterator-modeling.cpp
+++ clang/test/Analysis/iterator-modeling.cpp
@@ -2026,6 +2026,55 @@
 ++i0;
 }
 
+template 
+struct delegated_ctor_iterator {
+  delegated_ctor_iterator(const T&, int);
+  delegated_ctor_iterator(const T& t) : delegated_ctor_iterator(t, 0) {}
+  delegated_ctor_iterator operator++();
+  delegated_ctor_iterator operator++(int);
+  T& operator*();
+};
+
+template 
+struct container_with_delegated_ctor_iterator {
+  typedef delegated_ctor_iterator iterator;
+  iterator begin() const { return delegated_ctor_iterator(T()); }
+};

[PATCH] D85351: [Analyzer] Fix for `ExprEngine::computeObjectUnderConstruction()` for base and delegating consturctor initializers

2020-09-03 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 289703.
baloghadamsoftware added a comment.

Tests separated.


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

https://reviews.llvm.org/D85351

Files:
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp

Index: clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
===
--- clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
+++ clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp
@@ -51,22 +51,65 @@
 TEST(TestReturnValueUnderConstructionChecker,
  ReturnValueUnderConstructionChecker) {
   EXPECT_TRUE(runCheckerOnCode(
-  R"(class C {
- public:
-   C(int nn): n(nn) {}
-   virtual ~C() {}
- private:
-   int n;
- };
-
- C returnC(int m) {
-   C c(m);
-   return c;
- }
-
- void foo() {
-   C c = returnC(1); 
- })"));
+  R"(class C {
+ public:
+   C(int nn): n(nn) {}
+   virtual ~C() {}
+ private:
+   int n;
+ };
+
+ C returnC(int m) {
+   C c(m);
+   return c;
+ }
+
+ void foo() {
+   C c = returnC(1);
+ })"));
+
+  EXPECT_TRUE(runCheckerOnCode(
+  R"(class C {
+ public:
+   C(int nn): n(nn) {}
+   explicit C(): C(0) {}
+   virtual ~C() {}
+ private:
+   int n;
+ };
+
+ C returnC() {
+   C c;
+   return c;
+ }
+
+ void foo() {
+   C c = returnC();
+ })"));
+
+  EXPECT_TRUE(runCheckerOnCode(
+  R"(class C {
+ public:
+   C(int nn): n(nn) {}
+   virtual ~C() {}
+ private:
+   int n;
+ };
+
+ class D: public C {
+ public:
+   D(int nn): C(nn) {}
+   virtual ~D() {}
+ };
+
+ D returnD(int m) {
+   D d(m);
+   return d;
+ }
+
+ void foo() {
+   D d = returnD(1); 
+ })"));
 }
 
 } // namespace
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -132,10 +132,11 @@
 case ConstructionContext::SimpleConstructorInitializerKind: {
   const auto *ICC = cast(CC);
   const auto *Init = ICC->getCXXCtorInitializer();
-  assert(Init->isAnyMemberInitializer());
   const CXXMethodDecl *CurCtor = cast(LCtx->getDecl());
   Loc ThisPtr = SVB.getCXXThis(CurCtor, LCtx->getStackFrame());
   SVal ThisVal = State->getSVal(ThisPtr);
+  if (Init->isBaseInitializer() || Init->isDelegatingInitializer())
+return ThisVal;
 
   const ValueDecl *Field;
   SVal FieldVal;
@@ -364,6 +365,8 @@
 case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind:
 case ConstructionContext::SimpleConstructorInitializerKind: {
   const auto *ICC = cast(CC);
+  const auto *Init = ICC->getCXXCtorInitializer();
+  assert(Init->isAnyMemberInitializer());
   return addObjectUnderConstruction(State, ICC->getCXXCtorInitializer(),
 LCtx, V);
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D85728: [Analyzer] Support for the new variadic isa<> and isa_and_not_null<> in CastValueChecker

2020-09-03 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

I was indeed on vacation, so thanks for committing it, @NoQ! I was waiting for 
agreement for the prerequisite patch then I forgot to notify you that I was 
going on vacation.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D85728

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


[PATCH] D86874: [analyzer] Fix ArrayBoundCheckerV2 false positive regarding size_t indexer

2020-09-02 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp:226
+  // No unsigned symbolic value can be less then a negative constant.
+  if (const auto SymbolicRoot = RootNonLoc.getAs())
+if (SymbolicRoot->getSymbol()->getType()->isUnsignedIntegerType() &&

martong wrote:
> I really feel that this check would have a better place in the implementation 
> of `eval`. This seems really counter-intuitive to do this stuff at the 
> Checker's level. Is there any reason why we can't do this in `eval`?
> 
> `evalBinOpNN` could return with Unknown, and the state should remain 
> unchanged. Am I missing something?
I agree here. Actually, the //constraint manager// should handle this.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D86874

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


[PATCH] D86743: [analyzer] Ignore VLASizeChecker case that could cause crash

2020-09-02 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

I agree here with @Szelethus. We should investigate first why the assumption 
fails. Then we can decide about the best possible fix.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D86743

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


[PATCH] D85351: [Analyzer] Fix for `ExprEngine::computeObjectUnderConstruction()` for base and delegating consturctor initializers

2020-09-02 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

@NoQ could you please take a look on this short fix?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D85351

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


[PATCH] D85351: [Analyzer] Fix for `ExprEngine::computeObjectUnderConstruction()` for base and delegating consturctor initializers

2020-09-02 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

In D85351#2247095 , @Szelethus wrote:

> I think its a bad experience if you break something while developing. Instead 
> of getting a test failure for "delegating constructor initializers", you'll 
> have to deal with a test that handles a variety of things at once, and are 
> forced to tease it apart to find what just broke. When the introduced assert 
> fires, this wouldn't be an issue, but in any non-crashing case it might be.

This is a crashing case.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D85351

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


[PATCH] D81272: [clang-tidy] New check `bugprone-redundant-branch-condition`

2020-08-31 Thread Balogh , Ádám via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG14dd0737822b: [Clang-Tidy] New check 
`bugprone-redundant-branch-condition` (authored by baloghadamsoftware).

Changed prior to commit:
  https://reviews.llvm.org/D81272?vs=285656=288940#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D81272

Files:
  clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
  clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.cpp
  clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/bugprone-redundant-branch-condition.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp
@@ -0,0 +1,1190 @@
+// RUN: %check_clang_tidy %s bugprone-redundant-branch-condition %t
+
+extern unsigned peopleInTheBuilding;
+extern unsigned fireFighters;
+
+bool isBurning();
+bool isReallyBurning();
+bool isCollapsing();
+void tryToExtinguish(bool&);
+void tryPutFireOut();
+bool callTheFD();
+void scream();
+
+bool someOtherCondition();
+
+//===--- Basic Positives --===//
+
+void positive_direct() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire)
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: {{^\ *$}}
+scream();
+}
+  }
+}
+
+void positive_direct_inner_and_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire && peopleInTheBuilding > 0) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: if ( peopleInTheBuilding > 0) {
+  scream();
+}
+  }
+}
+
+void positive_indirect_inner_and_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire && peopleInTheBuilding > 0) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: if ( peopleInTheBuilding > 0) {
+scream();
+  }
+}
+  }
+}
+
+void positive_direct_inner_and_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (peopleInTheBuilding > 0 && onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: if (peopleInTheBuilding > 0 ) {
+  scream();
+}
+  }
+}
+
+void positive_indirect_inner_and_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (peopleInTheBuilding > 0 && onFire) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: if (peopleInTheBuilding > 0 ) {
+scream();
+  }
+}
+  }
+}
+
+void positive_direct_inner_or_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire || isCollapsing()) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect_inner_or_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire || isCollapsing()) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: {{^\ *$}}
+scream();
+  }
+  // CHECK-FIXES: {{^\ *$}}
+}
+  }
+}
+
+void positive_direct_inner_or_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (isCollapsing() || onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect_inner_or_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (isCollapsing() || onFire) {
+// CHECK-MESSAGES: 

[PATCH] D71199: [clang-tidy] New check cppcoreguidelines-prefer-member-initializer

2020-08-31 Thread Balogh , Ádám via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGf5fd7486d6c0: [clang-tidy] New check 
readability-prefer-member-initializer (authored by baloghadamsoftware).

Changed prior to commit:
  https://reviews.llvm.org/D71199?vs=285657=288939#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D71199

Files:
  clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
  clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  
clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
  clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-prefer-member-initializer.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer-modernize-use-default-member-init-assignment.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer-modernize-use-default-member-init.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
@@ -0,0 +1,454 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-prefer-member-initializer %t
+
+class Simple1 {
+  int n;
+  double x;
+
+public:
+  Simple1() {
+// CHECK-FIXES: Simple1() : n(0), x(0.0) {
+n = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+x = 0.0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple1(int nn, double xx) {
+// CHECK-FIXES: Simple1(int nn, double xx) : n(nn), x(xx) {
+n = nn;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+x = xx;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple1() = default;
+};
+
+class Simple2 {
+  int n;
+  double x;
+
+public:
+  Simple2() : n(0) {
+// CHECK-FIXES: Simple2() : n(0), x(0.0) {
+x = 0.0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple2(int nn, double xx) : n(nn) {
+// CHECK-FIXES: Simple2(int nn, double xx) : n(nn), x(xx) {
+x = xx;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple2() = default;
+};
+
+class Simple3 {
+  int n;
+  double x;
+
+public:
+  Simple3() : x(0.0) {
+// CHECK-FIXES: Simple3() : n(0), x(0.0) {
+n = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple3(int nn, double xx) : x(xx) {
+// CHECK-FIXES: Simple3(int nn, double xx) : n(nn), x(xx) {
+n = nn;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple3() = default;
+};
+
+int something_int();
+double something_double();
+
+class Simple4 {
+  int n;
+
+public:
+  Simple4() {
+// CHECK-FIXES: Simple4() : n(something_int()) {
+n = something_int();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple4() = default;
+};
+
+static bool dice();
+
+class Complex1 {
+  int n;
+  int m;
+
+public:
+  Complex1() : n(0) {
+if (dice())
+  m = 1;
+// NO-MESSAGES: initialization of 'm' is nested in a conditional expression
+  }
+
+  ~Complex1() = default;
+};
+
+class Complex2 {
+  int n;
+  int m;
+
+public:
+  Complex2() : n(0) {
+if (!dice())
+  return;
+m = 1;
+// NO-MESSAGES: initialization of 'm' follows a conditional expression
+  }
+
+  

[PATCH] D85351: [Analyzer] Fix for `ExprEngine::computeObjectUnderConstruction()` for base and delegating consturctor initializers

2020-08-31 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.
Herald added a subscriber: danielkiss.

In D85351#2215547 , @Szelethus wrote:

> Shouldn't we create a new test care for this, instead of expanding an 
> existing one? Btw, this looks great, but I lack the confidence to accept.

Why should we? This is just a fix for cases not covered, but it is the same 
functionality (retrieving the return value under construction). I added the 
missed cases to the test of this exact functionality.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D85351

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


[PATCH] D71199: [clang-tidy] New check cppcoreguidelines-prefer-member-initializer

2020-08-14 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 285657.
baloghadamsoftware added a comment.

Updated according to a comment.


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

https://reviews.llvm.org/D71199

Files:
  clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
  clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  
clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
  clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-prefer-member-initializer.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer-modernize-use-default-member-init-assignment.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer-modernize-use-default-member-init.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
@@ -0,0 +1,454 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-prefer-member-initializer %t
+
+class Simple1 {
+  int n;
+  double x;
+
+public:
+  Simple1() {
+// CHECK-FIXES: Simple1() : n(0), x(0.0) {
+n = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+x = 0.0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple1(int nn, double xx) {
+// CHECK-FIXES: Simple1(int nn, double xx) : n(nn), x(xx) {
+n = nn;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+x = xx;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple1() = default;
+};
+
+class Simple2 {
+  int n;
+  double x;
+
+public:
+  Simple2() : n(0) {
+// CHECK-FIXES: Simple2() : n(0), x(0.0) {
+x = 0.0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple2(int nn, double xx) : n(nn) {
+// CHECK-FIXES: Simple2(int nn, double xx) : n(nn), x(xx) {
+x = xx;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple2() = default;
+};
+
+class Simple3 {
+  int n;
+  double x;
+
+public:
+  Simple3() : x(0.0) {
+// CHECK-FIXES: Simple3() : n(0), x(0.0) {
+n = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple3(int nn, double xx) : x(xx) {
+// CHECK-FIXES: Simple3(int nn, double xx) : n(nn), x(xx) {
+n = nn;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple3() = default;
+};
+
+int something_int();
+double something_double();
+
+class Simple4 {
+  int n;
+
+public:
+  Simple4() {
+// CHECK-FIXES: Simple4() : n(something_int()) {
+n = something_int();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple4() = default;
+};
+
+static bool dice();
+
+class Complex1 {
+  int n;
+  int m;
+
+public:
+  Complex1() : n(0) {
+if (dice())
+  m = 1;
+// NO-MESSAGES: initialization of 'm' is nested in a conditional expression
+  }
+
+  ~Complex1() = default;
+};
+
+class Complex2 {
+  int n;
+  int m;
+
+public:
+  Complex2() : n(0) {
+if (!dice())
+  return;
+m = 1;
+// NO-MESSAGES: initialization of 'm' follows a conditional expression
+  }
+
+  ~Complex2() = default;
+};
+
+class Complex3 {
+  int n;
+  int m;
+
+public:
+  Complex3() : n(0) {
+while (dice())
+  m = 1;
+// NO-MESSAGES: initialization of 'm' is nested in a conditional 

[PATCH] D81272: [clang-tidy] New check `bugprone-redundant-branch-condition`

2020-08-14 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 285656.
baloghadamsoftware added a comment.

Tests andd for not yet handled cases. Known limiatations included in the docs.


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

https://reviews.llvm.org/D81272

Files:
  clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
  clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.cpp
  clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/bugprone-redundant-branch-condition.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp
@@ -0,0 +1,1190 @@
+// RUN: %check_clang_tidy %s bugprone-redundant-branch-condition %t
+
+extern unsigned peopleInTheBuilding;
+extern unsigned fireFighters;
+
+bool isBurning();
+bool isReallyBurning();
+bool isCollapsing();
+void tryToExtinguish(bool&);
+void tryPutFireOut();
+bool callTheFD();
+void scream();
+
+bool someOtherCondition();
+
+//===--- Basic Positives --===//
+
+void positive_direct() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire)
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: {{^\ *$}}
+scream();
+}
+  }
+}
+
+void positive_direct_inner_and_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire && peopleInTheBuilding > 0) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: if ( peopleInTheBuilding > 0) {
+  scream();
+}
+  }
+}
+
+void positive_indirect_inner_and_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire && peopleInTheBuilding > 0) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: if ( peopleInTheBuilding > 0) {
+scream();
+  }
+}
+  }
+}
+
+void positive_direct_inner_and_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (peopleInTheBuilding > 0 && onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: if (peopleInTheBuilding > 0 ) {
+  scream();
+}
+  }
+}
+
+void positive_indirect_inner_and_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (peopleInTheBuilding > 0 && onFire) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: if (peopleInTheBuilding > 0 ) {
+scream();
+  }
+}
+  }
+}
+
+void positive_direct_inner_or_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire || isCollapsing()) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect_inner_or_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire || isCollapsing()) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: {{^\ *$}}
+scream();
+  }
+  // CHECK-FIXES: {{^\ *$}}
+}
+  }
+}
+
+void positive_direct_inner_or_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (isCollapsing() || onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect_inner_or_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (isCollapsing() || onFire) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: {{^\ *$}}
+scream();
+   

[PATCH] D81272: [clang-tidy] New check `bugprone-redundant-branch-condition`

2020-08-14 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

In D81272#2218050 , @aaron.ballman 
wrote:

> Thanks to the new info, I think the check basically LGTM. Can you add some 
> negative tests and documentation wording to make it clear that the check 
> doesn't currently handle all logically equivalent predicates, like:
>
>   if (foo) {
>   } else {
> if (!foo) {
> }
>   }
>   
>   // or
>   if (foo > 5) {
> if (foo > 3) {
> }
>   }
>   
>   // or
>   if (foo > 5) {
> if (5 < foo) {
> }
>   }
>
> (I'm assuming these cases aren't handled currently and that handling them 
> isn't necessary to land the patch.)

Not even equality is handled yet, just single booleans.


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

https://reviews.llvm.org/D81272

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


[PATCH] D81272: [clang-tidy] New check `bugprone-redundant-branch-condition`

2020-08-14 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 285608.
baloghadamsoftware added a comment.

It seems that //release notes// were not renamed automatically. I updated it 
manually now.


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

https://reviews.llvm.org/D81272

Files:
  clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
  clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.cpp
  clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/bugprone-redundant-branch-condition.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp
@@ -0,0 +1,1153 @@
+// RUN: %check_clang_tidy %s bugprone-redundant-branch-condition %t
+
+extern unsigned peopleInTheBuilding;
+extern unsigned fireFighters;
+
+bool isBurning();
+bool isReallyBurning();
+bool isCollapsing();
+void tryToExtinguish(bool&);
+void tryPutFireOut();
+bool callTheFD();
+void scream();
+
+bool someOtherCondition();
+
+//===--- Basic Positives --===//
+
+void positive_direct() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire)
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: {{^\ *$}}
+scream();
+}
+  }
+}
+
+void positive_direct_inner_and_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire && peopleInTheBuilding > 0) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: if ( peopleInTheBuilding > 0) {
+  scream();
+}
+  }
+}
+
+void positive_indirect_inner_and_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire && peopleInTheBuilding > 0) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: if ( peopleInTheBuilding > 0) {
+scream();
+  }
+}
+  }
+}
+
+void positive_direct_inner_and_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (peopleInTheBuilding > 0 && onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: if (peopleInTheBuilding > 0 ) {
+  scream();
+}
+  }
+}
+
+void positive_indirect_inner_and_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (peopleInTheBuilding > 0 && onFire) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: if (peopleInTheBuilding > 0 ) {
+scream();
+  }
+}
+  }
+}
+
+void positive_direct_inner_or_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire || isCollapsing()) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect_inner_or_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire || isCollapsing()) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: {{^\ *$}}
+scream();
+  }
+  // CHECK-FIXES: {{^\ *$}}
+}
+  }
+}
+
+void positive_direct_inner_or_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (isCollapsing() || onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect_inner_or_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (isCollapsing() || onFire) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: {{^\ *$}}
+

[PATCH] D81272: [clang-tidy] New check `bugprone-redundant-branch-condition`

2020-08-14 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 285606.
baloghadamsoftware retitled this revision from "[clang-tidy] New check 
`misc-redundant-condition`" to "[clang-tidy] New check 
`bugprone-redundant-branch-condition`".
baloghadamsoftware edited the summary of this revision.
baloghadamsoftware added a comment.

Check renamed.


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

https://reviews.llvm.org/D81272

Files:
  clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
  clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.cpp
  clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/bugprone-redundant-branch-condition.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp
@@ -0,0 +1,1153 @@
+// RUN: %check_clang_tidy %s bugprone-redundant-branch-condition %t
+
+extern unsigned peopleInTheBuilding;
+extern unsigned fireFighters;
+
+bool isBurning();
+bool isReallyBurning();
+bool isCollapsing();
+void tryToExtinguish(bool&);
+void tryPutFireOut();
+bool callTheFD();
+void scream();
+
+bool someOtherCondition();
+
+//===--- Basic Positives --===//
+
+void positive_direct() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire)
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: {{^\ *$}}
+scream();
+}
+  }
+}
+
+void positive_direct_inner_and_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire && peopleInTheBuilding > 0) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: if ( peopleInTheBuilding > 0) {
+  scream();
+}
+  }
+}
+
+void positive_indirect_inner_and_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire && peopleInTheBuilding > 0) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: if ( peopleInTheBuilding > 0) {
+scream();
+  }
+}
+  }
+}
+
+void positive_direct_inner_and_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (peopleInTheBuilding > 0 && onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: if (peopleInTheBuilding > 0 ) {
+  scream();
+}
+  }
+}
+
+void positive_indirect_inner_and_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (peopleInTheBuilding > 0 && onFire) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: if (peopleInTheBuilding > 0 ) {
+scream();
+  }
+}
+  }
+}
+
+void positive_direct_inner_or_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire || isCollapsing()) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect_inner_or_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire || isCollapsing()) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+// CHECK-FIXES: {{^\ *$}}
+scream();
+  }
+  // CHECK-FIXES: {{^\ *$}}
+}
+  }
+}
+
+void positive_direct_inner_or_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (isCollapsing() || onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect_inner_or_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (isCollapsing() || onFire) {
+// 

[PATCH] D81272: [clang-tidy] New check `misc-redundant-condition`

2020-08-14 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp:46
+CheckFactories.registerCheck(
+"misc-redundant-condition");
 CheckFactories.registerCheck(

aaron.ballman wrote:
> baloghadamsoftware wrote:
> > aaron.ballman wrote:
> > > baloghadamsoftware wrote:
> > > > aaron.ballman wrote:
> > > > > baloghadamsoftware wrote:
> > > > > > aaron.ballman wrote:
> > > > > > > I think this check should probably live in the `bugprone` module, 
> > > > > > > WDYT?
> > > > > > Based on my experience, `bugpronbe` is for checks whose findings 
> > > > > > are bugs that lead to undefined illegal memory access, behavior 
> > > > > > etc. This one is somewhere between that and readability. For 
> > > > > > example, `redundant-expression` is also in `misc`. But if you wish, 
> > > > > > I can move this checker into `bugprone`.
> > > > > The `bugprone` module has less to do with memory access or undefined 
> > > > > behavior specifically and more to do with checks that should expose 
> > > > > bugs in your code but don't belong to other categories. We try to 
> > > > > keep checks out of `misc` as much as possible these days and this 
> > > > > code pattern is attempting to find cases where the user potentially 
> > > > > has a bug, so I think `bugprone` is the correct home for it.
> > > > > 
> > > > > However, `bugprone` has a similar check and I sort of wonder whether 
> > > > > we should be extending that check rather than adding a separate one. 
> > > > > See `bugprone-branch-clone` which catches the highly related 
> > > > > situation where you have a chain of conditionals and one of the 
> > > > > conditions is repeated. e.g.,
> > > > > ```
> > > > > if (foo) {
> > > > >   if (foo) { // Caught by misc-redundant-condition
> > > > >   }
> > > > > } else if (foo) { // Caught by bugprone-branch-clone
> > > > > }
> > > > > ```
> > > > > Even if we don't combine the checks, we should ensure their behaviors 
> > > > > work well together (catch the same scenarios, don't repeat 
> > > > > diagnostics, etc).
> > > > OK, I will put this into `bugprone`. The two checks may look similar, 
> > > > but this one is more complex because it does not check for the same 
> > > > condition in multiple branches of the same branch statement but checks 
> > > > whether the condition expression could be mutated between the two 
> > > > branch statements. Therefore the the whole logic is totally different, 
> > > > I see no point in merging the two. Should I create a test case then, 
> > > > where both are enabled?
> > > > Therefore the the whole logic is totally different, I see no point in 
> > > > merging the two. 
> > > 
> > > I'm approaching the question from the perspective of the user, not a 
> > > check author. These two checks do the same thing (find redundant 
> > > conditions in flow control which look like they could be a logical 
> > > mistake), so why should they be two separate checks? "Because the code 
> > > looks different" isn't super compelling from that perspective, so I'm 
> > > trying to figure out what the underlying principles are for the checks. 
> > > If they're the same principle, they should be the same check. If they're 
> > > fundamentally different principles, we should be able to explain when to 
> > > use each check as part of their documentation without it sounding 
> > > contrived. (Note, I'm not saying the checks have to be combined, but I am 
> > > pushing back on adding an entirely new check that seems to be redundant 
> > > from a user perspective.)
> > > 
> > > As a litmus test: can you think of a situation where you'd want only one 
> > > of these two checks enabled? I can't think of a case where I'd care about 
> > > redundancy in nested conditionals but not in chained conditionals (or 
> > > vice versa) unless one of the checks had a really high false positive 
> > > rate (which isn't much of a reason to split the checks anyway).
> > > 
> > > > Should I create a test case then, where both are enabled?
> > > 
> > > If we wind up keeping the checks separate, then probably yes (also, the 
> > > documentation for the checks should be updated to explain how they're 
> > > different and why that's useful).
> > There are many checks that users almost always keep enabled together, but 
> > they are still separate checks. Now I looked into the branch clone check, 
> > combining them means simply copying them together because the logic is so 
> > much different.
> > 
> > Even from the user's perspective I see that branches with identical 
> > conditions are different from redundant checks. While the first one is a 
> > more serious bug (the second branch with the same condition is never 
> > executed) this one is slightly more than a readability error.
> > There are many checks that users almost always keep enabled together, but 
> > they are still separate checks. 
> 
> I cannot find an instance with two 

[PATCH] D81272: [clang-tidy] New check `misc-redundant-condition`

2020-08-13 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp:46
+CheckFactories.registerCheck(
+"misc-redundant-condition");
 CheckFactories.registerCheck(

aaron.ballman wrote:
> baloghadamsoftware wrote:
> > aaron.ballman wrote:
> > > baloghadamsoftware wrote:
> > > > aaron.ballman wrote:
> > > > > I think this check should probably live in the `bugprone` module, 
> > > > > WDYT?
> > > > Based on my experience, `bugpronbe` is for checks whose findings are 
> > > > bugs that lead to undefined illegal memory access, behavior etc. This 
> > > > one is somewhere between that and readability. For example, 
> > > > `redundant-expression` is also in `misc`. But if you wish, I can move 
> > > > this checker into `bugprone`.
> > > The `bugprone` module has less to do with memory access or undefined 
> > > behavior specifically and more to do with checks that should expose bugs 
> > > in your code but don't belong to other categories. We try to keep checks 
> > > out of `misc` as much as possible these days and this code pattern is 
> > > attempting to find cases where the user potentially has a bug, so I think 
> > > `bugprone` is the correct home for it.
> > > 
> > > However, `bugprone` has a similar check and I sort of wonder whether we 
> > > should be extending that check rather than adding a separate one. See 
> > > `bugprone-branch-clone` which catches the highly related situation where 
> > > you have a chain of conditionals and one of the conditions is repeated. 
> > > e.g.,
> > > ```
> > > if (foo) {
> > >   if (foo) { // Caught by misc-redundant-condition
> > >   }
> > > } else if (foo) { // Caught by bugprone-branch-clone
> > > }
> > > ```
> > > Even if we don't combine the checks, we should ensure their behaviors 
> > > work well together (catch the same scenarios, don't repeat diagnostics, 
> > > etc).
> > OK, I will put this into `bugprone`. The two checks may look similar, but 
> > this one is more complex because it does not check for the same condition 
> > in multiple branches of the same branch statement but checks whether the 
> > condition expression could be mutated between the two branch statements. 
> > Therefore the the whole logic is totally different, I see no point in 
> > merging the two. Should I create a test case then, where both are enabled?
> > Therefore the the whole logic is totally different, I see no point in 
> > merging the two. 
> 
> I'm approaching the question from the perspective of the user, not a check 
> author. These two checks do the same thing (find redundant conditions in flow 
> control which look like they could be a logical mistake), so why should they 
> be two separate checks? "Because the code looks different" isn't super 
> compelling from that perspective, so I'm trying to figure out what the 
> underlying principles are for the checks. If they're the same principle, they 
> should be the same check. If they're fundamentally different principles, we 
> should be able to explain when to use each check as part of their 
> documentation without it sounding contrived. (Note, I'm not saying the checks 
> have to be combined, but I am pushing back on adding an entirely new check 
> that seems to be redundant from a user perspective.)
> 
> As a litmus test: can you think of a situation where you'd want only one of 
> these two checks enabled? I can't think of a case where I'd care about 
> redundancy in nested conditionals but not in chained conditionals (or vice 
> versa) unless one of the checks had a really high false positive rate (which 
> isn't much of a reason to split the checks anyway).
> 
> > Should I create a test case then, where both are enabled?
> 
> If we wind up keeping the checks separate, then probably yes (also, the 
> documentation for the checks should be updated to explain how they're 
> different and why that's useful).
There are many checks that users almost always keep enabled together, but they 
are still separate checks. Now I looked into the branch clone check, combining 
them means simply copying them together because the logic is so much different.

Even from the user's perspective I see that branches with identical conditions 
are different from redundant checks. While the first one is a more serious bug 
(the second branch with the same condition is never executed) this one is 
slightly more than a readability error.


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

https://reviews.llvm.org/D81272

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


[PATCH] D71199: [clang-tidy] New check cppcoreguidelines-prefer-member-initializer

2020-08-13 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 285366.
baloghadamsoftware added a comment.

Since no better idea cam to my mind, in this version I check whether 
`modernize-use-default-member-init` is enabled. If it is, then we issue a 
warning and suggest a fix that uses default member initializer. We also take 
into account the option for that checker whether we should use brackets or 
assignment. This checker has no options now. If the other checker is not 
enabled, we always warn and suggest fix to use constructor member initializer.


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

https://reviews.llvm.org/D71199

Files:
  clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
  clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  
clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.cpp
  clang-tools-extra/clang-tidy/cppcoreguidelines/PreferMemberInitializerCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-prefer-member-initializer.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-prefer-member-initializer.cpp
@@ -0,0 +1,454 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-prefer-member-initializer %t
+
+class Simple1 {
+  int n;
+  double x;
+
+public:
+  Simple1() {
+// CHECK-FIXES: Simple1() : n(0), x(0.0) {
+n = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+x = 0.0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple1(int nn, double xx) {
+// CHECK-FIXES: Simple1(int nn, double xx) : n(nn), x(xx) {
+n = nn;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+x = xx;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple1() = default;
+};
+
+class Simple2 {
+  int n;
+  double x;
+
+public:
+  Simple2() : n(0) {
+// CHECK-FIXES: Simple2() : n(0), x(0.0) {
+x = 0.0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple2(int nn, double xx) : n(nn) {
+// CHECK-FIXES: Simple2(int nn, double xx) : n(nn), x(xx) {
+x = xx;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple2() = default;
+};
+
+class Simple3 {
+  int n;
+  double x;
+
+public:
+  Simple3() : x(0.0) {
+// CHECK-FIXES: Simple3() : n(0), x(0.0) {
+n = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  Simple3(int nn, double xx) : x(xx) {
+// CHECK-FIXES: Simple3(int nn, double xx) : n(nn), x(xx) {
+n = nn;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple3() = default;
+};
+
+int something_int();
+double something_double();
+
+class Simple4 {
+  int n;
+
+public:
+  Simple4() {
+// CHECK-FIXES: Simple4() : n(something_int()) {
+n = something_int();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
+// CHECK-FIXES: {{^\ *$}}
+  }
+
+  ~Simple4() = default;
+};
+
+static bool dice();
+
+class Complex1 {
+  int n;
+  int m;
+
+public:
+  Complex1() : n(0) {
+if (dice())
+  m = 1;
+// NO-MESSAGES: initialization of 'm' is nested in a conditional expression
+  }
+
+  ~Complex1() = default;
+};
+
+class Complex2 {
+  int n;
+  int m;
+
+public:
+  Complex2() : n(0) {
+if (!dice())
+  return;
+m = 1;
+// NO-MESSAGES: initialization of 'm' follows a conditional expression
+  }
+
+  ~Complex2() = default;
+};
+
+class Complex3 {
+  

[PATCH] D81272: [clang-tidy] New check `misc-redundant-condition`

2020-08-13 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp:46
+CheckFactories.registerCheck(
+"misc-redundant-condition");
 CheckFactories.registerCheck(

aaron.ballman wrote:
> baloghadamsoftware wrote:
> > aaron.ballman wrote:
> > > I think this check should probably live in the `bugprone` module, WDYT?
> > Based on my experience, `bugpronbe` is for checks whose findings are bugs 
> > that lead to undefined illegal memory access, behavior etc. This one is 
> > somewhere between that and readability. For example, `redundant-expression` 
> > is also in `misc`. But if you wish, I can move this checker into `bugprone`.
> The `bugprone` module has less to do with memory access or undefined behavior 
> specifically and more to do with checks that should expose bugs in your code 
> but don't belong to other categories. We try to keep checks out of `misc` as 
> much as possible these days and this code pattern is attempting to find cases 
> where the user potentially has a bug, so I think `bugprone` is the correct 
> home for it.
> 
> However, `bugprone` has a similar check and I sort of wonder whether we 
> should be extending that check rather than adding a separate one. See 
> `bugprone-branch-clone` which catches the highly related situation where you 
> have a chain of conditionals and one of the conditions is repeated. e.g.,
> ```
> if (foo) {
>   if (foo) { // Caught by misc-redundant-condition
>   }
> } else if (foo) { // Caught by bugprone-branch-clone
> }
> ```
> Even if we don't combine the checks, we should ensure their behaviors work 
> well together (catch the same scenarios, don't repeat diagnostics, etc).
OK, I will put this into `bugprone`. The two checks may look similar, but this 
one is more complex because it does not check for the same condition in 
multiple branches of the same branch statement but checks whether the condition 
expression could be mutated between the two branch statements. Therefore the 
the whole logic is totally different, I see no point in merging the two. Should 
I create a test case then, where both are enabled?


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

https://reviews.llvm.org/D81272

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


[PATCH] D85351: [Analyzer] Fix for `ExprEngine::computeObjectUnderConstruction()` for base and delegating consturctor initializers

2020-08-13 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

@NoQ Could you please take a look on this one? It is a fix of my earlier work.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D85351

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


[PATCH] D85728: [Analyzer] Support for the new variadic isa<> and isa_and_not_null<> in CastValueChecker

2020-08-13 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware marked 2 inline comments as done.
baloghadamsoftware added a comment.

@NoQ Thank you for the review. Please also review D85752 
 after my update and tell me what I have to 
change there if it is not acceptable yet. This patch depends on that one.


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

https://reviews.llvm.org/D85728

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


[PATCH] D77229: [Analyzer] Avoid handling of LazyCompundVals in IteratorModeling

2020-08-13 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware marked an inline comment as done.
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp:77
 
+  unsigned ArgNum = 999;
+

gamesh411 wrote:
> 999 seems a bit arbitrary here, consider using 
> std::numeric_limits::max(), or llvm::Optional.
I refactored this part. The earlier approach was very ugly and non-standard. I 
just intended to make it work as quickly as possible, but I forgot to refactor 
after that. Thank you for noticing it!


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

https://reviews.llvm.org/D77229

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


[PATCH] D77229: [Analyzer] Avoid handling of LazyCompundVals in IteratorModeling

2020-08-13 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 285326.
baloghadamsoftware added a comment.

Updated according to the latest comment.


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

https://reviews.llvm.org/D77229

Files:
  clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
  clang/lib/StaticAnalyzer/Checkers/Iterator.h
  clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
  clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
  clang/test/Analysis/iterator-modeling.cpp

Index: clang/test/Analysis/iterator-modeling.cpp
===
--- clang/test/Analysis/iterator-modeling.cpp
+++ clang/test/Analysis/iterator-modeling.cpp
@@ -1990,6 +1990,55 @@
 ++i0;
 }
 
+template 
+struct delegated_ctor_iterator {
+  delegated_ctor_iterator(const T&, int);
+  delegated_ctor_iterator(const T& t) : delegated_ctor_iterator(t, 0) {}
+  delegated_ctor_iterator operator++();
+  delegated_ctor_iterator operator++(int);
+  T& operator*();
+};
+
+template 
+struct container_with_delegated_ctor_iterator {
+  typedef delegated_ctor_iterator iterator;
+  iterator begin() const { return delegated_ctor_iterator(T()); }
+};
+
+void
+test_delegated_ctor_iterator(
+const container_with_delegated_ctor_iterator ) {
+  auto i = c.begin(); // no-crash
+  clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()");
+  clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.begin()}}
+}
+
+template 
+struct base_ctor_iterator {
+  base_ctor_iterator(const T&);
+  base_ctor_iterator operator++();
+  base_ctor_iterator operator++(int);
+  T& operator*();
+};
+
+template 
+struct derived_ctor_iterator: public base_ctor_iterator {
+  derived_ctor_iterator(const T& t) : base_ctor_iterator(t) {}
+};
+
+template 
+struct container_with_derived_ctor_iterator {
+  typedef derived_ctor_iterator iterator;
+  iterator begin() const { return derived_ctor_iterator(T()); }
+};
+
+void
+test_derived_ctor_iterator(const container_with_derived_ctor_iterator ) {
+  auto i = c.begin();
+  clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()");
+  clang_analyzer_express(clang_analyzer_iterator_position(i)); // expected-warning{{$c.begin()}}
+}
+
 void clang_analyzer_printState();
 
 void print_state(std::vector ) {
Index: clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
@@ -24,12 +24,12 @@
 namespace {
 
 class STLAlgorithmModeling : public Checker {
-  bool evalFind(CheckerContext , const CallExpr *CE) const;
+  void evalFind(CheckerContext , const CallExpr *CE, SVal Begin,
+SVal End) const;
 
-  void Find(CheckerContext , const CallExpr *CE, unsigned paramNum) const;
-
-  using FnCheck = bool (STLAlgorithmModeling::*)(CheckerContext &,
-const CallExpr *) const;
+  using FnCheck = void (STLAlgorithmModeling::*)(CheckerContext &,
+ const CallExpr *, SVal Begin,
+ SVal End) const;
 
   const CallDescriptionMap Callbacks = {
 {{{"std", "find"}, 3}, ::evalFind},
@@ -67,51 +67,45 @@
 
 bool STLAlgorithmModeling::evalCall(const CallEvent ,
 CheckerContext ) const {
-  const auto *CE = dyn_cast_or_null(Call.getOriginExpr());
-  if (!CE)
-return false;
-
-  const FnCheck *Handler = Callbacks.lookup(Call);
-  if (!Handler)
-return false;
-
-  return (this->**Handler)(C, CE);
-}
-
-bool STLAlgorithmModeling::evalFind(CheckerContext ,
-const CallExpr *CE) const {
   // std::find()-like functions either take their primary range in the first
   // two parameters, or if the first parameter is "execution policy" then in
   // the second and third. This means that the second parameter must always be
   // an iterator.
-  if (!isIteratorType(CE->getArg(1)->getType()))
+  if (Call.getNumArgs() < 2 || !isIteratorType(Call.getArgExpr(1)->getType()))
 return false;
 
   // If no "execution policy" parameter is used then the first argument is the
-  // beginning of the range.
-  if (isIteratorType(CE->getArg(0)->getType())) {
-Find(C, CE, 0);
-return true;
+  // beginning of the range. If "execution policy" parmeter is used then the
+  // third argument is the end of the range.
+  unsigned ArgNum = 0;
+  if (!isIteratorType(Call.getArgExpr(0)->getType())) {
+if (Call.getNumArgs() < 3 || !isIteratorType(Call.getArgExpr(2)->getType()))
+

[PATCH] D81272: [clang-tidy] New check `misc-redundant-condition`

2020-08-13 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware marked 3 inline comments as done.
baloghadamsoftware added inline comments.



Comment at: clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp:46
+CheckFactories.registerCheck(
+"misc-redundant-condition");
 CheckFactories.registerCheck(

aaron.ballman wrote:
> I think this check should probably live in the `bugprone` module, WDYT?
Based on my experience, `bugpronbe` is for checks whose findings are bugs that 
lead to undefined illegal memory access, behavior etc. This one is somewhere 
between that and readability. For example, `redundant-expression` is also in 
`misc`. But if you wish, I can move this checker into `bugprone`.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/misc-redundant-condition.cpp:1097
+  }
+}

aaron.ballman wrote:
> baloghadamsoftware wrote:
> > aaron.ballman wrote:
> > > Can you add some tests that exercise GNU expression statements, just to 
> > > make sure we get the behavior correct?
> > > ```
> > > if (({foo;})) {
> > > } else if (({foo;})) {
> > > }
> > > 
> > > if (foo) ({bar;});
> > > else if (foo) ({bar;});
> > > ```
> > > Another thing that's interesting to test is whether the redundant 
> > > expression is in a subexpression which doesn't contribute to the value of 
> > > the control expression:
> > > ```
> > > if (foo(), val) {
> > > } else if (foo(), other_val) {
> > > }
> > > ```
> > > (Similar can be tested with GNU statement expressions.)
> > Do you mean that I should handle these cases as well? (Detect a bug, 
> > provide a fix.)
> If the check misses these cases, I think that's reasonable (just comment that 
> the tests aren't currently handled). If the check diagnoses these cases but 
> the fixit causes an issue, then I think that should be corrected in this 
> patch. If it's trivial to support these cases (diagnosing or fixing), it's 
> your call on whether you want to do so. I mostly just want the test coverage 
> so I can know what to expect.
The check currently misses these cases completely, so I left a `FIXME` there. I 
can do it in the near future, but first I would like to commit a first version 
so I can tell the user who requested it that his request is fulfilled.


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

https://reviews.llvm.org/D81272

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


[PATCH] D81272: [clang-tidy] New check `misc-redundant-condition`

2020-08-13 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 285309.
baloghadamsoftware added a comment.

Updated according to the comments.


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

https://reviews.llvm.org/D81272

Files:
  clang-tools-extra/clang-tidy/misc/CMakeLists.txt
  clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
  clang-tools-extra/clang-tidy/misc/RedundantConditionCheck.cpp
  clang-tools-extra/clang-tidy/misc/RedundantConditionCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/misc-redundant-condition.rst
  clang-tools-extra/test/clang-tidy/checkers/misc-redundant-condition.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/misc-redundant-condition.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/misc-redundant-condition.cpp
@@ -0,0 +1,1153 @@
+// RUN: %check_clang_tidy %s misc-redundant-condition %t
+
+extern unsigned peopleInTheBuilding;
+extern unsigned fireFighters;
+
+bool isBurning();
+bool isReallyBurning();
+bool isCollapsing();
+void tryToExtinguish(bool&);
+void tryPutFireOut();
+bool callTheFD();
+void scream();
+
+bool someOtherCondition();
+
+//===--- Basic Positives --===//
+
+void positive_direct() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [misc-redundant-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire)
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [misc-redundant-condition]
+// CHECK-FIXES: {{^\ *$}}
+scream();
+}
+  }
+}
+
+void positive_direct_inner_and_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire && peopleInTheBuilding > 0) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [misc-redundant-condition]
+  // CHECK-FIXES: if ( peopleInTheBuilding > 0) {
+  scream();
+}
+  }
+}
+
+void positive_indirect_inner_and_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire && peopleInTheBuilding > 0) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [misc-redundant-condition]
+// CHECK-FIXES: if ( peopleInTheBuilding > 0) {
+scream();
+  }
+}
+  }
+}
+
+void positive_direct_inner_and_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (peopleInTheBuilding > 0 && onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [misc-redundant-condition]
+  // CHECK-FIXES: if (peopleInTheBuilding > 0 ) {
+  scream();
+}
+  }
+}
+
+void positive_indirect_inner_and_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (peopleInTheBuilding > 0 && onFire) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [misc-redundant-condition]
+// CHECK-FIXES: if (peopleInTheBuilding > 0 ) {
+scream();
+  }
+}
+  }
+}
+
+void positive_direct_inner_or_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (onFire || isCollapsing()) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [misc-redundant-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect_inner_or_lhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (onFire || isCollapsing()) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [misc-redundant-condition]
+// CHECK-FIXES: {{^\ *$}}
+scream();
+  }
+  // CHECK-FIXES: {{^\ *$}}
+}
+  }
+}
+
+void positive_direct_inner_or_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (isCollapsing() || onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [misc-redundant-condition]
+  // CHECK-FIXES: {{^\ *$}}
+  scream();
+}
+// CHECK-FIXES: {{^\ *$}}
+  }
+}
+
+void positive_indirect_inner_or_rhs() {
+  bool onFire = isBurning();
+  if (onFire) {
+if (someOtherCondition()) {
+  if (isCollapsing() || onFire) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [misc-redundant-condition]
+// CHECK-FIXES: {{^\ *$}}
+scream();
+  }
+  // CHECK-FIXES: {{^\ *$}}
+}
+  }
+}
+
+void positive_direct_outer_and_lhs() {
+  bool onFire = isBurning();
+  if (onFire && fireFighters < 10) {
+if (onFire) {
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant 

[PATCH] D81272: [clang-tidy] New check `misc-redundant-condition`

2020-08-12 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added inline comments.



Comment at: clang-tools-extra/clang-tidy/misc/RedundantConditionCheck.cpp:73
+  // If the variable has an alias then it can be changed by that alias as well.
+  // FIXME: Track pointers and references.
+  if (hasPtrOrReferenceInFunc(Func, CondVar))

aaron.ballman wrote:
> This FIXME makes me worried that what we really want is a clang static 
> analyzer check, since the check is already flow sensitive and needs to be 
> data sensitive as well. Have you considered implementing this as a static 
> analyzer check?
Actually, it is only a proposal for improvement. Maybe FIXME is not the best 
wording for it. This is not a bug to fix, just a possibility to find more true 
positives. This check is very similar to the infinite loop check which is also 
in Tidy. In the Static Analyzer this check would be too heavyweight and would 
probably produce false positives.



Comment at: 
clang-tools-extra/test/clang-tidy/checkers/misc-redundant-condition.cpp:1097
+  }
+}

aaron.ballman wrote:
> Can you add some tests that exercise GNU expression statements, just to make 
> sure we get the behavior correct?
> ```
> if (({foo;})) {
> } else if (({foo;})) {
> }
> 
> if (foo) ({bar;});
> else if (foo) ({bar;});
> ```
> Another thing that's interesting to test is whether the redundant expression 
> is in a subexpression which doesn't contribute to the value of the control 
> expression:
> ```
> if (foo(), val) {
> } else if (foo(), other_val) {
> }
> ```
> (Similar can be tested with GNU statement expressions.)
Do you mean that I should handle these cases as well? (Detect a bug, provide a 
fix.)


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

https://reviews.llvm.org/D81272

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


[PATCH] D85728: [Analyzer] Support for the new variadic isa<> and isa_and_not_null<> in CastValueChecker

2020-08-12 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware marked 3 inline comments as done.
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp:270-272
+default:
+  llvm_unreachable("Invalid template argument for isa<> or "
+   "isa_and_nonnull<>");

NoQ wrote:
> We shouldn't crash when code under analysis doesn't match our expectation.
The question is whether we can get any other template argument kind for 
`llvm::isa<>()` and `llvm::isa_and_nonnull<>()` than `Type` or `Pack`?



Comment at: clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp:315
+if (CastSucceeds) {
+  Success = true;
+  C.addTransition(

NoQ wrote:
> Let's return immediately after the transition instead. Like, generally, it's 
> a good practice to return immediately after a transition if you don't plan 
> any more state splits, because otherwise it's too easy to accidentally 
> introduce unwanted state splits.
Now I inserted a return but only if this is a known conversion. If this is an 
assumption, the we should assume every type in the template argument list.


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

https://reviews.llvm.org/D85728

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


[PATCH] D85728: [Analyzer] Support for the new variadic isa<> and isa_and_not_null<> in CastValueChecker

2020-08-12 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 285047.
baloghadamsoftware added a comment.

Updated according to the comments.


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

https://reviews.llvm.org/D85728

Files:
  clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
  clang/test/Analysis/Inputs/llvm.h
  clang/test/Analysis/cast-value-logic.cpp
  clang/test/Analysis/cast-value-notes.cpp

Index: clang/test/Analysis/cast-value-notes.cpp
===
--- clang/test/Analysis/cast-value-notes.cpp
+++ clang/test/Analysis/cast-value-notes.cpp
@@ -13,6 +13,8 @@
   const T *getAs() const;
 };
 class Triangle : public Shape {};
+class Rectangle : public Shape {};
+class Hexagon : public Shape {};
 class Circle : public Shape {};
 } // namespace clang
 
@@ -27,7 +29,6 @@
 }
 
 void evalNonNullParamNonNullReturnReference(const Shape ) {
-  // Unmodeled cast from reference to pointer.
   const auto *C = dyn_cast_or_null(S);
   // expected-note@-1 {{'C' initialized here}}
 
@@ -43,13 +44,37 @@
 return;
   }
 
+  if (dyn_cast_or_null(C)) {
+// expected-note@-1 {{Assuming 'C' is not a 'Rectangle'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (dyn_cast_or_null(C)) {
+// expected-note@-1 {{Assuming 'C' is not a 'Hexagon'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
   if (isa(C)) {
 // expected-note@-1 {{'C' is not a 'Triangle'}}
 // expected-note@-2 {{Taking false branch}}
 return;
   }
 
-  if (isa(C)) {
+  if (isa(C)) {
+// expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (isa(C)) {
+// expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle' nor a 'Hexagon'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (isa(C)) {
 // expected-note@-1 {{'C' is a 'Circle'}}
 // expected-note@-2 {{Taking true branch}}
 
@@ -65,22 +90,57 @@
   // expected-note@-1 {{'S' is a 'Circle'}}
   // expected-note@-2 {{'C' initialized here}}
 
-  if (!isa(C)) {
-// expected-note@-1 {{Assuming 'C' is a 'Triangle'}}
+  if (!dyn_cast_or_null(C)) {
+// expected-note@-1 {{'C' is a 'Circle'}}
 // expected-note@-2 {{Taking false branch}}
 return;
   }
 
-  if (!isa(C)) {
-// expected-note@-1 {{'C' is a 'Triangle'}}
+  if (dyn_cast_or_null(C)) {
+// expected-note@-1 {{Assuming 'C' is not a 'Triangle'}}
 // expected-note@-2 {{Taking false branch}}
 return;
   }
 
-  (void)(1 / !C);
-  // expected-note@-1 {{'C' is non-null}}
-  // expected-note@-2 {{Division by zero}}
-  // expected-warning@-3 {{Division by zero}}
+  if (dyn_cast_or_null(C)) {
+// expected-note@-1 {{Assuming 'C' is not a 'Rectangle'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (dyn_cast_or_null(C)) {
+// expected-note@-1 {{Assuming 'C' is not a 'Hexagon'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (isa(C)) {
+// expected-note@-1 {{'C' is not a 'Triangle'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (isa(C)) {
+// expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (isa(C)) {
+// expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle' nor a 'Hexagon'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (isa(C)) {
+// expected-note@-1 {{'C' is a 'Circle'}}
+// expected-note@-2 {{Taking true branch}}
+
+(void)(1 / !C);
+// expected-note@-1 {{'C' is non-null}}
+// expected-note@-2 {{Division by zero}}
+// expected-warning@-3 {{Division by zero}}
+  }
 }
 
 void evalNonNullParamNullReturn(const Shape *S) {
Index: clang/test/Analysis/cast-value-logic.cpp
===
--- clang/test/Analysis/cast-value-logic.cpp
+++ clang/test/Analysis/cast-value-logic.cpp
@@ -19,6 +19,8 @@
   virtual double area();
 };
 class Triangle : public Shape {};
+class Rectangle : public Shape {};
+class Hexagon : public Shape {};
 class Circle : public Shape {
 public:
   ~Circle();
@@ -39,6 +41,23 @@
 clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
 }
 
+void test_regions_isa_variadic(const Shape *A, const Shape *B) {
+  if (isa(A) &&
+  !isa(B))
+clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
+void test_regions_isa_and_nonnull(const Shape *A, const Shape *B) {
+  if (isa_and_nonnull(A) && !isa_and_nonnull(B))
+clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
+void test_regions_isa_and_nonnull_variadic(const Shape *A, const Shape *B) {
+  if (isa_and_nonnull(A) &&
+  !isa_and_nonnull(B))
+clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
 namespace test_cast {
 void 

[PATCH] D85752: [Analyzer] Store the pointed/referenced type for dynamic casts

2020-08-12 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware marked an inline comment as done.
baloghadamsoftware added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/DynamicType.cpp:73
+Ty = STTPTy->getReplacementType();
+  if (Ty->isPointerType())
+Ty = Ty->getPointeeType();

xazax.hun wrote:
> Is this doing what you intended? What about a reference to a pointer? 
> Wouldn't you do too much unboxing? 
> 
> Also, I think a function returning a value would be more conventional. 
> 
> Other sugars like typedefs cannot interfere? I think this patch might benefit 
> from additional test coverage. I also see no tests for template substitutions.
Reference to pointer cast using //LLVM//'s cast functions are syntactically 
invalid, they do not compile.

For `QualType` in-place modification is usual, since we use it by value.

I see no test coverage for this particular part of the analyzer specifically, 
it seems that its is only tested indirectly in the tests for `CastValueChecker`.


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

https://reviews.llvm.org/D85752

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


[PATCH] D85752: [Analyzer] Store the pointed/referenced type for dynamic casts

2020-08-12 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 285036.
baloghadamsoftware added a comment.

Updated according to the comments.


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

https://reviews.llvm.org/D85752

Files:
  clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
  clang/lib/StaticAnalyzer/Core/DynamicType.cpp
  clang/test/Analysis/cast-value-state-dump.cpp


Index: clang/test/Analysis/cast-value-state-dump.cpp
===
--- clang/test/Analysis/cast-value-state-dump.cpp
+++ clang/test/Analysis/cast-value-state-dump.cpp
@@ -35,8 +35,8 @@
   // CHECK-NEXT: ],
   // CHECK-NEXT: "dynamic_casts": [
   // CHECK:{ "region": "SymRegion{reg_$0}", "casts": [
-  // CHECK-NEXT: { "from": "const struct clang::Shape *", "to": "const 
class clang::Circle *", "kind": "success" },
-  // CHECK-NEXT: { "from": "const struct clang::Shape *", "to": "const 
class clang::Square *", "kind": "fail" }
+  // CHECK-NEXT: { "from": "struct clang::Shape", "to": "class 
clang::Circle", "kind": "success" },
+  // CHECK-NEXT: { "from": "struct clang::Shape", "to": "class 
clang::Square", "kind": "fail" }
   // CHECK-NEXT:   ] }
 
   (void)(1 / !C);
Index: clang/lib/StaticAnalyzer/Core/DynamicType.cpp
===
--- clang/lib/StaticAnalyzer/Core/DynamicType.cpp
+++ clang/lib/StaticAnalyzer/Core/DynamicType.cpp
@@ -65,6 +65,16 @@
   return State->get(MR);
 }
 
+static void unbox(QualType ) {
+  if (Ty->isReferenceType())
+Ty = Ty.getNonReferenceType();
+  Ty = Ty.getCanonicalType();
+  if (Ty->isPointerType())
+Ty = Ty->getPointeeType();
+  Ty = Ty.getCanonicalType();
+  Ty = Ty.getUnqualifiedType();
+}
+
 const DynamicCastInfo *getDynamicCastInfo(ProgramStateRef State,
   const MemRegion *MR,
   QualType CastFromTy,
@@ -73,6 +83,9 @@
   if (!Lookup)
 return nullptr;
 
+  unbox(CastFromTy);
+  unbox(CastToTy);
+
   for (const DynamicCastInfo  : *Lookup)
 if (Cast.equals(CastFromTy, CastToTy))
   return 
@@ -112,6 +125,9 @@
 State = State->set(MR, CastToTy);
   }
 
+  unbox(CastFromTy);
+  unbox(CastToTy);
+
   DynamicCastInfo::CastResult ResultKind =
   CastSucceeds ? DynamicCastInfo::CastResult::Success
: DynamicCastInfo::CastResult::Failure;
Index: clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
@@ -106,7 +106,7 @@
  QualType CastToTy, const Expr *Object,
  bool CastSucceeds, bool IsKnownCast) {
   std::string CastToName =
-  CastInfo ? CastInfo->to()->getPointeeCXXRecordDecl()->getNameAsString()
+  CastInfo ? CastInfo->to()->getAsCXXRecordDecl()->getNameAsString()
: CastToTy->getPointeeCXXRecordDecl()->getNameAsString();
   Object = Object->IgnoreParenImpCasts();
 


Index: clang/test/Analysis/cast-value-state-dump.cpp
===
--- clang/test/Analysis/cast-value-state-dump.cpp
+++ clang/test/Analysis/cast-value-state-dump.cpp
@@ -35,8 +35,8 @@
   // CHECK-NEXT: ],
   // CHECK-NEXT: "dynamic_casts": [
   // CHECK:{ "region": "SymRegion{reg_$0}", "casts": [
-  // CHECK-NEXT: { "from": "const struct clang::Shape *", "to": "const class clang::Circle *", "kind": "success" },
-  // CHECK-NEXT: { "from": "const struct clang::Shape *", "to": "const class clang::Square *", "kind": "fail" }
+  // CHECK-NEXT: { "from": "struct clang::Shape", "to": "class clang::Circle", "kind": "success" },
+  // CHECK-NEXT: { "from": "struct clang::Shape", "to": "class clang::Square", "kind": "fail" }
   // CHECK-NEXT:   ] }
 
   (void)(1 / !C);
Index: clang/lib/StaticAnalyzer/Core/DynamicType.cpp
===
--- clang/lib/StaticAnalyzer/Core/DynamicType.cpp
+++ clang/lib/StaticAnalyzer/Core/DynamicType.cpp
@@ -65,6 +65,16 @@
   return State->get(MR);
 }
 
+static void unbox(QualType ) {
+  if (Ty->isReferenceType())
+Ty = Ty.getNonReferenceType();
+  Ty = Ty.getCanonicalType();
+  if (Ty->isPointerType())
+Ty = Ty->getPointeeType();
+  Ty = Ty.getCanonicalType();
+  Ty = Ty.getUnqualifiedType();
+}
+
 const DynamicCastInfo *getDynamicCastInfo(ProgramStateRef State,
   const MemRegion *MR,
   QualType CastFromTy,
@@ -73,6 +83,9 @@
   if (!Lookup)
 return nullptr;
 
+  unbox(CastFromTy);
+  unbox(CastToTy);
+
   for (const DynamicCastInfo  : *Lookup)
 if (Cast.equals(CastFromTy, CastToTy))
   return 
@@ -112,6 +125,9 @@
 State = State->set(MR, CastToTy);
   }

[PATCH] D85728: [Analyzer] Support for the new variadic isa<> and isa_and_not_null<> in CastValueChecker

2020-08-11 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware updated this revision to Diff 284801.
baloghadamsoftware retitled this revision from "[Analyzer][WIP] Support for the 
new variadic isa<> and isa_and_not_null<> in CastValueChecker" to "[Analyzer] 
Support for the new variadic isa<> and isa_and_not_null<> in CastValueChecker".
baloghadamsoftware edited the summary of this revision.
baloghadamsoftware added a comment.

Working version. Debug printouts removed.


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

https://reviews.llvm.org/D85728

Files:
  clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
  clang/test/Analysis/Inputs/llvm.h
  clang/test/Analysis/cast-value-logic.cpp
  clang/test/Analysis/cast-value-notes.cpp

Index: clang/test/Analysis/cast-value-notes.cpp
===
--- clang/test/Analysis/cast-value-notes.cpp
+++ clang/test/Analysis/cast-value-notes.cpp
@@ -13,6 +13,8 @@
   const T *getAs() const;
 };
 class Triangle : public Shape {};
+class Rectangle : public Shape {};
+class Hexagon : public Shape {};
 class Circle : public Shape {};
 } // namespace clang
 
@@ -27,7 +29,6 @@
 }
 
 void evalNonNullParamNonNullReturnReference(const Shape ) {
-  // Unmodeled cast from reference to pointer.
   const auto *C = dyn_cast_or_null(S);
   // expected-note@-1 {{'C' initialized here}}
 
@@ -43,13 +44,37 @@
 return;
   }
 
+  if (dyn_cast_or_null(C)) {
+// expected-note@-1 {{Assuming 'C' is not a 'Rectangle'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (dyn_cast_or_null(C)) {
+// expected-note@-1 {{Assuming 'C' is not a 'Hexagon'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
   if (isa(C)) {
 // expected-note@-1 {{'C' is not a 'Triangle'}}
 // expected-note@-2 {{Taking false branch}}
 return;
   }
 
-  if (isa(C)) {
+  if (isa(C)) {
+// expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (isa(C)) {
+// expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle' nor a 'Hexagon'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (isa(C)) {
 // expected-note@-1 {{'C' is a 'Circle'}}
 // expected-note@-2 {{Taking true branch}}
 
@@ -65,22 +90,57 @@
   // expected-note@-1 {{'S' is a 'Circle'}}
   // expected-note@-2 {{'C' initialized here}}
 
-  if (!isa(C)) {
-// expected-note@-1 {{Assuming 'C' is a 'Triangle'}}
+  if (!dyn_cast_or_null(C)) {
+// expected-note@-1 {{'C' is a 'Circle'}}
 // expected-note@-2 {{Taking false branch}}
 return;
   }
 
-  if (!isa(C)) {
-// expected-note@-1 {{'C' is a 'Triangle'}}
+  if (dyn_cast_or_null(C)) {
+// expected-note@-1 {{Assuming 'C' is not a 'Triangle'}}
 // expected-note@-2 {{Taking false branch}}
 return;
   }
 
-  (void)(1 / !C);
-  // expected-note@-1 {{'C' is non-null}}
-  // expected-note@-2 {{Division by zero}}
-  // expected-warning@-3 {{Division by zero}}
+  if (dyn_cast_or_null(C)) {
+// expected-note@-1 {{Assuming 'C' is not a 'Rectangle'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (dyn_cast_or_null(C)) {
+// expected-note@-1 {{Assuming 'C' is not a 'Hexagon'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (isa(C)) {
+// expected-note@-1 {{'C' is not a 'Triangle'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (isa(C)) {
+// expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (isa(C)) {
+// expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle' nor a 'Hexagon'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (isa(C)) {
+// expected-note@-1 {{'C' is a 'Circle'}}
+// expected-note@-2 {{Taking true branch}}
+
+(void)(1 / !C);
+// expected-note@-1 {{'C' is non-null}}
+// expected-note@-2 {{Division by zero}}
+// expected-warning@-3 {{Division by zero}}
+  }
 }
 
 void evalNonNullParamNullReturn(const Shape *S) {
Index: clang/test/Analysis/cast-value-logic.cpp
===
--- clang/test/Analysis/cast-value-logic.cpp
+++ clang/test/Analysis/cast-value-logic.cpp
@@ -19,6 +19,8 @@
   virtual double area();
 };
 class Triangle : public Shape {};
+class Rectangle : public Shape {};
+class Hexagon : public Shape {};
 class Circle : public Shape {
 public:
   ~Circle();
@@ -39,6 +41,23 @@
 clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
 }
 
+void test_regions_isa_variadic(const Shape *A, const Shape *B) {
+  if (isa(A) &&
+  !isa(B))
+clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
+void test_regions_isa_and_nonnull(const Shape *A, const Shape *B) {
+  if (isa_and_nonnull(A) && !isa_and_nonnull(B))
+

[PATCH] D85752: [Analyzer] Store the pointed/referenced type for dynamic casts

2020-08-11 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware created this revision.
baloghadamsoftware added reviewers: NoQ, Charusso.
baloghadamsoftware added a project: clang.
Herald added subscribers: ASDenysPetrov, martong, steakhal, gamesh411, dkrupp, 
donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, 
kristof.beyls, xazax.hun, whisperity.
Herald added a reviewer: Szelethus.
baloghadamsoftware requested review of this revision.

The successfulness of a dynamic cast depends only on the //C++ class//, not the 
pointer or reference. Thus if `*A` //is a// `*B`, then `` //is a// ``, 
`const *A` //is a// `const *B` etc. This patch changes `DynamicCastInfo` to 
store and check the cast between the unqualified pointed/referenced types. It 
also removes e.g. `SubstTemplateTypeParmType` from both the pointer and the 
pointed type.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D85752

Files:
  clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
  clang/lib/StaticAnalyzer/Core/DynamicType.cpp
  clang/test/Analysis/cast-value-state-dump.cpp


Index: clang/test/Analysis/cast-value-state-dump.cpp
===
--- clang/test/Analysis/cast-value-state-dump.cpp
+++ clang/test/Analysis/cast-value-state-dump.cpp
@@ -35,8 +35,8 @@
   // CHECK-NEXT: ],
   // CHECK-NEXT: "dynamic_casts": [
   // CHECK:{ "region": "SymRegion{reg_$0}", "casts": [
-  // CHECK-NEXT: { "from": "const struct clang::Shape *", "to": "const 
class clang::Circle *", "kind": "success" },
-  // CHECK-NEXT: { "from": "const struct clang::Shape *", "to": "const 
class clang::Square *", "kind": "fail" }
+  // CHECK-NEXT: { "from": "struct clang::Shape", "to": "class 
clang::Circle", "kind": "success" },
+  // CHECK-NEXT: { "from": "struct clang::Shape", "to": "class 
clang::Square", "kind": "fail" }
   // CHECK-NEXT:   ] }
 
   (void)(1 / !C);
Index: clang/lib/StaticAnalyzer/Core/DynamicType.cpp
===
--- clang/lib/StaticAnalyzer/Core/DynamicType.cpp
+++ clang/lib/StaticAnalyzer/Core/DynamicType.cpp
@@ -65,6 +65,19 @@
   return State->get(MR);
 }
 
+static void unbox(QualType ) {
+  if (Ty->isReferenceType())
+Ty = Ty.getNonReferenceType();
+  if (const auto *STTPTy = 
dyn_cast(Ty.getTypePtr()))
+Ty = STTPTy->getReplacementType();
+  if (Ty->isPointerType())
+Ty = Ty->getPointeeType();
+  if (const auto *STTPTy =
+  dyn_cast(Ty.getTypePtr()))
+Ty = STTPTy->getReplacementType();
+  Ty = Ty.getUnqualifiedType();
+}
+
 const DynamicCastInfo *getDynamicCastInfo(ProgramStateRef State,
   const MemRegion *MR,
   QualType CastFromTy,
@@ -73,6 +86,9 @@
   if (!Lookup)
 return nullptr;
 
+  unbox(CastFromTy);
+  unbox(CastToTy);
+
   for (const DynamicCastInfo  : *Lookup)
 if (Cast.equals(CastFromTy, CastToTy))
   return 
@@ -112,6 +128,9 @@
 State = State->set(MR, CastToTy);
   }
 
+  unbox(CastFromTy);
+  unbox(CastToTy);
+
   DynamicCastInfo::CastResult ResultKind =
   CastSucceeds ? DynamicCastInfo::CastResult::Success
: DynamicCastInfo::CastResult::Failure;
Index: clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
@@ -106,7 +106,7 @@
  QualType CastToTy, const Expr *Object,
  bool CastSucceeds, bool IsKnownCast) {
   std::string CastToName =
-  CastInfo ? CastInfo->to()->getPointeeCXXRecordDecl()->getNameAsString()
+  CastInfo ? CastInfo->to()->getAsCXXRecordDecl()->getNameAsString()
: CastToTy->getPointeeCXXRecordDecl()->getNameAsString();
   Object = Object->IgnoreParenImpCasts();
 


Index: clang/test/Analysis/cast-value-state-dump.cpp
===
--- clang/test/Analysis/cast-value-state-dump.cpp
+++ clang/test/Analysis/cast-value-state-dump.cpp
@@ -35,8 +35,8 @@
   // CHECK-NEXT: ],
   // CHECK-NEXT: "dynamic_casts": [
   // CHECK:{ "region": "SymRegion{reg_$0}", "casts": [
-  // CHECK-NEXT: { "from": "const struct clang::Shape *", "to": "const class clang::Circle *", "kind": "success" },
-  // CHECK-NEXT: { "from": "const struct clang::Shape *", "to": "const class clang::Square *", "kind": "fail" }
+  // CHECK-NEXT: { "from": "struct clang::Shape", "to": "class clang::Circle", "kind": "success" },
+  // CHECK-NEXT: { "from": "struct clang::Shape", "to": "class clang::Square", "kind": "fail" }
   // CHECK-NEXT:   ] }
 
   (void)(1 / !C);
Index: clang/lib/StaticAnalyzer/Core/DynamicType.cpp
===
--- clang/lib/StaticAnalyzer/Core/DynamicType.cpp
+++ 

[PATCH] D85728: [Analyzer][WIP] Support for the new variadic isa<> and isa_and_nod_null<> in CastValueChecker

2020-08-11 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

My proposal is the following: do not store the casing info between pointers and 
references but the underlying types themselves. There are two ways to implement 
this: in the checkers using it (currently only this one) or behind the API of 
`DynamicCastInfo`. Maybe the latter is more appropriate.

To be fully correct we should not only change the `DynamicCastInfo` but also 
the `DynamicTypeInfo`: if the dynamic type of an object behind a pointer is 
known, then it remains the same also if we get a reference from the pointer or 
substitute a type for a template type parameter with it. (We can create new 
pointer or reference type using `ASTContext`.)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D85728

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


[PATCH] D85728: [Analyzer][WIP] Support for the new variadic isa<> and isa_and_nod_null<> in CastValueChecker

2020-08-11 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

This patch intends to fix bug 47037 
. It is still work in progress 
with lots of debug printouts.

I described the issue with this patch at the bug report:

//The variadic tests fail because the whole Dyanamic Type library is extremely 
poor design: it stores the pointers and references as they are instead of the 
underlying types. Unfortunately, cast<> functions which can take pointers have 
pointers to SubstTemplateTypeParmType but isa<> functions take everything by 
reference. Thus they have a reference to a SubstTemplateTypeParmType which 
contains the pointer. The two will never match even if I unpack the reference 
for the isa<> functions and get to the pointer itself because I cannot create a 
new pointer type in the cast<> functions where SubstTemplateTypeParmType is 
inside the pointer. I did not found any method to remove 
SubstTemplateTypeParmType from a pointer either.

This results that the test evalNonNullParamNonNullReturnReference() passes only 
by chance in the original version. Even if I fix the parameter which should 
have been pointer instead of reference the early exit blocks which use 
dyn_cast<> store a different "from" type for the casts that we retrieve later 
at the isa<> calls. This way both true and false branches for the isa<> blocks 
remain alive. If I extend the tests for variadic templates we are not lucky 
anymore, the tests fail.//


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D85728

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


[PATCH] D85728: [Analyzer][WIP] Support for the new variadic isa<> and isa_and_nod_null<> in CastValueChecker

2020-08-11 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware created this revision.
baloghadamsoftware added reviewers: NoQ, Charusso.
baloghadamsoftware added a project: clang.
Herald added subscribers: ASDenysPetrov, martong, steakhal, gamesh411, dkrupp, 
donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, xazax.hun, 
whisperity.
Herald added a reviewer: Szelethus.
baloghadamsoftware requested review of this revision.

llvm::isa<>() and llvm::isa_and_not_null<>() template functions recently became 
variadic. Unfortunately this causes crashes in case of isa_and_not_null<>() and 
incorrect behavior in isa<>(). This patch fixes this issue.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D85728

Files:
  clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
  clang/test/Analysis/Inputs/llvm.h
  clang/test/Analysis/cast-value-logic.cpp
  clang/test/Analysis/cast-value-notes.cpp

Index: clang/test/Analysis/cast-value-notes.cpp
===
--- clang/test/Analysis/cast-value-notes.cpp
+++ clang/test/Analysis/cast-value-notes.cpp
@@ -13,20 +13,22 @@
   const T *getAs() const;
 };
 class Triangle : public Shape {};
+class Rectangle : public Shape {};
+class Hexagon : public Shape {};
 class Circle : public Shape {};
 } // namespace clang
 
 using namespace llvm;
 using namespace clang;
 
-void evalReferences(const Shape ) {
+/*void evalReferences(const Shape ) {
   const auto  = dyn_cast(S);
   // expected-note@-1 {{Assuming 'S' is not a 'Circle'}}
   // expected-note@-2 {{Dereference of null pointer}}
   // expected-warning@-3 {{Dereference of null pointer}}
-}
+  }*/
 
-void evalNonNullParamNonNullReturnReference(const Shape ) {
+void evalNonNullParamNonNullReturnReference(const Shape *S) {
   // Unmodeled cast from reference to pointer.
   const auto *C = dyn_cast_or_null(S);
   // expected-note@-1 {{'C' initialized here}}
@@ -43,12 +45,36 @@
 return;
   }
 
+  if (dyn_cast_or_null(C)) {
+// expected-note@-1 {{Assuming 'C' is not a 'Rectangle'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (dyn_cast_or_null(C)) {
+// expected-note@-1 {{Assuming 'C' is not a 'Hexagon'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
   if (isa(C)) {
 // expected-note@-1 {{'C' is not a 'Triangle'}}
 // expected-note@-2 {{Taking false branch}}
 return;
   }
 
+  if (isa(C)) {
+// expected-note@-1 {{'C' is not a 'Triangle'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
+  if (isa(C)) {
+// expected-note@-1 {{'C' is not a 'Triangle'}}
+// expected-note@-2 {{Taking false branch}}
+return;
+  }
+
   if (isa(C)) {
 // expected-note@-1 {{'C' is a 'Circle'}}
 // expected-note@-2 {{Taking true branch}}
@@ -58,9 +84,29 @@
 // expected-note@-2 {{Division by zero}}
 // expected-warning@-3 {{Division by zero}}
   }
+
+  if (isa(C)) {
+// expected-note@-1 {{'C' is a 'Circle'}}
+// expected-note@-2 {{Taking true branch}}
+
+(void)(1 / !C);
+// expected-note@-1 {{'C' is non-null}}
+// expected-note@-2 {{Division by zero}}
+// expected-warning@-3 {{Division by zero}}
+  }
+
+  if (isa(C)) {
+// expected-note@-1 {{'C' is a 'Circle'}}
+// expected-note@-2 {{Taking true branch}}
+
+(void)(1 / !C);
+// expected-note@-1 {{'C' is non-null}}
+// expected-note@-2 {{Division by zero}}
+// expected-warning@-3 {{Division by zero}}
+  }
 }
 
-void evalNonNullParamNonNullReturn(const Shape *S) {
+/*void evalNonNullParamNonNullReturn(const Shape *S) {
   const auto *C = cast(S);
   // expected-note@-1 {{'S' is a 'Circle'}}
   // expected-note@-2 {{'C' initialized here}}
@@ -153,3 +199,4 @@
   // expected-note@-1 {{Division by zero}}
   // expected-warning@-2 {{Division by zero}}
 }
+*/
Index: clang/test/Analysis/cast-value-logic.cpp
===
--- clang/test/Analysis/cast-value-logic.cpp
+++ clang/test/Analysis/cast-value-logic.cpp
@@ -19,6 +19,8 @@
   virtual double area();
 };
 class Triangle : public Shape {};
+class Rectangle : public Shape {};
+class Hexagon : public Shape {};
 class Circle : public Shape {
 public:
   ~Circle();
@@ -39,6 +41,23 @@
 clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
 }
 
+void test_regions_isa_variadic(const Shape *A, const Shape *B) {
+  if (isa(A) &&
+  !isa(B))
+clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
+void test_regions_isa_and_nonnull(const Shape *A, const Shape *B) {
+  if (isa_and_nonnull(A) && !isa_and_nonnull(B))
+clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
+void test_regions_isa_and_nonnull_variadic(const Shape *A, const Shape *B) {
+  if (isa_and_nonnull(A) &&
+  !isa_and_nonnull(B))
+clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
 namespace test_cast {
 void evalLogic(const Shape *S) {
   const Circle *C = 

[PATCH] D81272: [clang-tidy] New check `misc-redundant-condition`

2020-08-11 Thread Balogh , Ádám via Phabricator via cfe-commits
baloghadamsoftware added a comment.

6 findings in the //LLVM Project//. All of them confirmed as trues positives, 5 
of them already fixed. Fix pending for the last one.

D82555 , D8556 
, D82557 , 
D82558 , D82559 
, D82563 

@aaron.ballman, @gribozavr2 or someone please review this patch.


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

https://reviews.llvm.org/D81272

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


  1   2   3   4   5   6   7   8   9   10   >