[PATCH] D38845: [ASTImporter] Support importing UnresolvedMemberExpr, DependentNameType, DependentScopeDeclRefExpr

2018-05-07 Thread Peter Szecsi via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC331630: [ASTImporter] Support importing 
UnresolvedMemberExpr, DependentNameType… (authored by szepet, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D38845?vs=145159=145447#toc

Repository:
  rC Clang

https://reviews.llvm.org/D38845

Files:
  lib/AST/ASTImporter.cpp
  unittests/AST/ASTImporterTest.cpp

Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -121,7 +121,7 @@
 QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T);
 QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T);
 QualType VisitElaboratedType(const ElaboratedType *T);
-// FIXME: DependentNameType
+QualType VisitDependentNameType(const DependentNameType *T);
 QualType VisitPackExpansionType(const PackExpansionType *T);
 QualType VisitDependentTemplateSpecializationType(
 const DependentTemplateSpecializationType *T);
@@ -347,8 +347,10 @@
 Expr *VisitCXXConstructExpr(CXXConstructExpr *E);
 Expr *VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
 Expr *VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
+Expr *VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E);
 Expr *VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *CE);
 Expr *VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E);
+Expr *VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E);
 Expr *VisitExprWithCleanups(ExprWithCleanups *EWC);
 Expr *VisitCXXThisExpr(CXXThisExpr *E);
 Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
@@ -938,6 +940,25 @@
 T->getKeyword(), Qualifier, Name, ToPack);
 }
 
+QualType ASTNodeImporter::VisitDependentNameType(const DependentNameType *T) {
+  NestedNameSpecifier *NNS = Importer.Import(T->getQualifier());
+  if (!NNS && T->getQualifier())
+return QualType();
+
+  IdentifierInfo *Name = Importer.Import(T->getIdentifier());
+  if (!Name && T->getIdentifier())
+return QualType();
+
+  QualType Canon = (T == T->getCanonicalTypeInternal().getTypePtr())
+   ? QualType()
+   : Importer.Import(T->getCanonicalTypeInternal());
+  if (!Canon.isNull())
+Canon = Canon.getCanonicalType();
+
+  return Importer.getToContext().getDependentNameType(T->getKeyword(), NNS,
+  Name, Canon);
+}
+
 QualType ASTNodeImporter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
   auto *Class =
   dyn_cast_or_null(Importer.Import(T->getDecl()));
@@ -6187,6 +6208,29 @@
   cast_or_null(ToFQ), MemberNameInfo, ResInfo);
 }
 
+Expr *
+ASTNodeImporter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
+  DeclarationName Name = Importer.Import(E->getDeclName());
+  if (!E->getDeclName().isEmpty() && Name.isEmpty())
+return nullptr;
+
+  DeclarationNameInfo NameInfo(Name, Importer.Import(E->getExprLoc()));
+  ImportDeclarationNameLoc(E->getNameInfo(), NameInfo);
+
+  TemplateArgumentListInfo ToTAInfo(Importer.Import(E->getLAngleLoc()),
+Importer.Import(E->getRAngleLoc()));
+  TemplateArgumentListInfo *ResInfo = nullptr;
+  if (E->hasExplicitTemplateArgs()) {
+if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo))
+  return nullptr;
+ResInfo = 
+  }
+
+  return DependentScopeDeclRefExpr::Create(
+  Importer.getToContext(), Importer.Import(E->getQualifierLoc()),
+  Importer.Import(E->getTemplateKeywordLoc()), NameInfo, ResInfo);
+}
+
 Expr *ASTNodeImporter::VisitCXXUnresolvedConstructExpr(
 CXXUnresolvedConstructExpr *CE) {
   unsigned NumArgs = CE->arg_size();
@@ -6244,6 +6288,47 @@
   E->isOverloaded(), ToDecls.begin(), ToDecls.end());
 }
 
+Expr *ASTNodeImporter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
+  DeclarationName Name = Importer.Import(E->getName());
+  if (!E->getName().isEmpty() && Name.isEmpty())
+return nullptr;
+  DeclarationNameInfo NameInfo(Name, Importer.Import(E->getNameLoc()));
+  // Import additional name location/type info.
+  ImportDeclarationNameLoc(E->getNameInfo(), NameInfo);
+
+  QualType BaseType = Importer.Import(E->getType());
+  if (!E->getType().isNull() && BaseType.isNull())
+return nullptr;
+
+  UnresolvedSet<8> ToDecls;
+  for (Decl *D : E->decls()) {
+if (NamedDecl *To = cast_or_null(Importer.Import(D)))
+  ToDecls.addDecl(To);
+else
+  return nullptr;
+  }
+
+  TemplateArgumentListInfo ToTAInfo;
+  TemplateArgumentListInfo *ResInfo = nullptr;
+  if (E->hasExplicitTemplateArgs()) {
+if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo))
+  return nullptr;
+ResInfo = 
+  }
+
+  Expr *BaseE = E->isImplicitAccess() ? nullptr : Importer.Import(E->getBase());
+  if (!BaseE && !E->isImplicitAccess() && 

[PATCH] D40937: [clang-tidy] Infinite loop checker

2018-05-04 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 145160.
szepet marked 2 inline comments as done.
szepet added a comment.

Changes based on comments.


https://reviews.llvm.org/D40937

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/InfiniteLoopCheck.cpp
  clang-tidy/bugprone/InfiniteLoopCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-infinite-loop.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-infinite-loop.cpp

Index: test/clang-tidy/bugprone-infinite-loop.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-infinite-loop.cpp
@@ -0,0 +1,121 @@
+// RUN: %check_clang_tidy %s bugprone-infinite-loop %t
+
+void simple_infinite_loop1() {
+  int i = 0;
+  int j = 0;
+  while (i < 10) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the condition variable (i) is not updated in the loop body [bugprone-infinite-loop]
+j++;
+  }
+
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the condition variable (i) is not updated in the loop body
+j++;
+  } while (i < 10);
+
+  for (i = 0; i < 10; ++j) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the condition variable (i) is not updated in the loop body
+  }
+}
+
+void simple_infinite_loop2() {
+  int i = 0;
+  int j = 0;
+  int Limit = 10;
+  while (i < Limit) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: none of the condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
+j++;
+  }
+
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: none of the condition variables (i, Limit) are updated in the loop body
+j++;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; ++j) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: none of the condition variables (i, Limit) are updated in the loop body
+  }
+}
+
+void simple_not_infinite() {
+  int i = 0;
+  int Limit = 100;
+  while (i < Limit) { // Not an error since 'Limit' is updated
+Limit--;
+  }
+  do {
+Limit--;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; Limit--) {
+  }
+}
+
+void escape_before1() {
+  int i = 0;
+  int Limit = 100;
+  int *p = 
+  while (i < Limit) { // Not an error, since p is alias of i.
+*++p;
+  }
+
+  do {
+*++p;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; *++p) {
+;
+  }
+}
+
+void escape_before2() {
+  int i = 0;
+  int Limit = 100;
+  int *p = 
+  while (i < Limit) { // We do not warn since the var 'i' is escaped but it is
+  // an actual error, since the pointer 'p' is increased.
+*(p++);
+  }
+}
+
+void escape_after() {
+  int i = 0;
+  int j = 0;
+  int Limit = 10;
+
+  while (i < Limit) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: none of the condition variables (i, Limit) are updated in the loop body
+  }
+  int *p = 
+}
+
+int glob;
+void glob_var(int ) {
+  int i = 0, Limit = 100;
+  while (x < Limit) { // Not an error since 'x' can be an alias of glob.
+glob++;
+  }
+}
+
+void glob_var2() {
+  int i = 0, Limit = 100;
+  while (glob < Limit) { // Since 'glob' is declared out of the function we do not warn.
+i++;
+  }
+}
+
+struct X {
+  void memberExpr_test(int i) {
+while (i < m) { // False negative: No warning, since skipping the case where
+// a memberExpr can be found in the condition.
+  ;
+}
+  }
+
+  void memberExpr_test2(int i) {
+while (i < m) {
+  --m;
+}
+  }
+  int m;
+};
Index: docs/clang-tidy/checks/list.rst
===
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -29,6 +29,7 @@
bugprone-forwarding-reference-overload
bugprone-inaccurate-erase
bugprone-incorrect-roundings
+   bugprone-infinite-loop
bugprone-integer-division
bugprone-lambda-function-name
bugprone-macro-parentheses
Index: docs/clang-tidy/checks/bugprone-infinite-loop.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/bugprone-infinite-loop.rst
@@ -0,0 +1,30 @@
+.. title:: clang-tidy - bugprone-infinite-loop
+
+bugprone-infinite-loop
+==
+
+Finds loops where none of the condition variables are updated in the body. This
+performs a very conservative check in order to avoid false positives and work
+only on integer types at the moment.
+
+Examples:
+
+.. code-block:: c++
+
+  void simple_infinite_loop() {
+int i = 0;
+int j = 0;
+int Limit = 10;
+while (i < Limit) { // Error, since none of the variables are updated.
+  j++;
+}
+  }
+
+  void escape_before() {
+int i = 0;
+int Limit = 100;
+int *p = 
+while (i < Limit) { // Not an error, since p is alias of i.
+  *++p;
+}
+  }
Index: docs/ReleaseNotes.rst
===
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -70,6 +70,12 @@
   Diagnoses 

[PATCH] D38845: [ASTImporter] Support importing UnresolvedMemberExpr, DependentNameType, DependentScopeDeclRefExpr

2018-05-04 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 145159.
szepet added a comment.

Format changes added based on comments.


https://reviews.llvm.org/D38845

Files:
  lib/AST/ASTImporter.cpp
  unittests/AST/ASTImporterTest.cpp

Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -1503,5 +1503,60 @@
 ParameterizedTests, ImportFunctions,
 ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
 
+const internal::VariadicDynCastAllOfMatcher
+dependentScopeDeclRefExpr;
+
+TEST(ImportExpr, DependentScopeDeclRefExpr) {
+  MatchVerifier Verifier;
+  testImport("template  struct S { static T foo; };"
+ "template  void declToImport() {"
+ "  (void) S::foo;"
+ "}"
+ "void instantiate() { declToImport(); }",
+ Lang_CXX11, "", Lang_CXX11, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(
+ has(cStyleCastExpr(has(dependentScopeDeclRefExpr());
+
+  testImport("template  struct S {"
+ "template static void foo(){};"
+ "};"
+ "template  void declToImport() {"
+ "  S::template foo();"
+ "}"
+ "void instantiate() { declToImport(); }",
+ Lang_CXX11, "", Lang_CXX11, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(
+ has(callExpr(has(dependentScopeDeclRefExpr());
+}
+
+const internal::VariadicDynCastAllOfMatcher
+dependentNameType;
+
+TEST(ImportExpr, DependentNameType) {
+  MatchVerifier Verifier;
+  testImport("template  struct declToImport {"
+ "  typedef typename T::type dependent_name;"
+ "};",
+ Lang_CXX11, "", Lang_CXX11, Verifier,
+ classTemplateDecl(has(
+ cxxRecordDecl(has(typedefDecl(has(dependentNameType(;
+}
+
+const internal::VariadicDynCastAllOfMatcher
+unresolvedMemberExpr;
+
+TEST(ImportExpr, UnresolvedMemberExpr) {
+  MatchVerifier Verifier;
+  testImport("struct S { template  void mem(); };"
+ "template  void declToImport() {"
+ "  S s;"
+ "  s.mem();"
+ "}"
+ "void instantiate() { declToImport(); }",
+ Lang_CXX11, "", Lang_CXX11, Verifier,
+ functionTemplateDecl(has(functionDecl(has(
+ compoundStmt(has(callExpr(has(unresolvedMemberExpr());
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -121,7 +121,7 @@
 QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T);
 QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T);
 QualType VisitElaboratedType(const ElaboratedType *T);
-// FIXME: DependentNameType
+QualType VisitDependentNameType(const DependentNameType *T);
 QualType VisitPackExpansionType(const PackExpansionType *T);
 QualType VisitDependentTemplateSpecializationType(
 const DependentTemplateSpecializationType *T);
@@ -347,8 +347,10 @@
 Expr *VisitCXXConstructExpr(CXXConstructExpr *E);
 Expr *VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
 Expr *VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
+Expr *VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E);
 Expr *VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *CE);
 Expr *VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E);
+Expr *VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E);
 Expr *VisitExprWithCleanups(ExprWithCleanups *EWC);
 Expr *VisitCXXThisExpr(CXXThisExpr *E);
 Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
@@ -938,6 +940,25 @@
 T->getKeyword(), Qualifier, Name, ToPack);
 }
 
+QualType ASTNodeImporter::VisitDependentNameType(const DependentNameType *T) {
+  NestedNameSpecifier *NNS = Importer.Import(T->getQualifier());
+  if (!NNS && T->getQualifier())
+return QualType();
+
+  IdentifierInfo *Name = Importer.Import(T->getIdentifier());
+  if (!Name && T->getIdentifier())
+return QualType();
+
+  QualType Canon = (T == T->getCanonicalTypeInternal().getTypePtr())
+   ? QualType()
+   : Importer.Import(T->getCanonicalTypeInternal());
+  if (!Canon.isNull())
+Canon = Canon.getCanonicalType();
+
+  return Importer.getToContext().getDependentNameType(T->getKeyword(), NNS,
+  Name, Canon);
+}
+
 QualType ASTNodeImporter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
   auto *Class =
   

[PATCH] D46019: [ASTImporter] Fix isa cast assert

2018-05-02 Thread Peter Szecsi via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL331344: [ASTImporter] Fix isa cast assert (authored by 
szepet, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D46019

Files:
  cfe/trunk/lib/AST/ASTImporter.cpp


Index: cfe/trunk/lib/AST/ASTImporter.cpp
===
--- cfe/trunk/lib/AST/ASTImporter.cpp
+++ cfe/trunk/lib/AST/ASTImporter.cpp
@@ -6089,9 +6089,13 @@
   if (!ToMember && E->getMemberDecl())
 return nullptr;
 
-  DeclAccessPair ToFoundDecl = DeclAccessPair::make(
-dyn_cast(Importer.Import(E->getFoundDecl().getDecl())),
-E->getFoundDecl().getAccess());
+  auto *ToDecl =
+  
dyn_cast_or_null(Importer.Import(E->getFoundDecl().getDecl()));
+  if (!ToDecl && E->getFoundDecl().getDecl())
+return nullptr;
+
+  DeclAccessPair ToFoundDecl =
+  DeclAccessPair::make(ToDecl, E->getFoundDecl().getAccess());
 
   DeclarationNameInfo ToMemberNameInfo(
 Importer.Import(E->getMemberNameInfo().getName()),


Index: cfe/trunk/lib/AST/ASTImporter.cpp
===
--- cfe/trunk/lib/AST/ASTImporter.cpp
+++ cfe/trunk/lib/AST/ASTImporter.cpp
@@ -6089,9 +6089,13 @@
   if (!ToMember && E->getMemberDecl())
 return nullptr;
 
-  DeclAccessPair ToFoundDecl = DeclAccessPair::make(
-dyn_cast(Importer.Import(E->getFoundDecl().getDecl())),
-E->getFoundDecl().getAccess());
+  auto *ToDecl =
+  dyn_cast_or_null(Importer.Import(E->getFoundDecl().getDecl()));
+  if (!ToDecl && E->getFoundDecl().getDecl())
+return nullptr;
+
+  DeclAccessPair ToFoundDecl =
+  DeclAccessPair::make(ToDecl, E->getFoundDecl().getAccess());
 
   DeclarationNameInfo ToMemberNameInfo(
 Importer.Import(E->getMemberNameInfo().getName()),
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38845: [ASTImporter] Support importing UnresolvedMemberExpr, DependentNameType, DependentScopeDeclRefExpr

2018-05-02 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 144842.
szepet marked an inline comment as done.
szepet added a comment.

Yepp, good point, Aleksei, rewritten the tests using explicit instantiation.


https://reviews.llvm.org/D38845

Files:
  lib/AST/ASTImporter.cpp
  unittests/AST/ASTImporterTest.cpp

Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -1502,6 +1502,58 @@
 INSTANTIATE_TEST_CASE_P(
 ParameterizedTests, ImportFunctions,
 ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
+const internal::VariadicDynCastAllOfMatcher
+dependentScopeDeclRefExpr;
+TEST(ImportExpr, DependentScopeDeclRefExpr) {
+  MatchVerifier Verifier;
+  testImport("template  struct S {static T foo;};"
+ "template  void declToImport() {"
+ "  (void) S::foo;"
+ "}"
+ "void instantiate() { declToImport(); }",
+ Lang_CXX11, "", Lang_CXX11, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(
+ has(cStyleCastExpr(has(dependentScopeDeclRefExpr());
+
+  testImport("template  struct S {"
+ "template static void foo(){};"
+ "};"
+ "template  void declToImport() {"
+ "  S::template foo();"
+ "}"
+ "void instantiate() { declToImport(); }",
+ Lang_CXX11, "", Lang_CXX11, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(
+ has(callExpr(has(dependentScopeDeclRefExpr());
+}
+
+const internal::VariadicDynCastAllOfMatcher
+dependentNameType;
+TEST(ImportExpr, DependentNameType) {
+  MatchVerifier Verifier;
+  testImport("template  struct declToImport {"
+ "  typedef typename T::type dependent_name;"
+ "};",
+ Lang_CXX11, "", Lang_CXX11, Verifier,
+ classTemplateDecl(has(
+ cxxRecordDecl(has(typedefDecl(has(dependentNameType(;
+}
+
+const internal::VariadicDynCastAllOfMatcher
+unresolvedMemberExpr;
+
+TEST(ImportExpr, UnresolvedMemberExpr) {
+  MatchVerifier Verifier;
+  testImport("struct S { template  void mem(); };"
+ "template  void declToImport() {"
+ "  S s;"
+ "  s.mem();"
+ "}"
+ "void instantiate() { declToImport(); }",
+ Lang_CXX11, "", Lang_CXX11, Verifier,
+ functionTemplateDecl(has(functionDecl(has(
+ compoundStmt(has(callExpr(has(unresolvedMemberExpr());
+}
 
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -121,7 +121,7 @@
 QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T);
 QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T);
 QualType VisitElaboratedType(const ElaboratedType *T);
-// FIXME: DependentNameType
+QualType VisitDependentNameType(const DependentNameType *T);
 QualType VisitPackExpansionType(const PackExpansionType *T);
 QualType VisitDependentTemplateSpecializationType(
 const DependentTemplateSpecializationType *T);
@@ -347,8 +347,10 @@
 Expr *VisitCXXConstructExpr(CXXConstructExpr *E);
 Expr *VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
 Expr *VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
+Expr *VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E);
 Expr *VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *CE);
 Expr *VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E);
+Expr *VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E);
 Expr *VisitExprWithCleanups(ExprWithCleanups *EWC);
 Expr *VisitCXXThisExpr(CXXThisExpr *E);
 Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
@@ -938,6 +940,25 @@
 T->getKeyword(), Qualifier, Name, ToPack);
 }
 
+QualType ASTNodeImporter::VisitDependentNameType(const DependentNameType *T) {
+  NestedNameSpecifier *NNS = Importer.Import(T->getQualifier());
+  if (!NNS && T->getQualifier())
+return QualType();
+
+  IdentifierInfo *Name = Importer.Import(T->getIdentifier());
+  if (!Name && T->getIdentifier())
+return QualType();
+
+  QualType Canon = (T == T->getCanonicalTypeInternal().getTypePtr())
+   ? QualType()
+   : Importer.Import(T->getCanonicalTypeInternal());
+  if (!Canon.isNull())
+Canon = Canon.getCanonicalType();
+
+  return Importer.getToContext().getDependentNameType(T->getKeyword(), NNS,
+  Name, 

[PATCH] D38845: [ASTImporter] Support importing UnresolvedMemberExpr, DependentNameType, DependentScopeDeclRefExpr

2018-04-26 Thread Peter Szecsi via Phabricator via cfe-commits
szepet marked an inline comment as done.
szepet added inline comments.



Comment at: unittests/AST/ASTImporterTest.cpp:1569
+FirstDeclMatcher().match(*TB, Pattern);
+if (!FromDSDRE)
+  return;

martong wrote:
> I think, this `if` would be needed only if the test suite would be 
> parameterized also with `ArgVector{"-fdelayed-template-parsing"}`, but that 
> is not.
Its necessary, since on windows platforms we have that flag by default (so, it 
does not matter that we dont include here, it will be used anyway).



Comment at: unittests/AST/ASTImporterTest.cpp:1573
+auto To = cast(Import(FromDSDRE, Lang_CXX));
+EXPECT_TRUE(FirstDeclMatcher().match(To, Pattern));
+  }

martong wrote:
> It will be hard to notice based on the test output which DSDRE's import was 
> unsuccessful. Therefore I'd unroll the for loop instead, also please see the 
> above comment that it would be more practical to have one FromTU.
I understand the concern, but I am really against the mentioned design. The 
main point of this code is that whenever we would like to add one more test 
cases, then we need to add it to the vector and everything else is done. Other 
than that, I would say that debugging a broken test case is already a "time 
expensive" job, so in that case it wouldnt make much of a different, since you 
need to look at the code closely anyway.


https://reviews.llvm.org/D38845



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


[PATCH] D46019: [ASTImporter] Fix isa cast assert

2018-04-25 Thread Peter Szecsi via Phabricator via cfe-commits
szepet accepted this revision.
szepet added a comment.

Yepp, pretty straightforward check for something we were not aware previously 
(but unfortunately encountered it).


Repository:
  rC Clang

https://reviews.llvm.org/D46019



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


[PATCH] D40937: [clang-tidy] Infinite loop checker

2018-04-25 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 143949.
szepet marked 2 inline comments as done.
szepet added a comment.

Changes made based on comments.
The CFG recreating problem is handled the following (only for this check):
Always store the last visited function and its CFG* (in form of the Sequence*) 
and check if we are visiting it again. If so, then the check reuses the 
previous one, if not, then replaces them. As far as I know the AST traverse 
done by the tidy fits this model (at least for this check, since it not uses 
narrowing matchers to other functions).
Sure, it would be better to find a general solution to this problem, and make 
the CFG reusable by every check which needs it, but I would left it for a 
follow-up (and a change like this probably would worth an own patch/review 
anyway).


https://reviews.llvm.org/D40937

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/InfiniteLoopCheck.cpp
  clang-tidy/bugprone/InfiniteLoopCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-infinite-loop.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-infinite-loop.cpp

Index: test/clang-tidy/bugprone-infinite-loop.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-infinite-loop.cpp
@@ -0,0 +1,121 @@
+// RUN: %check_clang_tidy %s bugprone-infinite-loop %t
+
+void simple_infinite_loop1() {
+  int i = 0;
+  int j = 0;
+  while (i < 10) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the condition variable (i) is not updated in the loop body [bugprone-infinite-loop]
+j++;
+  }
+
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the condition variable (i) is not updated in the loop body
+j++;
+  } while (i < 10);
+
+  for (i = 0; i < 10; ++j) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the condition variable (i) is not updated in the loop body
+  }
+}
+
+void simple_infinite_loop2() {
+  int i = 0;
+  int j = 0;
+  int Limit = 10;
+  while (i < Limit) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: none of the condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
+j++;
+  }
+
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: none of the condition variables (i, Limit) are updated in the loop body
+j++;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; ++j) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: none of the condition variables (i, Limit) are updated in the loop body
+  }
+}
+
+void simple_not_infinite() {
+  int i = 0;
+  int Limit = 100;
+  while (i < Limit) { // Not an error since 'Limit' is updated
+Limit--;
+  }
+  do {
+Limit--;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; Limit--) {
+  }
+}
+
+void escape_before1() {
+  int i = 0;
+  int Limit = 100;
+  int *p = 
+  while (i < Limit) { // Not an error, since p is alias of i.
+*++p;
+  }
+
+  do {
+*++p;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; *++p) {
+;
+  }
+}
+
+void escape_before2() {
+  int i = 0;
+  int Limit = 100;
+  int *p = 
+  while (i < Limit) { // We do not warn since the var 'i' is escaped but it is
+  // an actual error, since the pointer 'p' is increased.
+*(p++);
+  }
+}
+
+void escape_after() {
+  int i = 0;
+  int j = 0;
+  int Limit = 10;
+
+  while (i < Limit) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: none of the condition variables (i, Limit) are updated in the loop body
+  }
+  int *p = 
+}
+
+int glob;
+void glob_var(int ) {
+  int i = 0, Limit = 100;
+  while (x < Limit) { // Not an error since 'x' can be an alias of glob.
+glob++;
+  }
+}
+
+void glob_var2() {
+  int i = 0, Limit = 100;
+  while (glob < Limit) { // Since 'glob' is declared out of the function we do not warn.
+i++;
+  }
+}
+
+struct X {
+  void memberExpr_test(int i) {
+while (i < m) { // False negative: No warning, since skipping the case where
+// a memberExpr can be found in the condition.
+  ;
+}
+  }
+
+  void memberExpr_test2(int i) {
+while (i < m) {
+  --m;
+}
+  }
+  int m;
+};
Index: docs/clang-tidy/checks/list.rst
===
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -28,6 +28,7 @@
bugprone-forwarding-reference-overload
bugprone-inaccurate-erase
bugprone-incorrect-roundings
+   bugprone-infinite-loop
bugprone-integer-division
bugprone-lambda-function-name
bugprone-macro-parentheses
Index: docs/clang-tidy/checks/bugprone-infinite-loop.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/bugprone-infinite-loop.rst
@@ -0,0 +1,30 @@
+.. title:: clang-tidy - bugprone-infinite-loop
+
+bugprone-infinite-loop
+==
+
+Finds loops where none of the condition variables are updated in the body. This
+performs a very 

[PATCH] D38845: [ASTImporter] Support importing UnresolvedMemberExpr, DependentNameType, DependentScopeDeclRefExpr

2018-04-25 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 143925.
szepet added a comment.

Rewritten the tests using the newly added TEST_P method.
This patch failed earlier when -fdelayed-template-parsing flag was enabled, 
however, the actual import process was OK but the original AST havent included 
the checked nodes.
TEST_P made possible to check whether the original code contains the node we 
would like to import (and we test only in this case, since otherwise it does 
not make sense).


https://reviews.llvm.org/D38845

Files:
  lib/AST/ASTImporter.cpp
  unittests/AST/ASTImporterTest.cpp

Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -1503,5 +1503,91 @@
 ParameterizedTests, ImportFunctions,
 ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
 
+const internal::VariadicDynCastAllOfMatcher
+unresolvedMemberExpr;
+
+struct NoDelayedTemplateParsing : ASTImporterTestBase {};
+TEST_P(NoDelayedTemplateParsing, UnresolvedMemberExpr) {
+  auto Code = "struct S { template  void mem(); };"
+  "template  void declToImport() {"
+  "  S s;"
+  "  s.mem();"
+  "}";
+  Decl *FromTU = getTuDecl(Code, Lang_CXX);
+  auto Pattern = functionTemplateDecl(has(functionDecl(
+  has(compoundStmt(has(callExpr(has(unresolvedMemberExpr();
+  auto *FromUME =
+  FirstDeclMatcher().match(FromTU, Pattern);
+  if (!FromUME)
+return;
+
+  auto To = cast(Import(FromUME, Lang_CXX));
+  EXPECT_TRUE(FirstDeclMatcher().match(To, Pattern));
+}
+
+const internal::VariadicDynCastAllOfMatcher
+dependentScopeDeclRefExpr;
+TEST_P(NoDelayedTemplateParsing, ImportDependentScopeDeclRefExpr) {
+  llvm::SmallVector Codes;
+  Codes.push_back("template  struct S;"
+  "template  void declToImport() {"
+  "  S::foo;"
+  "}");
+
+  Codes.push_back("template  struct S;"
+  "template  void declToImport() {"
+  "  S::template foo;"
+  "}");
+
+  Codes.push_back("template  struct S;"
+  "template  void declToImport() {"
+  "  S::template foo<>;"
+  "}");
+
+  Codes.push_back("template  struct S;"
+  "template  void declToImport() {"
+  "  S::template foo;"
+  "}");
+
+  auto Pattern = functionTemplateDecl(
+  has(functionDecl(has(compoundStmt(has(dependentScopeDeclRefExpr()));
+  llvm::SmallVector FromTUs;
+  // Converting code texts into TUs
+  std::transform(Codes.begin(), Codes.end(), std::back_inserter(FromTUs),
+ [this](StringRef Code) {
+   static int cnt = 0;
+   ++cnt;
+   return getTuDecl(Code, Lang_CXX,
+std::to_string(cnt) + std::string(".cc"));
+ });
+
+  for (llvm::SmallVector::const_iterator TB = FromTUs.begin(),
+TE = FromTUs.end();
+   TB != TE; ++TB) {
+auto *FromDSDRE =
+FirstDeclMatcher().match(*TB, Pattern);
+if (!FromDSDRE)
+  return;
+
+auto To = cast(Import(FromDSDRE, Lang_CXX));
+EXPECT_TRUE(FirstDeclMatcher().match(To, Pattern));
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, NoDelayedTemplateParsing,
+::testing::Values(ArgVector()), );
+
+const internal::VariadicDynCastAllOfMatcher
+dependentNameType;
+TEST(ImportExpr, DependentNameType) {
+  MatchVerifier Verifier;
+  testImport("template  struct declToImport {"
+ "  typedef typename T::type dependent_name;"
+ "};",
+ Lang_CXX11, "", Lang_CXX11, Verifier,
+ classTemplateDecl(has(
+ cxxRecordDecl(has(typedefDecl(has(dependentNameType(;
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -121,7 +121,7 @@
 QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T);
 QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T);
 QualType VisitElaboratedType(const ElaboratedType *T);
-// FIXME: DependentNameType
+QualType VisitDependentNameType(const DependentNameType *T);
 QualType VisitPackExpansionType(const PackExpansionType *T);
 QualType VisitDependentTemplateSpecializationType(
 const DependentTemplateSpecializationType *T);
@@ -347,8 +347,10 @@
 Expr *VisitCXXConstructExpr(CXXConstructExpr *E);
 Expr *VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
 Expr 

[PATCH] D38845: [ASTImporter] Support importing UnresolvedMemberExpr, DependentNameType, DependentScopeDeclRefExpr

2018-04-11 Thread Peter Szecsi via Phabricator via cfe-commits
szepet marked an inline comment as done.
szepet added a comment.

Hello Aleksei,

Thanks for carrying the ASTImporter improvements (in general)! I will rebase it 
and upload for sure, but probably just next week. (After EuroLLVM.)


https://reviews.llvm.org/D38845



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


[PATCH] D40937: [clang-tidy] Infinite loop checker

2018-04-06 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 141322.
szepet marked 4 inline comments as done.
szepet added a comment.

Addressed comments and readded the lost fixes.


https://reviews.llvm.org/D40937

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/InfiniteLoopCheck.cpp
  clang-tidy/bugprone/InfiniteLoopCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-infinite-loop.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-infinite-loop.cpp

Index: test/clang-tidy/bugprone-infinite-loop.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-infinite-loop.cpp
@@ -0,0 +1,121 @@
+// RUN: %check_clang_tidy %s bugprone-infinite-loop %t
+
+void simple_infinite_loop1() {
+  int i = 0;
+  int j = 0;
+  while (i < 10) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body [bugprone-infinite-loop]
+j++;
+  }
+
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body
+j++;
+  } while (i < 10);
+
+  for (i = 0; i < 10; ++j) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body
+  }
+}
+
+void simple_infinite_loop2() {
+  int i = 0;
+  int j = 0;
+  int Limit = 10;
+  while (i < Limit) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
+j++;
+  }
+
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+j++;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; ++j) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+  }
+}
+
+void simple_not_infinite() {
+  int i = 0;
+  int Limit = 100;
+  while (i < Limit) { // Not an error since 'Limit' is updated
+Limit--;
+  }
+  do {
+Limit--;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; Limit--) {
+  }
+}
+
+void escape_before1() {
+  int i = 0;
+  int Limit = 100;
+  int *p = 
+  while (i < Limit) { // Not an error, since p is alias of i.
+*++p;
+  }
+
+  do {
+*++p;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; *++p) {
+;
+  }
+}
+
+void escape_before2() {
+  int i = 0;
+  int Limit = 100;
+  int *p = 
+  while (i < Limit) { // We do not warn since the var 'i' is escaped but it is
+  // an actual error, since the pointer 'p' is increased.
+*(p++);
+  }
+}
+
+void escape_after() {
+  int i = 0;
+  int j = 0;
+  int Limit = 10;
+
+  while (i < Limit) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+  }
+  int *p = 
+}
+
+int glob;
+void glob_var(int ) {
+  int i = 0, Limit = 100;
+  while (x < Limit) { // Not an error since 'x' can be an alias of glob.
+glob++;
+  }
+}
+
+void glob_var2() {
+  int i = 0, Limit = 100;
+  while (glob < Limit) { // Since 'glob' is declared out of the function we do not warn.
+i++;
+  }
+}
+
+struct X {
+  void memberExpr_test(int i) {
+while (i < m) { // False negative: No warning, since skipping the case where
+// a memberExpr can be found in the condition.
+  ;
+}
+  }
+
+  void memberExpr_test2(int i) {
+while (i < m) {
+  --m;
+}
+  }
+  int m;
+};
Index: docs/clang-tidy/checks/list.rst
===
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -28,6 +28,7 @@
bugprone-forwarding-reference-overload
bugprone-inaccurate-erase
bugprone-incorrect-roundings
+   bugprone-infinite-loop
bugprone-integer-division
bugprone-lambda-function-name
bugprone-macro-parentheses
Index: docs/clang-tidy/checks/bugprone-infinite-loop.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/bugprone-infinite-loop.rst
@@ -0,0 +1,30 @@
+.. title:: clang-tidy - bugprone-infinite-loop
+
+bugprone-infinite-loop
+==
+
+Finds loops where none of the condition variables are updated in the body. This
+performs a very conservative check in order to avoid false positives and work
+only on integer types at the moment.
+
+Examples:
+
+.. code-block:: c++
+
+  void simple_infinite_loop() {
+int i = 0;
+int j = 0;
+int Limit = 10;
+while (i < Limit) { // Error, since none of the variables are updated.
+  j++;
+}
+  }
+
+  void escape_before() {
+int i = 0;
+int Limit = 100;
+int *p = 
+while (i < Limit) { // Not an error, since p is alias of i.
+  *++p;
+}
+  }
Index: docs/ReleaseNotes.rst
===
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -64,6 

[PATCH] D40937: [clang-tidy] Infinite loop checker

2018-04-05 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added inline comments.



Comment at: clang-tidy/misc/InfiniteLoopCheck.cpp:121
+
+  Stmt *FunctionBody = nullptr;
+  if (ContainingLambda)

xazax.hun wrote:
> This could be pointer to const, right?
Since the createSequence uses it as a parameter for buildCFG which expects a 
Stmt*, I believe this is fine. (Or I could const cast is away on the call)


https://reviews.llvm.org/D40937



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


[PATCH] D40937: [clang-tidy] Infinite loop checker

2018-04-05 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 141132.
szepet marked 3 inline comments as done.
szepet added a comment.

Removed to bugprone category,
skipping memberExpr cases for now in order to avoid false positives,
other small changes based on review comments.


https://reviews.llvm.org/D40937

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/bugprone/InfiniteLoopCheck.cpp
  clang-tidy/bugprone/InfiniteLoopCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/bugprone-infinite-loop.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/bugprone-infinite-loop.cpp

Index: test/clang-tidy/bugprone-infinite-loop.cpp
===
--- /dev/null
+++ test/clang-tidy/bugprone-infinite-loop.cpp
@@ -0,0 +1,121 @@
+// RUN: %check_clang_tidy %s bugprone-infinite-loop %t
+
+void simple_infinite_loop1() {
+  int i = 0;
+  int j = 0;
+  while (i < 10) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body [bugprone-infinite-loop]
+j++;
+  }
+
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body
+j++;
+  } while (i < 10);
+
+  for (i = 0; i < 10; ++j) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body
+  }
+}
+
+void simple_infinite_loop2() {
+  int i = 0;
+  int j = 0;
+  int Limit = 10;
+  while (i < Limit) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
+j++;
+  }
+
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+j++;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; ++j) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+  }
+}
+
+void simple_not_infinite() {
+  int i = 0;
+  int Limit = 100;
+  while (i < Limit) { // Not an error since 'Limit' is updated
+Limit--;
+  }
+  do {
+Limit--;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; Limit--) {
+  }
+}
+
+void escape_before1() {
+  int i = 0;
+  int Limit = 100;
+  int *p = 
+  while (i < Limit) { // Not an error, since p is alias of i.
+*++p;
+  }
+
+  do {
+*++p;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; *++p) {
+;
+  }
+}
+
+void escape_before2() {
+  int i = 0;
+  int Limit = 100;
+  int *p = 
+  while (i < Limit) { // We do not warn since the var 'i' is escaped but it is
+  // an actual error, since the pointer 'p' is increased.
+*(p++);
+  }
+}
+
+void escape_after() {
+  int i = 0;
+  int j = 0;
+  int Limit = 10;
+
+  while (i < Limit) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+  }
+  int *p = 
+}
+
+int glob;
+void glob_var(int ) {
+  int i = 0, Limit = 100;
+  while (x < Limit) { // Not an error since 'x' can be an alias of glob.
+glob++;
+  }
+}
+
+void glob_var2() {
+  int i = 0, Limit = 100;
+  while (glob < Limit) { // Since 'glob' is declared out of the function we do not warn.
+i++;
+  }
+}
+
+struct X {
+  void memberExpr_test(int i) {
+while(i < m) { // False negative: No warning, since skipping the case where
+   // a memberExpr can be found in the condition.
+  ;
+}
+  }
+
+  void memberExpr_test2(int i) {
+while(i < m) {
+  --m;
+}
+  }
+  int m;
+};
Index: docs/clang-tidy/checks/list.rst
===
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -28,6 +28,7 @@
bugprone-forwarding-reference-overload
bugprone-inaccurate-erase
bugprone-incorrect-roundings
+   bugprone-infinite-loop
bugprone-integer-division
bugprone-lambda-function-name
bugprone-macro-parentheses
Index: docs/clang-tidy/checks/bugprone-infinite-loop.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/bugprone-infinite-loop.rst
@@ -0,0 +1,30 @@
+.. title:: clang-tidy - bugprone-infinite-loop
+
+bugprone-infinite-loop
+==
+
+Finds loops where none of the condition variables are updated in the body. This
+performs a very conservative check in order to avoid false positives and work
+only on integer types at the moment.
+
+Examples:
+
+.. code-block:: c++
+
+  void simple_infinite_loop() {
+int i = 0;
+int j = 0;
+int Limit = 10;
+while (i < Limit) { // Error, since none of the variables are updated.
+  j++;
+}
+  }
+
+  void escape_before() {
+int i = 0;
+int Limit = 100;
+int *p = 
+while (i < Limit) { // Not an error, since p is alias of i.
+  *++p;
+}
+  }
Index: docs/ReleaseNotes.rst

[PATCH] D43967: [ASTImporter] Add test helper Fixture

2018-03-30 Thread Peter Szecsi via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC328906: [ASTImporter] Add test helper Fixture (authored by 
szepet, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D43967?vs=139791=140497#toc

Repository:
  rC Clang

https://reviews.llvm.org/D43967

Files:
  unittests/AST/ASTImporterTest.cpp
  unittests/AST/DeclMatcher.h

Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -17,6 +17,8 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Tooling/Tooling.h"
+
+#include "DeclMatcher.h"
 #include "gtest/gtest.h"
 
 namespace clang {
@@ -29,7 +31,7 @@
   return Lang == Lang_CXX || Lang == Lang_CXX11;
 }
 
-static RunOptions getRunOptionsForLanguage(Language Lang) {
+static ArgVector getBasicRunOptionsForLanguage(Language Lang) {
   ArgVector BasicArgs;
   // Test with basic arguments.
   switch (Lang) {
@@ -49,6 +51,11 @@
   case Lang_OBJCXX:
 llvm_unreachable("Not implemented yet!");
   }
+  return BasicArgs;
+}
+
+static RunOptions getRunOptionsForLanguage(Language Lang) {
+  ArgVector BasicArgs = getBasicRunOptionsForLanguage(Lang);
 
   // For C++, test with "-fdelayed-template-parsing" enabled to handle MSVC
   // default behaviour.
@@ -61,6 +68,19 @@
   return {BasicArgs};
 }
 
+// Creates a virtual file and assigns that to the context of given AST. If the
+// file already exists then the file will not be created again as a duplicate.
+static void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
+  const std::string ) {
+  assert(ToAST);
+  ASTContext  = ToAST->getASTContext();
+  auto *OFS = static_cast(
+  ToCtx.getSourceManager().getFileManager().getVirtualFileSystem().get());
+  auto *MFS =
+  static_cast(OFS->overlays_begin()->get());
+  MFS->addFile(FileName, 0, llvm::MemoryBuffer::getMemBuffer(Code.c_str()));
+}
+
 template
 testing::AssertionResult
 testImport(const std::string , const ArgVector ,
@@ -79,11 +99,7 @@
 
   // Add input.cc to virtual file system so importer can 'find' it
   // while importing SourceLocations.
-  vfs::OverlayFileSystem *OFS = static_cast(
-ToCtx.getSourceManager().getFileManager().getVirtualFileSystem().get());
-  vfs::InMemoryFileSystem *MFS = static_cast(
-OFS->overlays_begin()->get());
-  MFS->addFile(InputFileName, 0, llvm::MemoryBuffer::getMemBuffer(FromCode));
+  createVirtualFileIfNeeded(ToAST.get(), InputFileName, FromCode);
 
   ASTImporter Importer(ToCtx, ToAST->getFileManager(),
FromCtx, FromAST->getFileManager(), false);
@@ -133,6 +149,165 @@
  Verifier, AMatcher));
 }
 
+const StringRef DeclToImportID = "declToImport";
+
+// This class provides generic methods to write tests which can check internal
+// attributes of AST nodes like getPreviousDecl(), isVirtual(), etc.  Also,
+// this fixture makes it possible to import from several "From" contexts.
+class ASTImporterTestBase : public ::testing::TestWithParam {
+
+  const char *const InputFileName = "input.cc";
+  const char *const OutputFileName = "output.cc";
+
+  // Buffer for the To context, must live in the test scope.
+  std::string ToCode;
+
+  struct TU {
+// Buffer for the context, must live in the test scope.
+std::string Code;
+std::string FileName;
+std::unique_ptr Unit;
+TranslationUnitDecl *TUDecl = nullptr;
+TU(StringRef Code, StringRef FileName, ArgVector Args)
+: Code(Code), FileName(FileName),
+  Unit(tooling::buildASTFromCodeWithArgs(this->Code, Args,
+ this->FileName)),
+  TUDecl(Unit->getASTContext().getTranslationUnitDecl()) {}
+  };
+
+  // We may have several From contexts and related translation units. In each
+  // AST, the buffers for the source are handled via references and are set
+  // during the creation of the AST. These references must point to a valid
+  // buffer until the AST is alive. Thus, we must use a list in order to avoid
+  // moving of the stored objects because that would mean breaking the
+  // references in the AST. By using a vector a move could happen when the
+  // vector is expanding, with the list we won't have these issues.
+  std::list FromTUs;
+
+public:
+  // We may have several From context but only one To context.
+  std::unique_ptr ToAST;
+
+  // Returns the argument vector used for a specific language, this set
+  // can be tweaked by the test parameters.
+  ArgVector getArgVectorForLanguage(Language Lang) {
+ArgVector Args = getBasicRunOptionsForLanguage(Lang);
+ArgVector ExtraArgs = GetParam();
+for (const auto& Arg : ExtraArgs) {
+  Args.push_back(Arg);
+}
+return Args;
+  }
+
+  // Creates an AST both for the From and To source code and 

[PATCH] D45086: [analyzer] Unroll the loop when it has a unsigned counter.

2018-03-30 Thread Peter Szecsi via Phabricator via cfe-commits
szepet accepted this revision.
szepet added a comment.

Yepp, thanks for the patch! One small typo below.




Comment at: test/Analysis/loop-unrolling.cpp:50
+
+int simple_unroll4_unsinged() {
+  int a[9];

typo: unsigned


Repository:
  rC Clang

https://reviews.llvm.org/D45086



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


[PATCH] D38921: [analyzer] LoopUnrolling: update the matched assignment operators

2018-03-27 Thread Peter Szecsi via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC328619: [analyzer] LoopUnrolling: update the matched 
assignment operators (authored by szepet, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D38921

Files:
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  test/Analysis/loop-unrolling.cpp

Index: test/Analysis/loop-unrolling.cpp
===
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -99,13 +99,101 @@
   return 0;
 }
 
+int no_unroll_assignment() {
+  for (int i = 0; i < 9; i++) {
+i = i + 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment2() {
+  for (int i = 0; i < 9; i++) {
+i *= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment3() {
+  for (int i = 128; i > 0; i--) {
+i /= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment4() {
+  for (int i = 0; i < 9; i++) {
+i -= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment5() {
+  for (int i = 0; i < 9; i++) {
+i += 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment6() {
+  for (int i = 128; i > 0; i--) {
+i >>= 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment7() {
+  for (int i = 0; i < 512; i++) {
+i <<= 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment8() {
+  for (int i = 0; i < 9; i++) {
+i %= 8;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment9() {
+  for (int i = 0; i < 9; i++) {
+i &= 31;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment10() {
+  for (int i = 0; i < 9; i++) {
+i |= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment11() {
+  for (int i = 0; i < 9; i++) {
+i ^= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
 int make_new_branches_loop_cached() {
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{4}}
-if(getNum()){
-(void) i; // Since this Stmt does not change the State the analyzer
-  // won't make a new execution path but reuse the earlier nodes.
-  }
+if (getNum()) {
+  (void)i; // Since this Stmt does not change the State the analyzer
+   // won't make a new execution path but reuse the earlier nodes.
+}
   }
   clang_analyzer_warnIfReached(); // no-warning
   return 0;
@@ -115,7 +203,7 @@
   int l = 2;
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{10}}
-if(getNum()){
+if (getNum()) {
   ++l;
 }
   }
@@ -127,7 +215,7 @@
   int l = 2;
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{10}}
-if(getNum()){
+if (getNum()) {
   ++l;
 }
 (void) // This ensures that the loop won't be unrolled.
@@ -185,7 +273,7 @@
 for (j = 0; j < 9; ++j) {
   clang_analyzer_numTimesReached(); // expected-warning {{4}}
   a[j] = 22;
-  (void)  // ensures that the inner loop won't be unrolled
+  (void) // ensures that the inner loop won't be unrolled
 }
 a[i] = 42;
   }
@@ -268,8 +356,8 @@
   int k = 2;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{13}}
-if(i == 0 && b) // Splits the state in the first iteration but the recursion
-// call will be unrolled anyway since the condition is known there.
+if (i == 0 && b)  // Splits the state in the first iteration but the recursion
+  // call will be unrolled anyway since the condition is known there.
   recursion_unroll1(false);
 clang_analyzer_numTimesReached(); // expected-warning {{14}}
   }
@@ -281,7 +369,7 @@
   int k = 0;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{9}}
-if(i == 0 && b)
+if (i == 0 && b)
   recursion_unroll2(false);
 clang_analyzer_numTimesReached(); // expected-warning {{9}}
   }
@@ -307,7 +395,7 @@
   int k = 2;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{13}}
-if(i == 0 && b) {
+if (i == 0 && b) {
   recursion_unroll4(false);
   continue;
 }
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- 

[PATCH] D44893: [ASTMatchers] Add isAssignmentOperator matcher

2018-03-27 Thread Peter Szecsi via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC328618: [ASTMatchers] Add isAssignmentOperator matcher 
(authored by szepet, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D44893?vs=139769=139900#toc

Repository:
  rC Clang

https://reviews.llvm.org/D44893

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

Index: docs/LibASTMatchersReference.html
===
--- docs/LibASTMatchersReference.html
+++ docs/LibASTMatchersReference.html
@@ -1926,6 +1926,19 @@
 
 
 
+Matcherhttp://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html;>BinaryOperatorisAssignmentOperator
+Matches all kinds of assignment operators.
+
+Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+  if (a == b)
+a += b;
+
+Example 2: matches s1 = s2 (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+  struct S { S& operator=(const S&); };
+  void x() { S s1, s2; s1 = s2; })
+
+
+
 Matcherhttp://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html;>CXXBoolLiteralExprequalsbool Value
 
 
@@ -2306,6 +2319,19 @@
 
 
 
+Matcherhttp://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html;>CXXOperatorCallExprisAssignmentOperator
+Matches all kinds of assignment operators.
+
+Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+  if (a == b)
+a += b;
+
+Example 2: matches s1 = s2 (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+  struct S { S& operator=(const S&); };
+  void x() { S s1, s2; s1 = s2; })
+
+
+
 Matcherhttp://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html;>CXXRecordDeclhasDefinition
 Matches a class declaration that is defined.
 
Index: include/clang/ASTMatchers/ASTMatchers.h
===
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -4003,6 +4003,26 @@
   return Name == Node.getOpcodeStr(Node.getOpcode());
 }
 
+/// \brief Matches on all kinds of assignment operators.
+///
+/// Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+/// \code
+///   if (a == b)
+/// a += b;
+/// \endcode
+///
+/// Example 2: matches s1 = s2
+///(matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+/// \code
+///   struct S { S& operator=(const S&); };
+///   void x() { S s1, s2; s1 = s2; })
+/// \endcode
+AST_POLYMORPHIC_MATCHER(isAssignmentOperator,
+AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator,
+CXXOperatorCallExpr)) {
+  return Node.isAssignmentOp();
+}
+
 /// \brief Matches the left hand side of binary operator expressions.
 ///
 /// Example matches a (matcher = binaryOperator(hasLHS()))
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -322,6 +322,7 @@
   REGISTER_MATCHER(isAnyPointer);
   REGISTER_MATCHER(isArray);
   REGISTER_MATCHER(isArrow);
+  REGISTER_MATCHER(isAssignmentOperator);
   REGISTER_MATCHER(isBaseInitializer);
   REGISTER_MATCHER(isBitField);
   REGISTER_MATCHER(isCatchAll);
Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2139,5 +2139,20 @@
   functionDecl(hasTrailingReturn(;
 }
 
+TEST(IsAssignmentOperator, Basic) {
+  StatementMatcher BinAsgmtOperator = binaryOperator(isAssignmentOperator());
+  StatementMatcher CXXAsgmtOperator =
+  cxxOperatorCallExpr(isAssignmentOperator());
+
+  EXPECT_TRUE(matches("void x() { int a; a += 1; }", BinAsgmtOperator));
+  EXPECT_TRUE(matches("void x() { int a; a = 2; }", BinAsgmtOperator));
+  EXPECT_TRUE(matches("void x() { int a; a &= 3; }", BinAsgmtOperator));
+  EXPECT_TRUE(matches("struct S { S& operator=(const S&); };"
+  "void x() { S s1, s2; s1 = s2; }",
+  CXXAsgmtOperator));
+  EXPECT_TRUE(
+  notMatches("void x() { int a; if(a == 0) return; }", BinAsgmtOperator));
+}
+
 } // namespace ast_matchers
 } // namespace clang
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38921: [analyzer] LoopUnrolling: update the matched assignment operators

2018-03-26 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 139776.
szepet added a comment.

Added the assignment operator matcher patch as a dependency and rebased on top 
of that.


https://reviews.llvm.org/D38921

Files:
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  test/Analysis/loop-unrolling.cpp

Index: test/Analysis/loop-unrolling.cpp
===
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -99,13 +99,101 @@
   return 0;
 }
 
+int no_unroll_assignment() {
+  for (int i = 0; i < 9; i++) {
+i = i + 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment2() {
+  for (int i = 0; i < 9; i++) {
+i *= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment3() {
+  for (int i = 128; i > 0; i--) {
+i /= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment4() {
+  for (int i = 0; i < 9; i++) {
+i -= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment5() {
+  for (int i = 0; i < 9; i++) {
+i += 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment6() {
+  for (int i = 128; i > 0; i--) {
+i >>= 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment7() {
+  for (int i = 0; i < 512; i++) {
+i <<= 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment8() {
+  for (int i = 0; i < 9; i++) {
+i %= 8;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment9() {
+  for (int i = 0; i < 9; i++) {
+i &= 31;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment10() {
+  for (int i = 0; i < 9; i++) {
+i |= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment11() {
+  for (int i = 0; i < 9; i++) {
+i ^= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
 int make_new_branches_loop_cached() {
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{4}}
-if(getNum()){
-(void) i; // Since this Stmt does not change the State the analyzer
-  // won't make a new execution path but reuse the earlier nodes.
-  }
+if (getNum()) {
+  (void)i; // Since this Stmt does not change the State the analyzer
+   // won't make a new execution path but reuse the earlier nodes.
+}
   }
   clang_analyzer_warnIfReached(); // no-warning
   return 0;
@@ -115,7 +203,7 @@
   int l = 2;
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{10}}
-if(getNum()){
+if (getNum()) {
   ++l;
 }
   }
@@ -127,7 +215,7 @@
   int l = 2;
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{10}}
-if(getNum()){
+if (getNum()) {
   ++l;
 }
 (void) // This ensures that the loop won't be unrolled.
@@ -185,7 +273,7 @@
 for (j = 0; j < 9; ++j) {
   clang_analyzer_numTimesReached(); // expected-warning {{4}}
   a[j] = 22;
-  (void)  // ensures that the inner loop won't be unrolled
+  (void) // ensures that the inner loop won't be unrolled
 }
 a[i] = 42;
   }
@@ -268,8 +356,8 @@
   int k = 2;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{13}}
-if(i == 0 && b) // Splits the state in the first iteration but the recursion
-// call will be unrolled anyway since the condition is known there.
+if (i == 0 && b)  // Splits the state in the first iteration but the recursion
+  // call will be unrolled anyway since the condition is known there.
   recursion_unroll1(false);
 clang_analyzer_numTimesReached(); // expected-warning {{14}}
   }
@@ -281,7 +369,7 @@
   int k = 0;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{9}}
-if(i == 0 && b)
+if (i == 0 && b)
   recursion_unroll2(false);
 clang_analyzer_numTimesReached(); // expected-warning {{9}}
   }
@@ -307,7 +395,7 @@
   int k = 2;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{13}}
-if(i == 0 && b) {
+if (i == 0 && b) {
   recursion_unroll4(false);
   continue;
 }
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -97,9 +97,7 

[PATCH] D38921: [analyzer] LoopUnrolling: update the matched assignment operators

2018-03-26 Thread Peter Szecsi via Phabricator via cfe-commits
szepet marked 2 inline comments as done.
szepet added a comment.

In https://reviews.llvm.org/D38921#1037180, @alexfh wrote:

> Do you want to submit the matcher part separately?


Yepp, but added as a different patch since implemented it for cxxOperatorCall 
as well. (I guess Aaron's test request implied it and I find it useful as well.)
See: https://reviews.llvm.org/D44893


https://reviews.llvm.org/D38921



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


[PATCH] D44893: [ASTMatchers] Add isAssignmentOperator matcher

2018-03-26 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.
szepet added reviewers: aaron.ballman, alexfh.
Herald added subscribers: dkrupp, rnkovacs, klimek.

Adding a matcher for BinaryOperator and cxxOperatorCallExpr to be able to 
decide whether it is any kind of assignment operator or not. This would be 
useful since allows us to easily detect assignments via matchers for static 
analysis (Tidy, SA) purposes.


Repository:
  rC Clang

https://reviews.llvm.org/D44893

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

Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2139,5 +2139,20 @@
   functionDecl(hasTrailingReturn(;
 }
 
+TEST(IsAssignmentOperator, Basic) {
+  StatementMatcher BinAsgmtOperator = binaryOperator(isAssignmentOperator());
+  StatementMatcher CXXAsgmtOperator =
+  cxxOperatorCallExpr(isAssignmentOperator());
+
+  EXPECT_TRUE(matches("void x() { int a; a += 1; }", BinAsgmtOperator));
+  EXPECT_TRUE(matches("void x() { int a; a = 2; }", BinAsgmtOperator));
+  EXPECT_TRUE(matches("void x() { int a; a &= 3; }", BinAsgmtOperator));
+  EXPECT_TRUE(matches("struct S { S& operator=(const S&); };"
+  "void x() { S s1, s2; s1 = s2; }",
+  CXXAsgmtOperator));
+  EXPECT_TRUE(
+  notMatches("void x() { int a; if(a == 0) return; }", BinAsgmtOperator));
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -322,6 +322,7 @@
   REGISTER_MATCHER(isAnyPointer);
   REGISTER_MATCHER(isArray);
   REGISTER_MATCHER(isArrow);
+  REGISTER_MATCHER(isAssignmentOperator);
   REGISTER_MATCHER(isBaseInitializer);
   REGISTER_MATCHER(isBitField);
   REGISTER_MATCHER(isCatchAll);
Index: include/clang/ASTMatchers/ASTMatchers.h
===
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -4003,6 +4003,26 @@
   return Name == Node.getOpcodeStr(Node.getOpcode());
 }
 
+/// \brief Matches on all kinds of assignment operators.
+///
+/// Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+/// \code
+///   if (a == b)
+/// a += b;
+/// \endcode
+///
+/// Example 2: matches s1 = s2
+///(matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+/// \code
+///   struct S { S& operator=(const S&); };
+///   void x() { S s1, s2; s1 = s2; })
+/// \endcode
+AST_POLYMORPHIC_MATCHER(isAssignmentOperator,
+AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator,
+CXXOperatorCallExpr)) {
+  return Node.isAssignmentOp();
+}
+
 /// \brief Matches the left hand side of binary operator expressions.
 ///
 /// Example matches a (matcher = binaryOperator(hasLHS()))
Index: docs/LibASTMatchersReference.html
===
--- docs/LibASTMatchersReference.html
+++ docs/LibASTMatchersReference.html
@@ -1926,6 +1926,19 @@
 
 
 
+Matcherhttp://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html;>BinaryOperatorisAssignmentOperator
+Matches all kinds of assignment operators.
+
+Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+  if (a == b)
+a += b;
+
+Example 2: matches s1 = s2 (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+  struct S { S& operator=(const S&); };
+  void x() { S s1, s2; s1 = s2; })
+
+
+
 Matcherhttp://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html;>CXXBoolLiteralExprequalsbool Value
 
 
@@ -2306,6 +2319,19 @@
 
 
 
+Matcherhttp://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html;>CXXOperatorCallExprisAssignmentOperator
+Matches all kinds of assignment operators.
+
+Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+  if (a == b)
+a += b;
+
+Example 2: matches s1 = s2 (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+  struct S { S& operator=(const S&); };
+  void x() { S s1, s2; s1 = s2; })
+
+
+
 Matcherhttp://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html;>CXXRecordDeclhasDefinition
 Matches a class declaration that is defined.
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D44606: [analyzer] Fix the crash in `IteratorChecker.cpp` when `SymbolConjured` has a null Stmt.

2018-03-19 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

Nice catch, it looks good to me! Thank you!
One small nit for future debugging people: Could you insert a comment line in 
the test case where you explain what is this all about? E.g what you just have 
written in the description: "invalidateRegions() will construct the 
SymbolConjured with null Stmt" or something like this.


Repository:
  rC Clang

https://reviews.llvm.org/D44606



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


[PATCH] D42266: [analyzer] Prevent AnalyzerStatsChecker from crash

2018-02-21 Thread Peter Szecsi via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC325693: [analyzer] Prevent AnalyzerStatsChecker from crash 
(authored by szepet, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D42266?vs=130501=135266#toc

Repository:
  rC Clang

https://reviews.llvm.org/D42266

Files:
  lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
  test/Analysis/analyzer-stats.c


Index: test/Analysis/analyzer-stats.c
===
--- test/Analysis/analyzer-stats.c
+++ test/Analysis/analyzer-stats.c
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 
-analyzer-checker=core,deadcode.DeadStores,debug.Stats -verify 
-Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,deadcode.DeadStores,debug.Stats -verify 
-Wno-unreachable-code -analyzer-opt-analyze-nested-blocks -analyzer-max-loop 4 
%s
 
 int foo();
 
@@ -12,3 +12,19 @@
   a /= 4;
   return a;
 }
+
+
+int sink() // expected-warning-re{{sink -> Total CFGBlocks: {{[0-9]+}} | 
Unreachable CFGBlocks: 1 | Exhausted Block: yes | Empty WorkList: yes}}
+{
+  for (int i = 0; i < 10; ++i) // expected-warning {{(sink): The analyzer 
generated a sink at this point}}
+++i;
+
+  return 0;
+}
+
+int emptyConditionLoop() // expected-warning-re{{emptyConditionLoop -> Total 
CFGBlocks: {{[0-9]+}} | Unreachable CFGBlocks: 0 | Exhausted Block: yes | Empty 
WorkList: yes}}
+{
+  int num = 1;
+  for (;;)
+num++;
+}
Index: lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -122,6 +122,8 @@
   E = CE.blocks_exhausted_end(); I != E; ++I) {
 const BlockEdge  =  I->first;
 const CFGBlock *Exit = BE.getDst();
+if (Exit->empty())
+  continue;
 const CFGElement  = Exit->front();
 if (Optional CS = CE.getAs()) {
   SmallString<128> bufI;


Index: test/Analysis/analyzer-stats.c
===
--- test/Analysis/analyzer-stats.c
+++ test/Analysis/analyzer-stats.c
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,deadcode.DeadStores,debug.Stats -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,deadcode.DeadStores,debug.Stats -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks -analyzer-max-loop 4 %s
 
 int foo();
 
@@ -12,3 +12,19 @@
   a /= 4;
   return a;
 }
+
+
+int sink() // expected-warning-re{{sink -> Total CFGBlocks: {{[0-9]+}} | Unreachable CFGBlocks: 1 | Exhausted Block: yes | Empty WorkList: yes}}
+{
+  for (int i = 0; i < 10; ++i) // expected-warning {{(sink): The analyzer generated a sink at this point}}
+++i;
+
+  return 0;
+}
+
+int emptyConditionLoop() // expected-warning-re{{emptyConditionLoop -> Total CFGBlocks: {{[0-9]+}} | Unreachable CFGBlocks: 0 | Exhausted Block: yes | Empty WorkList: yes}}
+{
+  int num = 1;
+  for (;;)
+num++;
+}
Index: lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -122,6 +122,8 @@
   E = CE.blocks_exhausted_end(); I != E; ++I) {
 const BlockEdge  =  I->first;
 const CFGBlock *Exit = BE.getDst();
+if (Exit->empty())
+  continue;
 const CFGElement  = Exit->front();
 if (Optional CS = CE.getAs()) {
   SmallString<128> bufI;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D16403: Add scope information to CFG

2018-02-21 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

In https://reviews.llvm.org/D16403#1011218, @NoQ wrote:

> Yeah, i mean, like, if we change the scope markers to also appear even when 
> no variables are present in the scope, then it would be possible to replace 
> loop markers with some of the scope markers, right?


OK, probably I am a bit too slow for this, but I dont get it. Yes, it would be 
possible to replace them IF these markers appears even in case of no variables. 
However, this patch is based on LocalScopes which practically means that 
VarDecls are needed.  Aaand here we are, it would require a different approach 
to consistently mark things like LoopExit.
 Another thing that what should be the TriggerStmt? I guess the Stmt of the 
loop. So, LoopExit and ScopeExit would be the same but the underlying 
TriggerStmt would decide which marks a loop and which marks a variable? Then I 
can just rewrite LoopExit into ScopeEnd. Or if you would like to see that, a 
subclass of ScopeEnd. However, the main functionality should stay the same (I 
guess).
So, could you help me out what are those things I do not see/understand?


Repository:
  rL LLVM

https://reviews.llvm.org/D16403



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


[PATCH] D39398: [CFG][Analyzer] Add LoopExit element to the CFG in more cases

2018-02-16 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.
Herald added a reviewer: george.karpenkov.

ping


https://reviews.llvm.org/D39398



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


[PATCH] D41150: [CFG] Adding new CFGStmt LoopEntrance for the StaticAnalyzer

2018-02-16 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.
Herald added a reviewer: george.karpenkov.

ping


https://reviews.llvm.org/D41150



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


[PATCH] D16403: Add scope information to CFG

2018-02-16 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

In https://reviews.llvm.org/D16403#992452, @NoQ wrote:

> Thank you, this explanation looks very reasonable.
>
> All right, so right after the termination of the loop we have
>
>   [B1]
>   1: ForStmt (LoopExit)
>   2: [B4.5].~A() (Implicit destructor)
>   3: [B5.3].~A() (Implicit destructor)
>   4: CFGScopeEnd(a)
>   5: CFGScopeEnd(b)
>
>
> ... where `[B4.5]` is `A b = a;` and `[B5.3]` is `A a;`. Am i understanding 
> correctly that while destroying `a` you can still use the storage of `b` 
> safely? Or should `a` go out of scope before `b` gets destroyed? Also, is the 
> order of scope ends actually correct here - shouldn't `b` go out of scope 
> earlier? Given that they are in very different lifetime scopes (`a` is one 
> for the whole loop, `b` is per-loop-iteration). I guess the order would 
> matter for the analyzer.


I guess CFGScopeEnd should happen (should be encountered) before the LoopExit 
and CFGScopeBegin should be after LoopEntrance (still not sure if it is going 
to be part of the CFG ever.) Just like parenthesis {(())}  that is what would 
make the most sense for me. However, I do not want to block this patch or 
something so I can do these changes as well by modifying LoopExit (and probably 
should since ImplicitDestructor calls should precede the LoopExit as well).

In https://reviews.llvm.org/D16403#992454, @NoQ wrote:

> @szepet: so i see that `LoopExit` goes in the beginning of the cleanup block 
> after the loop, while various `ScopeEnd`s go after the `LoopExit`. Would loop 
> unrolling be significantly broken if you simply subscribe to `ScopeEnd` 
> instead of `LoopExit` and avoid cleaning up the loop state until destructors 
> are processed? I might not be remembering correctly - is `LoopExit` only used 
> for cleanup, or do we have more work to be done here?


I guess your following comment just answers this:

In https://reviews.llvm.org/D16403#1001466, @NoQ wrote:

> We still don't have scopes for segments of code that don't have any variables 
> in them, so i guess it's not yet in the shape where it is super useful for 
> loops, but it's already useful for finding use of stale stack variables, 
> which was the whole point originally, so i think this should definitely land 
> soon.


It could be, however, we would lose cases like:

  int i = 0;
  int a[32];
  for(i = 0;i<32;++i) {a[i] = i;}

Since there is no variable which has the scope of the loop, ScopeEnd would be 
not enough. Sure, we could remove this case, however, the aim is to extend the 
loop-patterns for completely unrolling. Another thing that there are the 
patches which would enhance the covered cases by LoopExit 
(https://reviews.llvm.org/D39398) and add the LoopEntrance to the 
CFG(https://reviews.llvm.org/D41150) as well. So, at this point, I feel like it 
would be a huge step back not to use these elements. (Sorry Maxim that we are 
discussing this here^^)


Repository:
  rL LLVM

https://reviews.llvm.org/D16403



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


[PATCH] D42266: [analyzer] Prevent AnalyzerStatsChecker from crash

2018-01-21 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

> Would it make sense to use the last element of the block edge's source for 
> the diagnostic location when the destination block is empty?

I do not think so. In the testfile `emptyConditionLoop` function is a great 
counter example since the last element of the source block is the `num = 1` 
which would not make sense (in my opinion). However, in this case the location 
of the terminator statement could be used (if there is any). If you are OK with 
that solution, I can update the patch.


Repository:
  rC Clang

https://reviews.llvm.org/D42266



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


[PATCH] D41151: [analyzer] Adding LoopContext and improve loop modeling

2018-01-18 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added inline comments.



Comment at: lib/StaticAnalyzer/Core/LoopUnrolling.cpp:28-46
 struct LoopState {
 private:
   enum Kind { Normal, Unrolled } K;
-  const Stmt *LoopStmt;
-  const LocationContext *LCtx;
-  unsigned maxStep;
-  LoopState(Kind InK, const Stmt *S, const LocationContext *L, unsigned N)
-  : K(InK), LoopStmt(S), LCtx(L), maxStep(N) {}
+  unsigned MaxStep;
+  LoopState(Kind InK, unsigned N) : K(InK), MaxStep(N) {}
 
 public:

NoQ wrote:
> Should the whole `LoopState` be reduced to a field(s) in `LoopContext`? It 
> seems to make sense to me, unless we're planning to modify it in the middle 
> of the loop.
I'm not sure about that. I mean, LoopContext is a general thing for all of the 
loops. It can easily happen that we modify the bound in the middle of the loop. 
Another thing what we keep track on if it is unrolled or not which is again 
something that we can decide to change in the middle of an iteration (e.g. it 
splits the state).

Yes, in our case MaxStep is not likely to change since we store loops that have 
a fix bound. (This could change in the future but maybe this is a too bold 
idea.)


https://reviews.llvm.org/D41151



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


[PATCH] D41151: [analyzer] Adding LoopContext and improve loop modeling

2018-01-18 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 130516.
szepet marked 2 inline comments as done.
szepet added a comment.

First, sorry for this delayed update, however, I was working on this and 
running this on real projects. I wanted to make sure that this update will be 
complete enough that this patch would not cause any harm (yes, these features 
are hidden behind a flag but anyway) and not crashes on edge cases I haven't 
thought of. The core used the fact that LocationContext only contains 
StackFramce and BlockInvocation and I aimed to eliminate all these code 
snippets (more like rewrite).

> This thing is very similar to https://reviews.llvm.org/D19979. Do we really 
> need to create a separate LoopContext or we can reuse ScopeContext instead?



> I guess LoopContext can be treated as a sub-class of ScopeContext. And i 
> don't mind having ScopeContext be split into small distinct sub-classes. 
> Because we're stuck in corner cases for covering all possible scopes, while 
> we're fine with covering only simple scopes (it's better than nothing) and 
> lacking a scope from time to time.

In this patch I left it as it was, so a separate context. I agree with Aleksei 
that yes, it could be implemented as a ScopeContext and checked if it contains 
a While/Do/For Statement.
On the other hand, I like the idea more, that we split ScopeContext into small 
distinct subclasses which would result in a more manageable code.
However, this would require refactoring on ScopeContext as well, in order to 
make it a great base class (like StmtPoint for ProgramPoint). Then, LoopContext 
would be its only subclass. So, I do not really see the point of doing these 
changes right now. I think in this state (when ScopeContext not used by the 
analyzer as I can see) the LoopContext could live as a separate Context and not 
make any harm. In case when another Context shows up which is similar 
LoopContext (e.g. ScopeContext) I would happily refactor it but right now, I do 
not see the point of this.


https://reviews.llvm.org/D41151

Files:
  include/clang/Analysis/AnalysisDeclContext.h
  include/clang/Analysis/ProgramPoint.h
  include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
  lib/Analysis/AnalysisDeclContext.cpp
  lib/StaticAnalyzer/Core/BugReporter.cpp
  lib/StaticAnalyzer/Core/CallEvent.cpp
  lib/StaticAnalyzer/Core/CoreEngine.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  lib/StaticAnalyzer/Core/PathDiagnostic.cpp
  test/Analysis/loop-unrolling.cpp

Index: test/Analysis/loop-unrolling.cpp
===
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -373,7 +373,6 @@
   return 0;
 }
 
-
 void pr34943() {
   for (int i = 0; i < 6L; ++i) {
 clang_analyzer_numTimesReached(); // expected-warning {{6}}
Index: lib/StaticAnalyzer/Core/PathDiagnostic.cpp
===
--- lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -576,12 +576,18 @@
   return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
 return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
   }
+  case CFGElement::LoopEntrance: {
+const Stmt *LoopStmt = Source.castAs().getLoopStmt();
+return PathDiagnosticLocation(LoopStmt, SM, CallerCtx);
+  }
+  case CFGElement::LoopExit: {
+const Stmt *LoopStmt = Source.castAs().getLoopStmt();
+return PathDiagnosticLocation::createEnd(LoopStmt, SM, CallerCtx);
+  }
   case CFGElement::TemporaryDtor:
   case CFGElement::NewAllocator:
 llvm_unreachable("not yet implemented!");
   case CFGElement::LifetimeEnds:
-  case CFGElement::LoopExit:
-  case CFGElement::LoopEntrance:
 llvm_unreachable("CFGElement kind should not be on callsite!");
   }
 
@@ -742,6 +748,10 @@
 return CEE->getCalleeContext()->getCallSite();
   if (Optional PIPP = P.getAs())
 return PIPP->getInitializer()->getInit();
+  if (Optional LE = P.getAs())
+return LE->getLoopStmt();
+  if (Optional LE = P.getAs())
+return LE->getLoopStmt();
 
   return nullptr;
 }
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -13,11 +13,11 @@
 ///
 //===--===//
 
-#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include 

[PATCH] D41150: [CFG] Adding new CFGStmt LoopEntrance for the StaticAnalyzer

2018-01-18 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 130505.
szepet added a comment.

> I essentially have one question at a glance - for loop counter variables, 
> don't we want LoopEntrance be before the initialization?

I guess this would just make too much sense. Done that.

Additionally, handle the cases when we just hop to the body of the loop via 
goto stmt.
Now the patches can be applied without any conflict (added the loopexit patch 
as a dependency).


https://reviews.llvm.org/D41150

Files:
  include/clang/Analysis/CFG.h
  lib/Analysis/CFG.cpp
  lib/StaticAnalyzer/Core/PathDiagnostic.cpp
  test/Analysis/loopexit-cfg-output.cpp

Index: test/Analysis/loopexit-cfg-output.cpp
===
--- test/Analysis/loopexit-cfg-output.cpp
+++ test/Analysis/loopexit-cfg-output.cpp
@@ -32,8 +32,9 @@
 // CHECK-NEXT:   Succs (2): B3 B1
 
 // CHECK:   [B5]
-// CHECK-NEXT:   1: 0
-// CHECK-NEXT:   2: int i = 0;
+// CHECK-NEXT:   1: ForStmt (LoopEntrance)
+// CHECK-NEXT:   2: 0
+// CHECK-NEXT:   3: int i = 0;
 // CHECK-NEXT:   Preds (1): B6
 // CHECK-NEXT:   Succs (1): B4
 
@@ -46,8 +47,8 @@
   return;
 }
 
-// CHECK:   [B4 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B3
+// CHECK:   [B5 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B4
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: ForStmt (LoopExit)
@@ -62,15 +63,20 @@
 // CHECK-NEXT:   Preds (2): B2 B4
 // CHECK-NEXT:   Succs (2): B2 NULL
 
+// CHECK:   [B4]
+// CHECK-NEXT:   1: ForStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B5
+// CHECK-NEXT:   Succs (1): B3
+
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
 void check_forloop2() {
   for (;;)
 ;
 }
 
-// CHECK:   [B5 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B4
+// CHECK:   [B6 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B5
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: WhileStmt (LoopExit)
@@ -91,6 +97,11 @@
 // CHECK-NEXT:   Preds (2): B2 B5
 // CHECK-NEXT:   Succs (2): B3 NULL
 
+// CHECK:   [B5]
+// CHECK-NEXT:   1: WhileStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B4
+
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
 void check_while1() {
@@ -125,6 +136,7 @@
 
 // CHECK:   [B4]
 // CHECK-NEXT:   1: int l;
+// CHECK-NEXT:   2: WhileStmt (LoopEntrance)
 // CHECK-NEXT:   Preds (1): B5
 // CHECK-NEXT:   Succs (1): B3
 
@@ -138,8 +150,8 @@
   return;
 }
 
-// CHECK:   [B4 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B3
+// CHECK:   [B5 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B4
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: WhileStmt (LoopExit)
@@ -155,16 +167,21 @@
 // CHECK-NEXT:   Preds (2): B2 B4
 // CHECK-NEXT:   Succs (2): NULL B1
 
+// CHECK:   [B4]
+// CHECK-NEXT:   1: WhileStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B5
+// CHECK-NEXT:   Succs (1): B3
+
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
 void check_while3() {
   while (false) {
 ;
   }
 }
 
-// CHECK:   [B4 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B2
+// CHECK:   [B5 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B4
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: DoStmt (LoopExit)
@@ -180,6 +197,11 @@
 // CHECK:   [B3]
 // CHECK-NEXT:   Succs (1): B2
 
+// CHECK:   [B4]
+// CHECK-NEXT:   1: DoStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B5
+// CHECK-NEXT:   Succs (1): B2
+
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
 void check_dowhile1() {
@@ -221,6 +243,7 @@
 // CHECK:   [B5]
 // CHECK-NEXT:   1: 2
 // CHECK-NEXT:   2: int j = 2;
+// CHECK-NEXT:   3: DoStmt (LoopEntrance)
 // CHECK-NEXT:   Preds (1): B6
 // CHECK-NEXT:   Succs (1): B3
 
@@ -274,8 +297,9 @@
 // CHECK-NEXT:   Succs (2): B5 B3
 
 // CHECK:   [B7]
-// CHECK-NEXT:   1: 1
-// CHECK-NEXT:   2: int j = 1;
+// CHECK-NEXT:   1: ForStmt (LoopEntrance)
+// CHECK-NEXT:   2: 1
+// CHECK-NEXT:   3: int j = 1;
 // CHECK-NEXT:   Preds (1): B8
 // CHECK-NEXT:   Succs (1): B6
 
@@ -292,6 +316,7 @@
 // CHECK-NEXT:   1: 40
 // CHECK-NEXT:   2: -[B9.1]
 // CHECK-NEXT:   3: int i = -40;
+// CHECK-NEXT:   4: WhileStmt (LoopEntrance)
 // CHECK-NEXT:   Preds (1): B10
 // CHECK-NEXT:   Succs (1): B8
 
@@ -305,19 +330,19 @@
   }
 }
 
-// CHECK:   [B9 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B8
+// CHECK:   [B10 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B9
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: ForStmt (LoopExit)
-// CHECK-NEXT:   Preds (1): B7
+// CHECK-NEXT:   Preds (1): B8
 // CHECK-NEXT:   Succs (1): B0
 
 // CHECK:   [B2]
 // CHECK-NEXT:   1: j
 // CHECK-NEXT:   2: [B2.1]++
 // CHECK-NEXT:   Preds (1): B3
-// CHECK-NEXT:   Succs (1): B7
+// CHECK-NEXT:   Succs (1): B8
 
 // CHECK:   [B3]
 // CHECK-NEXT:   1: DoStmt (LoopExit)
@@ -346,22 +371,28 @@
 // CHECK-NEXT:   Succs (1): B5
 
 // CHECK:   [B7]
+// CHECK-NEXT:   1: DoStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B8
+// CHECK-NEXT:   Succs (1): B5
+
+// CHECK:   [B8]
 // CHECK-NEXT:   1: j
-// CHECK-NEXT:   2: [B7.1] (ImplicitCastExpr, LValueToRValue, 

[PATCH] D39398: [CFG][Analyzer] Add LoopExit element to the CFG in more cases

2018-01-18 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added inline comments.



Comment at: test/Analysis/loopexit-cfg-output.cpp:912-914
+// CHECK:   [B5]
+// CHECK-NEXT:   Succs (1): B8
+

NoQ wrote:
> P.S. This is not a regression introduced by your patch, but i'm really 
> curious what does this block even do.
I believe this is the corresponding TransitionBlock to the WhileStmt (there is 
always a block which marks the looping back to the head of the loop event) but 
the optimization phase was good enough to detect that we will never proceed on 
that (since the first statement of the while loop is a goto jump).


https://reviews.llvm.org/D39398



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


[PATCH] D39398: [CFG][Analyzer] Add LoopExit element to the CFG in more cases

2018-01-18 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 130503.
szepet marked 2 inline comments as done.
szepet added a comment.

Added comments and removed indirect goto support from this patch.

>   This seems a bit scary because if there's no obvious one-to-once 
> correspondence between entrances and exits along every path, how would we 
> know when to pop loop contexts from the stack of location contexts? Like, if 
> we attach variable lifetime checks to the loop exit, would we need to write 
> additional code in the analyzer to see if the variable indeed goes out of 
> scope on the current path.

Yepp, we should check if the current loop (one quick method on the 
LocationContext) belongs to the LoopExit. This was already necessary in the 
previous patch since cases like:

  if(Cond)
for(;;){...}
  stmt1
  stmt2
  ...

In the above example even if `Cond` is false the analyzer will encounter the 
LoopExit since it is the first element of the `breakBlock` of the loop. (So it 
is within the same block as stmt1 and stmt2)

I have removed IndirectGoto support since it was not precise enough and rather 
handle this in the analyzer. (`isPrecisableModelableLoop` function in the 
https://reviews.llvm.org/D41151)


https://reviews.llvm.org/D39398

Files:
  include/clang/Analysis/CFG.h
  lib/Analysis/CFG.cpp
  test/Analysis/loopexit-cfg-output.cpp

Index: test/Analysis/loopexit-cfg-output.cpp
===
--- test/Analysis/loopexit-cfg-output.cpp
+++ test/Analysis/loopexit-cfg-output.cpp
@@ -458,19 +458,428 @@
 
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
-void check_break()
-{
-  for(int i = 2; i < 6; i++) {
-if(i == 4)
+void check_break() {
+  for (int i = 2; i < 6; i++) {
+if (i == 4)
   break;
   }
 
   int i = 1;
-  while(i<5){
+  while (i < 5) {
 i++;
-if(i%2)
+if (i % 2)
   break;
   }
-  
+
+  return;
+}
+
+// CHECK:   [B11 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B10
+
+// CHECK:   [B1]
+// CHECK-NEXT:   1: ForStmt (LoopExit)
+// CHECK-NEXT:   2: return;
+// CHECK-NEXT:   Preds (1): B9
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:   [B2]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B2.1]++
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (1): B9
+
+// CHECK:   [B3]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   Preds (1): B7
+// CHECK-NEXT:   Succs (1): B2
+
+// CHECK:   [B4]
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B7
+
+// CHECK:   [B5]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   2: ForStmt (LoopExit)
+// CHECK-NEXT:   T: goto lab;
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B10
+
+// CHECK:   [B6]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B6.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 2
+// CHECK-NEXT:   4: [B6.2] % [B6.3]
+// CHECK-NEXT:   5: [B6.4] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT:   T: if [B6.5]
+// CHECK-NEXT:   Preds (1): B7
+// CHECK-NEXT:   Succs (2): B5 B4
+
+// CHECK:   [B7]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B7.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 12
+// CHECK-NEXT:   4: [B7.2] < [B7.3]
+// CHECK-NEXT:   T: while [B7.4]
+// CHECK-NEXT:   Preds (2): B4 B8
+// CHECK-NEXT:   Succs (2): B6 B3
+
+// CHECK:   [B8]
+// CHECK-NEXT:   1: 1
+// CHECK-NEXT:   2: int j = 1;
+// CHECK-NEXT:   Preds (1): B9
+// CHECK-NEXT:   Succs (1): B7
+
+// CHECK:   [B9]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B9.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 10
+// CHECK-NEXT:   4: [B9.2] < [B9.3]
+// CHECK-NEXT:   T: for (...; [B9.4]; ...)
+// CHECK-NEXT:   Preds (2): B2 B10
+// CHECK-NEXT:   Succs (2): B8 B1
+
+// CHECK:   [B10]
+// CHECK-NEXT:   lab:
+// CHECK-NEXT:   1: 0
+// CHECK-NEXT:   2: int i = 0;
+// CHECK-NEXT:   Preds (2): B5 B11
+// CHECK-NEXT:   Succs (1): B9
+
+// CHECK:   [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void check_goto() {
+lab:
+  for (int i = 0; i < 10; i++) {
+int j = 1;
+while (j < 12) {
+  if (j % 2)
+goto lab;
+}
+  }
+  return;
+}
+
+// CHECK:   [B11 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B10
+
+// CHECK:   [B1]
+// CHECK-NEXT:   1: ForStmt (LoopExit)
+// CHECK-NEXT:   2: return;
+// CHECK-NEXT:   Preds (1): B9
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:   [B2]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B2.1]++
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (1): B9
+
+// CHECK:   [B3]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   Preds (1): B7
+// CHECK-NEXT:   Succs (1): B2
+
+// CHECK:   [B4]
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B7
+
+// CHECK:   [B5]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   T: goto lab;
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B8
+
+// CHECK:   [B6]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B6.1] 

[PATCH] D42266: [analyzer] Prevent AnalyzerStatsChecker from crash

2018-01-18 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.
szepet added reviewers: NoQ, dcoughlin, xazax.hun.
Herald added subscribers: dkrupp, a.sidorin, rnkovacs, baloghadamsoftware, 
whisperity.

The checker marks the locations where the analyzer creates sinks. However, it 
can happen that the sink was created because of a loop which does not contain 
condition statement, only breaks in the body. The `exhausted block` is the 
block which should contain the condition but empty, in this case.
This change only emits this marking in order to avoid the undefined behavior.


Repository:
  rC Clang

https://reviews.llvm.org/D42266

Files:
  lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
  test/Analysis/analyzer-stats.c


Index: test/Analysis/analyzer-stats.c
===
--- test/Analysis/analyzer-stats.c
+++ test/Analysis/analyzer-stats.c
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 
-analyzer-checker=core,deadcode.DeadStores,debug.Stats -verify 
-Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,deadcode.DeadStores,debug.Stats -verify 
-Wno-unreachable-code -analyzer-opt-analyze-nested-blocks -analyzer-max-loop 4 
%s
 
 int foo();
 
@@ -12,3 +12,19 @@
   a /= 4;
   return a;
 }
+
+
+int sink() // expected-warning-re{{sink -> Total CFGBlocks: {{[0-9]+}} | 
Unreachable CFGBlocks: 1 | Exhausted Block: yes | Empty WorkList: yes}}
+{
+  for (int i = 0; i < 10; ++i) // expected-warning {{(sink): The analyzer 
generated a sink at this point}}
+++i;
+
+  return 0;
+}
+
+int emptyConditionLoop() // expected-warning-re{{emptyConditionLoop -> Total 
CFGBlocks: {{[0-9]+}} | Unreachable CFGBlocks: 0 | Exhausted Block: yes | Empty 
WorkList: yes}}
+{
+  int num = 1;
+  for (;;)
+num++;
+}
Index: lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -122,6 +122,8 @@
   E = CE.blocks_exhausted_end(); I != E; ++I) {
 const BlockEdge  =  I->first;
 const CFGBlock *Exit = BE.getDst();
+if (Exit->empty())
+  continue;
 const CFGElement  = Exit->front();
 if (Optional CS = CE.getAs()) {
   SmallString<128> bufI;


Index: test/Analysis/analyzer-stats.c
===
--- test/Analysis/analyzer-stats.c
+++ test/Analysis/analyzer-stats.c
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,deadcode.DeadStores,debug.Stats -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,deadcode.DeadStores,debug.Stats -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks -analyzer-max-loop 4 %s
 
 int foo();
 
@@ -12,3 +12,19 @@
   a /= 4;
   return a;
 }
+
+
+int sink() // expected-warning-re{{sink -> Total CFGBlocks: {{[0-9]+}} | Unreachable CFGBlocks: 1 | Exhausted Block: yes | Empty WorkList: yes}}
+{
+  for (int i = 0; i < 10; ++i) // expected-warning {{(sink): The analyzer generated a sink at this point}}
+++i;
+
+  return 0;
+}
+
+int emptyConditionLoop() // expected-warning-re{{emptyConditionLoop -> Total CFGBlocks: {{[0-9]+}} | Unreachable CFGBlocks: 0 | Exhausted Block: yes | Empty WorkList: yes}}
+{
+  int num = 1;
+  for (;;)
+num++;
+}
Index: lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -122,6 +122,8 @@
   E = CE.blocks_exhausted_end(); I != E; ++I) {
 const BlockEdge  =  I->first;
 const CFGBlock *Exit = BE.getDst();
+if (Exit->empty())
+  continue;
 const CFGElement  = Exit->front();
 if (Optional CS = CE.getAs()) {
   SmallString<128> bufI;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D41150: [CFG] Adding new CFGStmt LoopEntrance for the StaticAnalyzer

2017-12-21 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 127894.
szepet marked an inline comment as done.
szepet added a comment.

Comment added to LoopEntrance CFGElement.


https://reviews.llvm.org/D41150

Files:
  include/clang/Analysis/CFG.h
  lib/Analysis/CFG.cpp
  lib/StaticAnalyzer/Core/PathDiagnostic.cpp
  test/Analysis/loopexit-cfg-output.cpp

Index: test/Analysis/loopexit-cfg-output.cpp
===
--- test/Analysis/loopexit-cfg-output.cpp
+++ test/Analysis/loopexit-cfg-output.cpp
@@ -34,6 +34,7 @@
 // CHECK:   [B5]
 // CHECK-NEXT:   1: 0
 // CHECK-NEXT:   2: int i = 0;
+// CHECK-NEXT:   3: ForStmt (LoopEntrance)
 // CHECK-NEXT:   Preds (1): B6
 // CHECK-NEXT:   Succs (1): B4
 
@@ -46,8 +47,8 @@
   return;
 }
 
-// CHECK:   [B4 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B3
+// CHECK:   [B5 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B4
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: ForStmt (LoopExit)
@@ -62,15 +63,20 @@
 // CHECK-NEXT:   Preds (2): B2 B4
 // CHECK-NEXT:   Succs (2): B2 NULL
 
+// CHECK:   [B4]
+// CHECK-NEXT:   1: ForStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B5
+// CHECK-NEXT:   Succs (1): B3
+
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
 void check_forloop2() {
   for (;;)
 ;
 }
 
-// CHECK:   [B5 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B4
+// CHECK:   [B6 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B5
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: WhileStmt (LoopExit)
@@ -91,6 +97,11 @@
 // CHECK-NEXT:   Preds (2): B2 B5
 // CHECK-NEXT:   Succs (2): B3 NULL
 
+// CHECK:   [B5]
+// CHECK-NEXT:   1: WhileStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B4
+
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
 void check_while1() {
@@ -125,6 +136,7 @@
 
 // CHECK:   [B4]
 // CHECK-NEXT:   1: int l;
+// CHECK-NEXT:   2: WhileStmt (LoopEntrance)
 // CHECK-NEXT:   Preds (1): B5
 // CHECK-NEXT:   Succs (1): B3
 
@@ -138,8 +150,8 @@
   return;
 }
 
-// CHECK:   [B4 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B3
+// CHECK:   [B5 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B4
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: WhileStmt (LoopExit)
@@ -155,16 +167,21 @@
 // CHECK-NEXT:   Preds (2): B2 B4
 // CHECK-NEXT:   Succs (2): NULL B1
 
+// CHECK:   [B4]
+// CHECK-NEXT:   1: WhileStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B5
+// CHECK-NEXT:   Succs (1): B3
+
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
 void check_while3() {
   while (false) {
 ;
   }
 }
 
-// CHECK:   [B4 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B2
+// CHECK:   [B5 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B4
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: DoStmt (LoopExit)
@@ -180,6 +197,11 @@
 // CHECK:   [B3]
 // CHECK-NEXT:   Succs (1): B2
 
+// CHECK:   [B4]
+// CHECK-NEXT:   1: DoStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B5
+// CHECK-NEXT:   Succs (1): B2
+
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
 void check_dowhile1() {
@@ -221,6 +243,7 @@
 // CHECK:   [B5]
 // CHECK-NEXT:   1: 2
 // CHECK-NEXT:   2: int j = 2;
+// CHECK-NEXT:   3: DoStmt (LoopEntrance)
 // CHECK-NEXT:   Preds (1): B6
 // CHECK-NEXT:   Succs (1): B3
 
@@ -276,6 +299,7 @@
 // CHECK:   [B7]
 // CHECK-NEXT:   1: 1
 // CHECK-NEXT:   2: int j = 1;
+// CHECK-NEXT:   3: ForStmt (LoopEntrance)
 // CHECK-NEXT:   Preds (1): B8
 // CHECK-NEXT:   Succs (1): B6
 
@@ -292,6 +316,7 @@
 // CHECK-NEXT:   1: 40
 // CHECK-NEXT:   2: -[B9.1]
 // CHECK-NEXT:   3: int i = -40;
+// CHECK-NEXT:   4: WhileStmt (LoopEntrance)
 // CHECK-NEXT:   Preds (1): B10
 // CHECK-NEXT:   Succs (1): B8
 
@@ -305,19 +330,19 @@
   }
 }
 
-// CHECK:   [B9 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B8
+// CHECK:   [B10 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B9
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: ForStmt (LoopExit)
-// CHECK-NEXT:   Preds (1): B7
+// CHECK-NEXT:   Preds (1): B8
 // CHECK-NEXT:   Succs (1): B0
 
 // CHECK:   [B2]
 // CHECK-NEXT:   1: j
 // CHECK-NEXT:   2: [B2.1]++
 // CHECK-NEXT:   Preds (1): B3
-// CHECK-NEXT:   Succs (1): B7
+// CHECK-NEXT:   Succs (1): B8
 
 // CHECK:   [B3]
 // CHECK-NEXT:   1: DoStmt (LoopExit)
@@ -346,22 +371,28 @@
 // CHECK-NEXT:   Succs (1): B5
 
 // CHECK:   [B7]
+// CHECK-NEXT:   1: DoStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B8
+// CHECK-NEXT:   Succs (1): B5
+
+// CHECK:   [B8]
 // CHECK-NEXT:   1: j
-// CHECK-NEXT:   2: [B7.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   2: [B8.1] (ImplicitCastExpr, LValueToRValue, int)
 // CHECK-NEXT:   3: 6
-// CHECK-NEXT:   4: [B7.2] < [B7.3]
-// CHECK-NEXT:   T: for (...; [B7.4]; ...)
-// CHECK-NEXT:   Preds (2): B2 B8
-// CHECK-NEXT:   Succs (2): B5 B1
+// CHECK-NEXT:   4: [B8.2] < [B8.3]
+// CHECK-NEXT:   T: for (...; [B8.4]; ...)
+// CHECK-NEXT:   Preds (2): B2 B9
+// CHECK-NEXT:   Succs (2): B7 B1
 
-// CHECK:   [B8]
+// CHECK:   [B9]
 // CHECK-NEXT:   1: 40
-// 

[PATCH] D41444: [ASTImporterTest] Make testing under '-fdelayed-template-parsing' mandatory

2017-12-21 Thread Peter Szecsi via Phabricator via cfe-commits
szepet accepted this revision.
szepet added a comment.

In https://reviews.llvm.org/D41444#961110, @a.sidorin wrote:

> Test both with and without '-fdelayed-template-parsing' in C++ mode.


This solution LGTM as well. 
Just a small nit added inline.




Comment at: unittests/AST/ASTImporterTest.cpp:68
+   const std::string , const std::string ,
+   MatchVerifier , const MatcherType ) {
   const char *const InputFileName = "input.cc";

Nit: Maybe the order of the parameters could stay similar as the original: 
FromCode, FromArgs, ToCode, ToArgs, Verifier, AMatcher. (Or just Codes before 
Args)

It seems more intuitive to me.


Repository:
  rC Clang

https://reviews.llvm.org/D41444



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


[PATCH] D41077: [analyser] different.CallArgsOrder checker implementation

2017-12-18 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added subscribers: alexfh, szepet.
szepet requested changes to this revision.
szepet edited reviewers, added: xazax.hun, szepet; removed: dergachev.a.
szepet added a comment.
Herald added a subscriber: rnkovacs.

Hi Alexey!

Thank you for working on this!

Some general comments on the patch:

1. Please upload the changes with the context included (git flag -U9) which 
could help the review process.
2. Use the LLVM Coding Guidelines on the tests as well (Start variable names 
with a capital letter, etc )
3. Ping here, not necessary on the cfe-dev mailing list ;)
4. FYI: There is a similar check under review which uses only the AST provided 
information and implemented as a tidy-checker: https://reviews.llvm.org/D20689 
(As I see your checker does not uses symbolic execution provided features. So, 
it would probably worth thinking about if the analyzer is the project where the 
checker should be implemented. However, @dcoughlin and @alexfh have more 
insight on the answer to this question. What do you think? )
5. In overall, please add comments to the function which describes its purpose. 
Mainly on heuristic functions, it can help to understand it more easily. Also, 
could you provide some results of the current heuristics, what are the false 
positive rates on real projects like LLVM, FFmpeg, etc? I am quite interested 
in that.

Some comments added inline but they are basically the above mentioned things.




Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:57
+
+bool isNamedLike(StringRef Name) const {
+  if (SimplifiedName.size() < Name.size()) {

It looks like that [[ https://en.wikipedia.org/wiki/Levenshtein_distance | 
Levenshtein ]] edit distance could come handy in cases like this. It is already 
implemented as a method `edit_distance` on StringRef.



Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:164
+
+StringRefVec ParamsGroup::rtrimSame(StringRefVec StrVec) {
+  if (StrVec.empty())

Please add a comment to this function which describes its input, output, 
purpose.



Comment at: test/Analysis/call-args-order.c:4
+struct Viewport {
+  int width;
+  int height;

Please use capital starting letter on variables. On the other test file as well.


Repository:
  rC Clang

https://reviews.llvm.org/D41077



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


[PATCH] D41151: [analyzer] Adding LoopContext and improve loop modeling

2017-12-12 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.
szepet added reviewers: dcoughlin, NoQ, zaks.anna, xazax.hun, a.sidorin.
Herald added subscribers: dkrupp, baloghadamsoftware, whisperity.

Based on the CFGLoopEntrance element, it is possible to have a CFG driven 
LocationContext update which contains loop information as well.
Updated the loop unrolling feature as well to use purely the LocationContext 
stack and not implement its own.


https://reviews.llvm.org/D41151

Files:
  include/clang/Analysis/AnalysisDeclContext.h
  include/clang/Analysis/ProgramPoint.h
  include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
  lib/Analysis/AnalysisDeclContext.cpp
  lib/StaticAnalyzer/Core/CoreEngine.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  test/Analysis/loop-unrolling.cpp

Index: test/Analysis/loop-unrolling.cpp
===
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -373,7 +373,6 @@
   return 0;
 }
 
-
 void pr34943() {
   for (int i = 0; i < 6L; ++i) {
 clang_analyzer_numTimesReached(); // expected-warning {{6}}
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -13,11 +13,11 @@
 ///
 //===--===//
 
-#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
 
 using namespace clang;
 using namespace ento;
@@ -28,56 +28,36 @@
 struct LoopState {
 private:
   enum Kind { Normal, Unrolled } K;
-  const Stmt *LoopStmt;
-  const LocationContext *LCtx;
-  unsigned maxStep;
-  LoopState(Kind InK, const Stmt *S, const LocationContext *L, unsigned N)
-  : K(InK), LoopStmt(S), LCtx(L), maxStep(N) {}
+  unsigned MaxStep;
+  LoopState(Kind InK, unsigned N) : K(InK), MaxStep(N) {}
 
 public:
-  static LoopState getNormal(const Stmt *S, const LocationContext *L,
- unsigned N) {
-return LoopState(Normal, S, L, N);
-  }
-  static LoopState getUnrolled(const Stmt *S, const LocationContext *L,
-   unsigned N) {
-return LoopState(Unrolled, S, L, N);
-  }
+  static LoopState getNormal(unsigned N) { return LoopState(Normal, N); }
+  static LoopState getUnrolled(unsigned N) { return LoopState(Unrolled, N); }
   bool isUnrolled() const { return K == Unrolled; }
-  unsigned getMaxStep() const { return maxStep; }
-  const Stmt *getLoopStmt() const { return LoopStmt; }
-  const LocationContext *getLocationContext() const { return LCtx; }
+  unsigned getMaxStep() const { return MaxStep; }
   bool operator==(const LoopState ) const {
-return K == X.K && LoopStmt == X.LoopStmt;
+return K == X.K && MaxStep == X.MaxStep;
   }
   void Profile(llvm::FoldingSetNodeID ) const {
 ID.AddInteger(K);
-ID.AddPointer(LoopStmt);
-ID.AddPointer(LCtx);
-ID.AddInteger(maxStep);
+ID.AddInteger(MaxStep);
   }
 };
 
-// The tracked stack of loops. The stack indicates that which loops the
-// simulated element contained by. The loops are marked depending if we decided
-// to unroll them.
-// TODO: The loop stack should not need to be in the program state since it is
-// lexical in nature. Instead, the stack of loops should be tracked in the
-// LocationContext.
-REGISTER_LIST_WITH_PROGRAMSTATE(LoopStack, LoopState)
+// The map of the currently simulated loops which are marked depending if we
+// decided to unroll them.
+REGISTER_MAP_WITH_PROGRAMSTATE(LoopMap, const LoopContext *, LoopState)
 
 namespace clang {
 namespace ento {
 
 static bool isLoopStmt(const Stmt *S) {
   return S && (isa(S) || isa(S) || isa(S));
 }
 
-ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State) {
-  auto LS = State->get();
-  if (!LS.isEmpty() && LS.getHead().getLoopStmt() == LoopStmt)
-State = State->set(LS.getTail());
-  return State;
+ProgramStateRef processLoopEnd(const LoopContext *LC, ProgramStateRef State) {
+  return State->remove(LC);
 }
 
 static internal::Matcher simpleCondition(StringRef BindName) {
@@ -157,7 +137,8 @@
  hasUnaryOperand(declRefExpr(
  to(varDecl(allOf(equalsBoundNode("initVarName"),
   hasType(isInteger(),
- unless(hasBody(hasSuspiciousStmt("initVarName".bind("forLoop");
+ 

[PATCH] D41150: [CFG] Adding new CFGStmt LoopEntrance for the StaticAnalyzer

2017-12-12 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.
szepet added reviewers: dcoughlin, zaks.anna, NoQ, rsmith.
Herald added subscribers: dkrupp, a.sidorin, baloghadamsoftware, whisperity.

Adding LoopEntrance as a new CFGElement to the CFG.
This element is added as the last element of the CFGBlock just before the loop 
condition block.
This can help the Static Analyzer to have a more precise loop modeling.


https://reviews.llvm.org/D41150

Files:
  include/clang/Analysis/CFG.h
  lib/Analysis/CFG.cpp
  test/Analysis/loopexit-cfg-output.cpp

Index: test/Analysis/loopexit-cfg-output.cpp
===
--- test/Analysis/loopexit-cfg-output.cpp
+++ test/Analysis/loopexit-cfg-output.cpp
@@ -34,6 +34,7 @@
 // CHECK:   [B5]
 // CHECK-NEXT:   1: 0
 // CHECK-NEXT:   2: int i = 0;
+// CHECK-NEXT:   3: ForStmt (LoopEntrance)
 // CHECK-NEXT:   Preds (1): B6
 // CHECK-NEXT:   Succs (1): B4
 
@@ -46,8 +47,8 @@
   return;
 }
 
-// CHECK:   [B4 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B3
+// CHECK:   [B5 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B4
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: ForStmt (LoopExit)
@@ -62,15 +63,20 @@
 // CHECK-NEXT:   Preds (2): B2 B4
 // CHECK-NEXT:   Succs (2): B2 NULL
 
+// CHECK:   [B4]
+// CHECK-NEXT:   1: ForStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B5
+// CHECK-NEXT:   Succs (1): B3
+
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
 void check_forloop2() {
   for (;;)
 ;
 }
 
-// CHECK:   [B5 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B4
+// CHECK:   [B6 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B5
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: WhileStmt (LoopExit)
@@ -91,6 +97,11 @@
 // CHECK-NEXT:   Preds (2): B2 B5
 // CHECK-NEXT:   Succs (2): B3 NULL
 
+// CHECK:   [B5]
+// CHECK-NEXT:   1: WhileStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B4
+
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
 void check_while1() {
@@ -125,6 +136,7 @@
 
 // CHECK:   [B4]
 // CHECK-NEXT:   1: int l;
+// CHECK-NEXT:   2: WhileStmt (LoopEntrance)
 // CHECK-NEXT:   Preds (1): B5
 // CHECK-NEXT:   Succs (1): B3
 
@@ -138,8 +150,8 @@
   return;
 }
 
-// CHECK:   [B4 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B3
+// CHECK:   [B5 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B4
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: WhileStmt (LoopExit)
@@ -155,16 +167,21 @@
 // CHECK-NEXT:   Preds (2): B2 B4
 // CHECK-NEXT:   Succs (2): NULL B1
 
+// CHECK:   [B4]
+// CHECK-NEXT:   1: WhileStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B5
+// CHECK-NEXT:   Succs (1): B3
+
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
 void check_while3() {
   while (false) {
 ;
   }
 }
 
-// CHECK:   [B4 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B2
+// CHECK:   [B5 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B4
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: DoStmt (LoopExit)
@@ -180,6 +197,11 @@
 // CHECK:   [B3]
 // CHECK-NEXT:   Succs (1): B2
 
+// CHECK:   [B4]
+// CHECK-NEXT:   1: DoStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B5
+// CHECK-NEXT:   Succs (1): B2
+
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
 void check_dowhile1() {
@@ -221,6 +243,7 @@
 // CHECK:   [B5]
 // CHECK-NEXT:   1: 2
 // CHECK-NEXT:   2: int j = 2;
+// CHECK-NEXT:   3: DoStmt (LoopEntrance)
 // CHECK-NEXT:   Preds (1): B6
 // CHECK-NEXT:   Succs (1): B3
 
@@ -276,6 +299,7 @@
 // CHECK:   [B7]
 // CHECK-NEXT:   1: 1
 // CHECK-NEXT:   2: int j = 1;
+// CHECK-NEXT:   3: ForStmt (LoopEntrance)
 // CHECK-NEXT:   Preds (1): B8
 // CHECK-NEXT:   Succs (1): B6
 
@@ -292,6 +316,7 @@
 // CHECK-NEXT:   1: 40
 // CHECK-NEXT:   2: -[B9.1]
 // CHECK-NEXT:   3: int i = -40;
+// CHECK-NEXT:   4: WhileStmt (LoopEntrance)
 // CHECK-NEXT:   Preds (1): B10
 // CHECK-NEXT:   Succs (1): B8
 
@@ -305,19 +330,19 @@
   }
 }
 
-// CHECK:   [B9 (ENTRY)]
-// CHECK-NEXT:   Succs (1): B8
+// CHECK:   [B10 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B9
 
 // CHECK:   [B1]
 // CHECK-NEXT:   1: ForStmt (LoopExit)
-// CHECK-NEXT:   Preds (1): B7
+// CHECK-NEXT:   Preds (1): B8
 // CHECK-NEXT:   Succs (1): B0
 
 // CHECK:   [B2]
 // CHECK-NEXT:   1: j
 // CHECK-NEXT:   2: [B2.1]++
 // CHECK-NEXT:   Preds (1): B3
-// CHECK-NEXT:   Succs (1): B7
+// CHECK-NEXT:   Succs (1): B8
 
 // CHECK:   [B3]
 // CHECK-NEXT:   1: DoStmt (LoopExit)
@@ -346,22 +371,28 @@
 // CHECK-NEXT:   Succs (1): B5
 
 // CHECK:   [B7]
+// CHECK-NEXT:   1: DoStmt (LoopEntrance)
+// CHECK-NEXT:   Preds (1): B8
+// CHECK-NEXT:   Succs (1): B5
+
+// CHECK:   [B8]
 // CHECK-NEXT:   1: j
-// CHECK-NEXT:   2: [B7.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   2: [B8.1] (ImplicitCastExpr, LValueToRValue, int)
 // CHECK-NEXT:   3: 6
-// CHECK-NEXT:   4: [B7.2] < [B7.3]
-// CHECK-NEXT:   T: for (...; [B7.4]; ...)
-// CHECK-NEXT:   Preds (2): B2 B8
-// CHECK-NEXT:   Succs (2): B5 B1
+// CHECK-NEXT:   4: [B8.2] < [B8.3]
+// 

[PATCH] D40937: [clang-tidy] Infinite loop checker

2017-12-07 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

In https://reviews.llvm.org/D40937#947760, @JVApen wrote:

> How does this check deal with atomic members?
>  ...


This patch only works on integer types. So, since the atomic is a non-supported 
type the check will skip that `while` loop.


https://reviews.llvm.org/D40937



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


[PATCH] D40937: [clang-tidy] Infinite loop checker

2017-12-07 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 125965.
szepet marked 9 inline comments as done.
szepet added a comment.

Updates based on comments.


https://reviews.llvm.org/D40937

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/InfiniteLoopCheck.cpp
  clang-tidy/misc/InfiniteLoopCheck.h
  clang-tidy/misc/MiscTidyModule.cpp
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-infinite-loop.rst
  test/clang-tidy/misc-infinite-loop.cpp

Index: test/clang-tidy/misc-infinite-loop.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-infinite-loop.cpp
@@ -0,0 +1,114 @@
+// RUN: %check_clang_tidy %s misc-infinite-loop %t
+
+void simple_infinite_loop1() {
+  int i = 0;
+  int j = 0;
+  while (i < 10) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body [misc-infinite-loop]
+j++;
+  }
+
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body
+j++;
+  } while (i < 10);
+
+  for (i = 0; i < 10; ++j) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body
+  }
+}
+
+void simple_infinite_loop2() {
+  int i = 0;
+  int j = 0;
+  int Limit = 10;
+  while (i < Limit) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body [misc-infinite-loop]
+j++;
+  }
+
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+j++;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; ++j) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+  }
+}
+
+void simple_not_infinite() {
+  int i = 0;
+  int Limit = 100;
+  while (i < Limit) { // Not an error since 'Limit' is updated
+Limit--;
+  }
+  do {
+Limit--;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; Limit--) {
+  }
+}
+
+void escape_before1() {
+  int i = 0;
+  int Limit = 100;
+  int *p = 
+  while (i < Limit) { // Not an error, since p is alias of i.
+*++p;
+  }
+
+  do {
+*++p;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; *++p) {
+  }
+}
+
+void escape_before2() {
+  int i = 0;
+  int Limit = 100;
+  int *p = 
+  while (i < Limit) { // We do not warn since the var 'i' is escaped but it is
+  // an actual error, since the pointer 'p' is increased.
+*(p++);
+  }
+}
+
+void escape_after() {
+  int i = 0;
+  int j = 0;
+  int Limit = 10;
+
+  while (i < Limit) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+  }
+  int *p = 
+}
+
+int glob;
+void glob_var(int ) {
+  int i = 0;
+  int Limit = 100;
+  while (x < Limit) { // Not an error since 'x' can be an alias of glob.
+glob++;
+  }
+}
+
+void glob_var2() {
+  int i = 0, Limit = 100;
+  while (glob < Limit) { // Since 'glob' is declared out of the function we do not warn.
+i++;
+  }
+}
+
+bool foo(int n);
+void fun_call() {
+  int i = 0;
+  int Limit = 100;
+  while (foo(i)) { // Do not warn, since foo can have state.
+Limit--;
+  }
+}
Index: docs/clang-tidy/checks/misc-infinite-loop.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-infinite-loop.rst
@@ -0,0 +1,30 @@
+.. title:: clang-tidy - misc-infinite-loop
+
+misc-infinite-loop
+==
+
+The check finds loops where none of the condition variables are updated in the
+body. This performs a very conservative check in order to avoid false positives
+and work only on integer types at the moment.
+
+Examples:
+
+.. code-block:: c++
+
+  void simple_infinite_loop() {
+int i = 0;
+int j = 0;
+int Limit = 10;
+while (i < Limit) { // Error, since none of the variables are updated.
+  j++;
+}
+  }
+
+  void escape_before() {
+int i = 0;
+int Limit = 100;
+int *p = 
+while (i < Limit) { // Not an error, since p is alias of i.
+  *++p;
+}
+  }
Index: docs/clang-tidy/checks/list.rst
===
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -120,6 +120,7 @@
misc-definitions-in-headers
misc-forwarding-reference-overload
misc-incorrect-roundings
+   misc-infinite-loop
misc-lambda-function-name
misc-macro-parentheses
misc-macro-repeated-side-effects
Index: docs/ReleaseNotes.rst
===
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -158,6 +158,11 @@
   Finds uses of bitwise operations on signed integer types, which may lead to 
   undefined or implementation defined behaviour.
 
+- New `misc-infinite-loop
+  

[PATCH] D40937: [clang-tidy] Infinite loop checker

2017-12-06 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

Hi Eugen!
Good question, probably should have detailed it in the description.
This matcher based solution would not gain much benefit from the symbolic 
execution provided information. (I mean, it would mean a much different type of 
check on the states.) 
The main problems that the analyzer does not completely unroll the loops only 
the first steps and we always have information about the simulated path. 
However, detecting that some variables will surely not be modified requires a 
top level overview on the loop and the AST provides these informations. The one 
thing (that I can say right now) that can come handy is that we would able to 
detect more precisely the happened-before relation on the escape and the loop 
statements. Since the CFG can provide us fair enough information on this one, I 
do not think that this is enough reason to put this checker to the analyzer.

Other note: If somebody would came up with an approach which can benefit from 
the symbolic execution, these solutions could still live happily in the 
different tools eg. UseAfterMove (tidy) and MisusedMovedObjectChecker 
(analyzer).


https://reviews.llvm.org/D40937



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


[PATCH] D40937: [clang-tidy] Infinite loop checker

2017-12-06 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 125870.
szepet marked an inline comment as done.
szepet added a comment.

Updated the wording in the docs.


https://reviews.llvm.org/D40937

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/InfiniteLoopCheck.cpp
  clang-tidy/misc/InfiniteLoopCheck.h
  clang-tidy/misc/MiscTidyModule.cpp
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-infinite-loop.rst
  test/clang-tidy/misc-infinite-loop.cpp

Index: test/clang-tidy/misc-infinite-loop.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-infinite-loop.cpp
@@ -0,0 +1,104 @@
+// RUN: %check_clang_tidy %s misc-infinite-loop %t
+
+void simple_infinite_loop1() {
+  int i = 0;
+  int j = 0;
+  while (i < 10) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body [misc-infinite-loop]
+j++;
+  }
+
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body
+j++;
+  } while (i < 10);
+
+  for (i = 0; i < 10; ++j) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body
+  }
+}
+
+void simple_infinite_loop2() {
+  int i = 0;
+  int j = 0;
+  int Limit = 10;
+  while (i < Limit) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body [misc-infinite-loop]
+j++;
+  }
+
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+j++;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; ++j) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+  }
+}
+
+void simple_not_infinite() {
+  int i = 0;
+  int Limit = 100;
+  while (i < Limit) { // Not an error since 'Limit' is updated
+Limit--;
+  }
+  do {
+Limit--;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit;Limit--) {
+  }
+}
+
+void escape_before1() {
+  int i = 0;
+  int Limit = 100;
+  int *p = 
+  while (i < Limit) { // Not an error, since p is alias of i.
+*++p;
+  }
+
+  do {
+*++p;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; *++p) {
+  }
+}
+
+void escape_before2() {
+  int i = 0;
+  int Limit = 100;
+  int *p = 
+  while (i < Limit) { // We do not warn since the var 'i' is escaped but it is
+  // an actual error, since the pointer 'p' is increased.
+*(p++);
+  }
+}
+
+void escape_after() {
+  int i = 0;
+  int j = 0;
+  int Limit = 10;
+
+  while (i < Limit) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+  }
+  int *p = 
+}
+
+int glob;
+void glob_var(int ) {
+  int i = 0, Limit = 100;
+  while (x < Limit) { // Not an error since 'x' can be an alias of glob.
+glob++;
+  }
+}
+
+void glob_var2() {
+  int i = 0, Limit = 100;
+  while (glob < Limit) { // Since 'glob' is declared out of the function we do not warn.
+i++;
+  }
+}
Index: docs/clang-tidy/checks/misc-infinite-loop.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-infinite-loop.rst
@@ -0,0 +1,30 @@
+.. title:: clang-tidy - misc-infinite-loop
+
+misc-infinite-loop
+==
+
+The check finds loops where none of the condition variables are updated in the
+body. This performs a very conservative check in order to avoid false positives
+and work only on integer types at the moment.
+
+Examples:
+
+.. code-block:: c++
+
+  void simple_infinite_loop() {
+int i = 0;
+int j = 0;
+int Limit = 10;
+while (i < Limit) { // Error, since none of the variables are updated.
+  j++;
+}
+  }
+
+  void escape_before() {
+int i = 0;
+int Limit = 100;
+int *p = 
+while (i < Limit) { // Not an error, since p is alias of i.
+  *++p;
+}
+  }
Index: docs/clang-tidy/checks/list.rst
===
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -119,6 +119,7 @@
misc-definitions-in-headers
misc-forwarding-reference-overload
misc-incorrect-roundings
+   misc-infinite-loop
misc-lambda-function-name
misc-macro-parentheses
misc-macro-repeated-side-effects
Index: docs/ReleaseNotes.rst
===
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -57,6 +57,12 @@
 Improvements to clang-tidy
 --
 
+- New `misc-infinite-loop
+  `_ check
+
+  The check finds loops where none of the condition variables are updated in the
+  body.
+
 - The 'misc-move-constructor-init' check was renamed to `performance-move-constructor-init
   

[PATCH] D40937: [clang-tidy] Infinite loop checker

2017-12-06 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.
Herald added subscribers: rnkovacs, baloghadamsoftware, whisperity, mgorny.

The checker aims to find loops where none of the condition variables are 
updated in the body. 
In this version it only works on integer types but the final aim is to make it 
work for objects as well. (via checking non-const method calls, etc)

Note: this kind of check is supported by clang warning as well 
(-Wfor-loop-analysis), however, it only works on for-loops and not investigate 
escape statements (modification via alias generates false positives e.g.  
`escape_before1()` test case).

Any suggestions on the checker are welcome!


https://reviews.llvm.org/D40937

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/InfiniteLoopCheck.cpp
  clang-tidy/misc/InfiniteLoopCheck.h
  clang-tidy/misc/MiscTidyModule.cpp
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-infinite-loop.rst
  test/clang-tidy/misc-infinite-loop.cpp

Index: test/clang-tidy/misc-infinite-loop.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-infinite-loop.cpp
@@ -0,0 +1,104 @@
+// RUN: %check_clang_tidy %s misc-infinite-loop %t
+
+void simple_infinite_loop1() {
+  int i = 0;
+  int j = 0;
+  while (i < 10) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body [misc-infinite-loop]
+j++;
+  }
+
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body
+j++;
+  } while (i < 10);
+
+  for (i = 0; i < 10; ++j) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: The condition variable (i) is not updated in the loop body
+  }
+}
+
+void simple_infinite_loop2() {
+  int i = 0;
+  int j = 0;
+  int Limit = 10;
+  while (i < Limit) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body [misc-infinite-loop]
+j++;
+  }
+
+  do {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+j++;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; ++j) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+  }
+}
+
+void simple_not_infinite() {
+  int i = 0;
+  int Limit = 100;
+  while (i < Limit) { // Not an error since 'Limit' is updated
+Limit--;
+  }
+  do {
+Limit--;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit;Limit--) {
+  }
+}
+
+void escape_before1() {
+  int i = 0;
+  int Limit = 100;
+  int *p = 
+  while (i < Limit) { // Not an error, since p is alias of i.
+*++p;
+  }
+
+  do {
+*++p;
+  } while (i < Limit);
+
+  for (i = 0; i < Limit; *++p) {
+  }
+}
+
+void escape_before2() {
+  int i = 0;
+  int Limit = 100;
+  int *p = 
+  while (i < Limit) { // We do not warn since the var 'i' is escaped but it is
+  // an actual error, since the pointer 'p' is increased.
+*(p++);
+  }
+}
+
+void escape_after() {
+  int i = 0;
+  int j = 0;
+  int Limit = 10;
+
+  while (i < Limit) {
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: None of the condition variables (i, Limit) are updated in the loop body
+  }
+  int *p = 
+}
+
+int glob;
+void glob_var(int ) {
+  int i = 0, Limit = 100;
+  while (x < Limit) { // Not an error since 'x' can be an alias of glob.
+glob++;
+  }
+}
+
+void glob_var2() {
+  int i = 0, Limit = 100;
+  while (glob < Limit) { // Since 'glob' is declared out of the function we do not warn.
+i++;
+  }
+}
Index: docs/clang-tidy/checks/misc-infinite-loop.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-infinite-loop.rst
@@ -0,0 +1,31 @@
+.. title:: clang-tidy - misc-infinite-loop
+
+misc-infinite-loop
+==
+
+The checker aims to find loops where none of the condition variables are
+updated in the body. This performs a very conservative check in order to
+avoid false positives and work only on integer types at the moment.
+
+Examples:
+
+.. code-block:: c++
+
+  void simple_infinite_loop() {
+int i = 0;
+int j = 0;
+int Limit = 10;
+while (i < Limit) { // Error, since none of the variables are updated.
+  j++;
+}
+  }
+
+  void escape_before() {
+int i = 0;
+int Limit = 100;
+int *p = 
+while (i < Limit) { // Not an error, since p is alias of i.
+  *++p;
+}
+  }
+  
\ No newline at end of file
Index: docs/clang-tidy/checks/list.rst
===
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -119,6 +119,7 @@
misc-definitions-in-headers
misc-forwarding-reference-overload
misc-incorrect-roundings
+   misc-infinite-loop
misc-lambda-function-name
misc-macro-parentheses
misc-macro-repeated-side-effects
Index: 

[PATCH] D38921: [analyzer] LoopUnrolling: update the matched assignment operators

2017-12-01 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added reviewers: alexfh, aaron.ballman.
szepet added a comment.

Added Alexander and Aaron as reviewers for the matcher parts.


https://reviews.llvm.org/D38921



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


[PATCH] D38845: [ASTImporter] Support importing UnresolvedMemberExpr, DependentNameType, DependentScopeDeclRefExpr

2017-11-29 Thread Peter Szecsi via Phabricator via cfe-commits
szepet marked an inline comment as done.
szepet added inline comments.



Comment at: unittests/AST/ASTImporterTest.cpp:611
+  EXPECT_TRUE(testImport("template  struct S;"
+ "template  void declToImport() {"
+ "  S::foo;"

a.sidorin wrote:
> Uninstantiated templates make me worry about Windows buildbots. If they will 
> start to fail, we should test these matchers with `-fms-compatibility` and 
> `-fdelayed-template-parsing` options enabled.
Not sure about Windows but I can ensure that this test has passed with these 
args added as well.


https://reviews.llvm.org/D38845



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


[PATCH] D38843: [ASTImporter] Support importing CXXPseudoDestructorExpr

2017-11-24 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 124173.
szepet marked 3 inline comments as done.
szepet added a comment.
Herald added a subscriber: rnkovacs.

Thank you for the review!

Updated according to review comments.


https://reviews.llvm.org/D38843

Files:
  lib/AST/ASTImporter.cpp
  unittests/AST/ASTImporterTest.cpp


Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -589,5 +589,21 @@
  binaryOperator(has(cxxUnresolvedConstructExpr()));
 }
 
+const internal::VariadicDynCastAllOfMatcher
+cxxPseudoDestructorExpr;
+
+TEST(ImportExpr, ImportCXXPseudoDestructorExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(
+  testImport("typedef int T;"
+ "void declToImport(int *p) {"
+ "  T t;"
+ "  p->T::~T();"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(has(compoundStmt(has(
+ callExpr(has(cxxPseudoDestructorExpr();
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -292,6 +292,7 @@
 Expr *VisitExprWithCleanups(ExprWithCleanups *EWC);
 Expr *VisitCXXThisExpr(CXXThisExpr *E);
 Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
+Expr *VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
 Expr *VisitMemberExpr(MemberExpr *E);
 Expr *VisitCallExpr(CallExpr *E);
 Expr *VisitInitListExpr(InitListExpr *E);
@@ -5910,6 +5911,39 @@
   E->isOverloaded(), ToDecls.begin(), ToDecls.end());
 }
 
+Expr *ASTNodeImporter::VisitCXXPseudoDestructorExpr(
+CXXPseudoDestructorExpr *E) {
+
+  Expr *BaseE = Importer.Import(E->getBase());
+  if (!BaseE)
+return nullptr;
+
+  TypeSourceInfo *ScopeInfo = Importer.Import(E->getScopeTypeInfo());
+  if (!ScopeInfo && E->getScopeTypeInfo())
+return nullptr;
+
+  PseudoDestructorTypeStorage Storage;
+  if (IdentifierInfo *FromII = E->getDestroyedTypeIdentifier()) {
+IdentifierInfo *ToII = Importer.Import(FromII);
+if (!ToII)
+  return nullptr;
+Storage = PseudoDestructorTypeStorage(
+  ToII, Importer.Import(E->getDestroyedTypeLoc()));
+  } else {
+TypeSourceInfo *TI = Importer.Import(E->getDestroyedTypeInfo());
+if (!TI)
+  return nullptr;
+Storage = PseudoDestructorTypeStorage(TI);
+  }
+
+  return new (Importer.getToContext()) CXXPseudoDestructorExpr(
+Importer.getToContext(), BaseE, E->isArrow(),
+Importer.Import(E->getOperatorLoc()),
+Importer.Import(E->getQualifierLoc()),
+ScopeInfo, Importer.Import(E->getColonColonLoc()),
+Importer.Import(E->getTildeLoc()), Storage);
+}
+
 Expr *ASTNodeImporter::VisitCallExpr(CallExpr *E) {
   QualType T = Importer.Import(E->getType());
   if (T.isNull())


Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -589,5 +589,21 @@
  binaryOperator(has(cxxUnresolvedConstructExpr()));
 }
 
+const internal::VariadicDynCastAllOfMatcher
+cxxPseudoDestructorExpr;
+
+TEST(ImportExpr, ImportCXXPseudoDestructorExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(
+  testImport("typedef int T;"
+ "void declToImport(int *p) {"
+ "  T t;"
+ "  p->T::~T();"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(has(compoundStmt(has(
+ callExpr(has(cxxPseudoDestructorExpr();
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -292,6 +292,7 @@
 Expr *VisitExprWithCleanups(ExprWithCleanups *EWC);
 Expr *VisitCXXThisExpr(CXXThisExpr *E);
 Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
+Expr *VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
 Expr *VisitMemberExpr(MemberExpr *E);
 Expr *VisitCallExpr(CallExpr *E);
 Expr *VisitInitListExpr(InitListExpr *E);
@@ -5910,6 +5911,39 @@
   E->isOverloaded(), ToDecls.begin(), ToDecls.end());
 }
 
+Expr *ASTNodeImporter::VisitCXXPseudoDestructorExpr(
+CXXPseudoDestructorExpr *E) {
+
+  Expr *BaseE = Importer.Import(E->getBase());
+  if (!BaseE)
+return nullptr;
+
+  TypeSourceInfo *ScopeInfo = Importer.Import(E->getScopeTypeInfo());
+  if (!ScopeInfo && E->getScopeTypeInfo())
+return nullptr;
+
+  PseudoDestructorTypeStorage Storage;
+  if (IdentifierInfo *FromII = 

[PATCH] D38694: [ASTImporter] Support importing CXXUnresolvedConstructExpr and UnresolvedLookupExpr

2017-11-23 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 124123.
szepet added a comment.

Updating the usage of `ImportTemplateArgumentListInfo`.


https://reviews.llvm.org/D38694

Files:
  lib/AST/ASTImporter.cpp
  unittests/AST/ASTImporterTest.cpp

Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -555,5 +555,39 @@
  has(cxxDependentScopeMemberExpr();
 }
 
+TEST(ImportExpr, ImportUnresolvedLookupExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(testImport("template int foo();"
+ "template  void declToImport() {"
+ "  ::foo;"
+ "  ::template foo;"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(
+ compoundStmt(has(unresolvedLookupExpr();
+}
+
+TEST(ImportExpr, ImportCXXUnresolvedConstructExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(
+  testImport("template  class C { T t; };"
+ "template  void declToImport() {"
+ "  C d;"
+ "  d.t = T();"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(has(
+ binaryOperator(has(cxxUnresolvedConstructExpr()));
+  EXPECT_TRUE(
+  testImport("template  class C { T t; };"
+ "template  void declToImport() {"
+ "  C d;"
+ "  ()->t = T();"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(has(
+ binaryOperator(has(cxxUnresolvedConstructExpr()));
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -287,6 +287,8 @@
 Expr *VisitCXXConstructExpr(CXXConstructExpr *E);
 Expr *VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
 Expr *VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
+Expr *VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *CE);
+Expr *VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E);
 Expr *VisitExprWithCleanups(ExprWithCleanups *EWC);
 Expr *VisitCXXThisExpr(CXXThisExpr *E);
 Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
@@ -5850,6 +5852,64 @@
   cast_or_null(ToFQ), MemberNameInfo, ResInfo);
 }
 
+Expr *ASTNodeImporter::VisitCXXUnresolvedConstructExpr(
+CXXUnresolvedConstructExpr *CE) {
+
+  unsigned NumArgs = CE->arg_size();
+
+  llvm::SmallVector ToArgs(NumArgs);
+  if (ImportArrayChecked(CE->arg_begin(), CE->arg_end(), ToArgs.begin()))
+return nullptr;
+
+  return CXXUnresolvedConstructExpr::Create(
+  Importer.getToContext(), Importer.Import(CE->getTypeSourceInfo()),
+  Importer.Import(CE->getLParenLoc()), llvm::makeArrayRef(ToArgs),
+  Importer.Import(CE->getRParenLoc()));
+}
+
+Expr *ASTNodeImporter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
+  CXXRecordDecl *NamingClass =
+  cast_or_null(Importer.Import(E->getNamingClass()));
+  if (E->getNamingClass() && !NamingClass)
+return nullptr;
+
+  DeclarationName Name = Importer.Import(E->getName());
+  if (E->getName().isEmpty() && Name.isEmpty())
+return nullptr;
+  DeclarationNameInfo NameInfo(Name, Importer.Import(E->getNameLoc()));
+  // Import additional name location/type info.
+  ImportDeclarationNameLoc(E->getNameInfo(), NameInfo);
+
+  UnresolvedSet<8> ToDecls;
+  for (Decl *D : E->decls()) {
+if (NamedDecl *To = cast_or_null(Importer.Import(D)))
+  ToDecls.addDecl(To);
+else
+  return nullptr;
+  }
+
+  TemplateArgumentListInfo ToTAInfo(Importer.Import(E->getLAngleLoc()),
+Importer.Import(E->getRAngleLoc()));
+  TemplateArgumentListInfo *ResInfo = nullptr;
+  if (E->hasExplicitTemplateArgs()) {
+if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo))
+  return nullptr;
+ResInfo = 
+  }
+
+  if (ResInfo || E->getTemplateKeywordLoc().isValid())
+return UnresolvedLookupExpr::Create(
+Importer.getToContext(), NamingClass,
+Importer.Import(E->getQualifierLoc()),
+Importer.Import(E->getTemplateKeywordLoc()), NameInfo, E->requiresADL(),
+ResInfo, ToDecls.begin(), ToDecls.end());
+
+  return UnresolvedLookupExpr::Create(
+  Importer.getToContext(), NamingClass,
+  Importer.Import(E->getQualifierLoc()), NameInfo, E->requiresADL(),
+  E->isOverloaded(), ToDecls.begin(), ToDecls.end());
+}
+
 Expr *ASTNodeImporter::VisitCallExpr(CallExpr *E) {
   QualType T = Importer.Import(E->getType());
   if 

[PATCH] D38845: [ASTImporter] Support importing UnresolvedMemberExpr, DependentNameType, DependentScopeDeclRefExpr

2017-11-23 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 124119.
szepet marked 6 inline comments as done.
szepet added a comment.
Herald added a subscriber: rnkovacs.

Updated based on review comments.

Hello Aleksei,
Thank for the review and the code snippet as well!


https://reviews.llvm.org/D38845

Files:
  lib/AST/ASTImporter.cpp
  unittests/AST/ASTImporterTest.cpp

Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -589,5 +589,68 @@
  binaryOperator(has(cxxUnresolvedConstructExpr()));
 }
 
+const internal::VariadicDynCastAllOfMatcher
+unresolvedMemberExpr;
+TEST(ImportExpr, ImportUnresolvedMemberExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(testImport("struct S { template  void mem(); };"
+ "template  void declToImport() {"
+ "  S s;"
+ "  s.mem();"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(
+ has(callExpr(has(unresolvedMemberExpr()));
+}
+
+const internal::VariadicDynCastAllOfMatcher
+dependentScopeDeclRefExpr;
+TEST(ImportExpr, ImportDependentScopeDeclRefExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(testImport("template  struct S;"
+ "template  void declToImport() {"
+ "  S::foo;"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(
+ has(dependentScopeDeclRefExpr();
+
+  EXPECT_TRUE(testImport("template  struct S;"
+ "template  void declToImport() {"
+ "  S::template foo;"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(
+ has(dependentScopeDeclRefExpr();
+
+  EXPECT_TRUE(testImport("template  struct S;"
+ "template  void declToImport() {"
+ "  S::template foo<>;"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(
+ has(dependentScopeDeclRefExpr();
+
+  EXPECT_TRUE(testImport("template  struct S;"
+ "template  void declToImport() {"
+ "  S::template foo;"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(
+ has(dependentScopeDeclRefExpr();
+}
+
+const internal::VariadicDynCastAllOfMatcher
+dependentNameType;
+TEST(ImportExpr, DependentNameType) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(testImport("template  struct declToImport {"
+ "  typedef typename T::type dependent_name;"
+ "};",
+ Lang_CXX11, "", Lang_CXX11, Verifier,
+ classTemplateDecl(has(cxxRecordDecl(
+ has(typedefDecl(has(dependentNameType();
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -76,7 +76,7 @@
 QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T);
 QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T);
 QualType VisitElaboratedType(const ElaboratedType *T);
-// FIXME: DependentNameType
+QualType VisitDependentNameType(const DependentNameType *T);
 QualType VisitPackExpansionType(const PackExpansionType *T);
 // FIXME: DependentTemplateSpecializationType
 QualType VisitObjCInterfaceType(const ObjCInterfaceType *T);
@@ -287,8 +287,10 @@
 Expr *VisitCXXConstructExpr(CXXConstructExpr *E);
 Expr *VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
 Expr *VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
+Expr *VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E);
 Expr *VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *CE);
 Expr *VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E);
+Expr *VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E);
 Expr *VisitExprWithCleanups(ExprWithCleanups *EWC);
 Expr *VisitCXXThisExpr(CXXThisExpr *E);
 Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
@@ -812,6 

[PATCH] D38694: [ASTImporter] Support importing CXXUnresolvedConstructExpr and UnresolvedLookupExpr

2017-11-23 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

Hello Aleksei,

Thank you for the review! (and sorry for the late update)




Comment at: lib/AST/ASTImporter.cpp:5510
+  UnresolvedSet<8> ToDecls;
+  for (Decl *D : E->decls()) {
+if (NamedDecl *To = cast_or_null(Importer.Import(D)))

a.sidorin wrote:
> ImportContainerChecked
Since the `operator*` is const on `UnresolvedSetIterator` so returns 
`NameDecl*` not `NamedDecl*&` the ImportContainerChecked can not be use here as 
I understand (since the left side of the = operator is not an LVal in this 
case). So we can add elements via the `addDecl` function call.


https://reviews.llvm.org/D38694



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


[PATCH] D38694: [ASTImporter] Support importing CXXUnresolvedConstructExpr and UnresolvedLookupExpr

2017-11-23 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 124115.
szepet marked 7 inline comments as done.
szepet added a comment.
Herald added a subscriber: rnkovacs.

Updates based on review comments.


https://reviews.llvm.org/D38694

Files:
  lib/AST/ASTImporter.cpp
  unittests/AST/ASTImporterTest.cpp

Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -555,5 +555,39 @@
  has(cxxDependentScopeMemberExpr();
 }
 
+TEST(ImportExpr, ImportUnresolvedLookupExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(testImport("template int foo();"
+ "template  void declToImport() {"
+ "  ::foo;"
+ "  ::template foo;"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(
+ compoundStmt(has(unresolvedLookupExpr();
+}
+
+TEST(ImportExpr, ImportCXXUnresolvedConstructExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(
+  testImport("template  class C { T t; };"
+ "template  void declToImport() {"
+ "  C d;"
+ "  d.t = T();"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(has(
+ binaryOperator(has(cxxUnresolvedConstructExpr()));
+  EXPECT_TRUE(
+  testImport("template  class C { T t; };"
+ "template  void declToImport() {"
+ "  C d;"
+ "  ()->t = T();"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(has(
+ binaryOperator(has(cxxUnresolvedConstructExpr()));
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -287,6 +287,8 @@
 Expr *VisitCXXConstructExpr(CXXConstructExpr *E);
 Expr *VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
 Expr *VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
+Expr *VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *CE);
+Expr *VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E);
 Expr *VisitExprWithCleanups(ExprWithCleanups *EWC);
 Expr *VisitCXXThisExpr(CXXThisExpr *E);
 Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
@@ -5846,6 +5848,64 @@
   cast_or_null(ToFQ), MemberNameInfo, );
 }
 
+Expr *ASTNodeImporter::VisitCXXUnresolvedConstructExpr(
+CXXUnresolvedConstructExpr *CE) {
+
+  unsigned NumArgs = CE->arg_size();
+
+  llvm::SmallVector ToArgs(NumArgs);
+  if (ImportArrayChecked(CE->arg_begin(), CE->arg_end(), ToArgs.begin()))
+return nullptr;
+
+  return CXXUnresolvedConstructExpr::Create(
+  Importer.getToContext(), Importer.Import(CE->getTypeSourceInfo()),
+  Importer.Import(CE->getLParenLoc()), llvm::makeArrayRef(ToArgs),
+  Importer.Import(CE->getRParenLoc()));
+}
+
+Expr *ASTNodeImporter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
+  CXXRecordDecl *NamingClass =
+  cast_or_null(Importer.Import(E->getNamingClass()));
+  if (E->getNamingClass() && !NamingClass)
+return nullptr;
+
+  DeclarationName Name = Importer.Import(E->getName());
+  if (E->getName().isEmpty() && Name.isEmpty())
+return nullptr;
+  DeclarationNameInfo NameInfo(Name, Importer.Import(E->getNameLoc()));
+  // Import additional name location/type info.
+  ImportDeclarationNameLoc(E->getNameInfo(), NameInfo);
+
+  UnresolvedSet<8> ToDecls;
+  for (Decl *D : E->decls()) {
+if (NamedDecl *To = cast_or_null(Importer.Import(D)))
+  ToDecls.addDecl(To);
+else
+  return nullptr;
+  }
+
+  TemplateArgumentListInfo *ResInfo = nullptr;
+  if (E->hasExplicitTemplateArgs()) {
+TemplateArgumentListInfo ToTAInfo(Importer.Import(E->getLAngleLoc()),
+  Importer.Import(E->getRAngleLoc()));
+if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo))
+  return nullptr;
+ResInfo = 
+  }
+
+  if (ResInfo || E->getTemplateKeywordLoc().isValid())
+return UnresolvedLookupExpr::Create(
+Importer.getToContext(), NamingClass,
+Importer.Import(E->getQualifierLoc()),
+Importer.Import(E->getTemplateKeywordLoc()), NameInfo, E->requiresADL(),
+ResInfo, ToDecls.begin(), ToDecls.end());
+
+  return UnresolvedLookupExpr::Create(
+  Importer.getToContext(), NamingClass,
+  Importer.Import(E->getQualifierLoc()), NameInfo, E->requiresADL(),
+  E->isOverloaded(), ToDecls.begin(), ToDecls.end());
+}
+
 Expr *ASTNodeImporter::VisitCallExpr(CallExpr *E) {
  

[PATCH] D38921: [analyzer] LoopUnrolling: update the matched assignment operators

2017-11-16 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 123187.
szepet marked 2 inline comments as done.
szepet added a comment.

Testfiles added and HTML updated.


https://reviews.llvm.org/D38921

Files:
  docs/LibASTMatchersReference.html
  include/clang/ASTMatchers/ASTMatchers.h
  lib/ASTMatchers/Dynamic/Registry.cpp
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  lib/StaticAnalyzer/Core/PathDiagnostic.cpp
  test/Analysis/loop-unrolling.cpp
  unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1983,5 +1983,15 @@
   namedDecl(hasExternalFormalLinkage(;
 }
 
+TEST(IsAssignmentOperator, Basic) {
+  StatementMatcher AsOperator = binaryOperator(isAssignmentOperator());
+
+  EXPECT_TRUE(matches("void x() { int a; a += 1; }", AsOperator));
+  EXPECT_TRUE(matches("void x() { int a; a = 2; }", AsOperator));
+  EXPECT_TRUE(matches("void x() { int a; a &= 3; }", AsOperator));
+  EXPECT_TRUE(notMatches("void x() { int a; if(a == 0) return; }", AsOperator));
+}
+
+
 } // namespace ast_matchers
 } // namespace clang
Index: test/Analysis/loop-unrolling.cpp
===
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -98,13 +98,101 @@
   return 0;
 }
 
+int no_unroll_assignment() {
+  for (int i = 0; i < 9; i++) {
+i = i + 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment2() {
+  for (int i = 0; i < 9; i++) {
+i *= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment3() {
+  for (int i = 128; i > 0; i--) {
+i /= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment4() {
+  for (int i = 0; i < 9; i++) {
+i -= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment5() {
+  for (int i = 0; i < 9; i++) {
+i += 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment6() {
+  for (int i = 128; i > 0; i--) {
+i >>= 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment7() {
+  for (int i = 0; i < 512; i++) {
+i <<= 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment8() {
+  for (int i = 0; i < 9; i++) {
+i %= 8;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment9() {
+  for (int i = 0; i < 9; i++) {
+i &= 31;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment10() {
+  for (int i = 0; i < 9; i++) {
+i |= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment11() {
+  for (int i = 0; i < 9; i++) {
+i ^= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
 int make_new_branches_loop_cached() {
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{4}}
-if(getNum()){
-(void) i; // Since this Stmt does not change the State the analyzer
-  // won't make a new execution path but reuse the earlier nodes.
-  }
+if (getNum()) {
+  (void)i; // Since this Stmt does not change the State the analyzer
+   // won't make a new execution path but reuse the earlier nodes.
+}
   }
   clang_analyzer_warnIfReached(); // no-warning
   return 0;
@@ -114,7 +202,7 @@
   int l = 2;
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{10}}
-if(getNum()){
+if (getNum()) {
   ++l;
 }
   }
@@ -126,7 +214,7 @@
   int l = 2;
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{10}}
-if(getNum()){
+if (getNum()) {
   ++l;
 }
 (void) // This ensures that the loop won't be unrolled.
@@ -184,7 +272,7 @@
 for (j = 0; j < 9; ++j) {
   clang_analyzer_numTimesReached(); // expected-warning {{4}}
   a[j] = 22;
-  (void)  // ensures that the inner loop won't be unrolled
+  (void) // ensures that the inner loop won't be unrolled
 }
 a[i] = 42;
   }
@@ -263,8 +351,8 @@
   int k = 2;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{13}}
-if(i == 0 && b) // Splits the state in the first iteration but the recursion
-// call will be unrolled anyway since the condition is known there.
+if (i == 0 && b)  // Splits the state in the 

[PATCH] D38921: [analyzer] LoopUnrolling: update the matched assignment operators

2017-11-16 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 123176.
szepet added a reviewer: klimek.
szepet added a comment.
Herald added subscribers: a.sidorin, rnkovacs.

isAssignmentOp matcher moved to ASTMatchers.h
(Manuel added to reviewers as the code owner of ASTMatchers)


https://reviews.llvm.org/D38921

Files:
  include/clang/ASTMatchers/ASTMatchers.h
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  test/Analysis/loop-unrolling.cpp

Index: test/Analysis/loop-unrolling.cpp
===
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -98,13 +98,101 @@
   return 0;
 }
 
+int no_unroll_assignment() {
+  for (int i = 0; i < 9; i++) {
+i = i + 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment2() {
+  for (int i = 0; i < 9; i++) {
+i *= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment3() {
+  for (int i = 128; i > 0; i--) {
+i /= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment4() {
+  for (int i = 0; i < 9; i++) {
+i -= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment5() {
+  for (int i = 0; i < 9; i++) {
+i += 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment6() {
+  for (int i = 128; i > 0; i--) {
+i >>= 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment7() {
+  for (int i = 0; i < 512; i++) {
+i <<= 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment8() {
+  for (int i = 0; i < 9; i++) {
+i %= 8;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment9() {
+  for (int i = 0; i < 9; i++) {
+i &= 31;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment10() {
+  for (int i = 0; i < 9; i++) {
+i |= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment11() {
+  for (int i = 0; i < 9; i++) {
+i ^= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
 int make_new_branches_loop_cached() {
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{4}}
-if(getNum()){
-(void) i; // Since this Stmt does not change the State the analyzer
-  // won't make a new execution path but reuse the earlier nodes.
-  }
+if (getNum()) {
+  (void)i; // Since this Stmt does not change the State the analyzer
+   // won't make a new execution path but reuse the earlier nodes.
+}
   }
   clang_analyzer_warnIfReached(); // no-warning
   return 0;
@@ -114,7 +202,7 @@
   int l = 2;
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{10}}
-if(getNum()){
+if (getNum()) {
   ++l;
 }
   }
@@ -126,7 +214,7 @@
   int l = 2;
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{10}}
-if(getNum()){
+if (getNum()) {
   ++l;
 }
 (void) // This ensures that the loop won't be unrolled.
@@ -184,7 +272,7 @@
 for (j = 0; j < 9; ++j) {
   clang_analyzer_numTimesReached(); // expected-warning {{4}}
   a[j] = 22;
-  (void)  // ensures that the inner loop won't be unrolled
+  (void) // ensures that the inner loop won't be unrolled
 }
 a[i] = 42;
   }
@@ -263,8 +351,8 @@
   int k = 2;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{13}}
-if(i == 0 && b) // Splits the state in the first iteration but the recursion
-// call will be unrolled anyway since the condition is known there.
+if (i == 0 && b)  // Splits the state in the first iteration but the recursion
+  // call will be unrolled anyway since the condition is known there.
   recursion_unroll1(false);
 clang_analyzer_numTimesReached(); // expected-warning {{14}}
   }
@@ -276,7 +364,7 @@
   int k = 0;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{9}}
-if(i == 0 && b)
+if (i == 0 && b)
   recursion_unroll2(false);
 clang_analyzer_numTimesReached(); // expected-warning {{9}}
   }
@@ -302,7 +390,7 @@
   int k = 2;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{13}}
-if(i == 0 && b) {
+if (i == 0 && b) {
   recursion_unroll4(false);
   continue;
 }
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp

[PATCH] D38674: [analyzer] MisusedMovedObjectChecker: More precise warning message

2017-10-28 Thread Peter Szecsi via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL316852: [analyzer] MisusedMovedObjectChecker: More precise 
warning message (authored by szepet).

Changed prior to commit:
  https://reviews.llvm.org/D38674?vs=118170=120737#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D38674

Files:
  cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
  cfe/trunk/test/Analysis/MisusedMovedObject.cpp

Index: cfe/trunk/test/Analysis/MisusedMovedObject.cpp
===
--- cfe/trunk/test/Analysis/MisusedMovedObject.cpp
+++ cfe/trunk/test/Analysis/MisusedMovedObject.cpp
@@ -38,6 +38,7 @@
   B() = default;
   B(const B &) = default;
   B(B &&) = default;
+  B& operator=(const B ) = default;
   void operator=(B &) {
 return;
   }
@@ -70,6 +71,12 @@
   A(A &, char *k) {
 moveconstruct(std::move(other));
   }
+  void operator=(const A ) {
+i = other.i;
+d = other.d;
+b = other.b;
+return;
+  }
   void operator=(A &) {
 moveconstruct(std::move(other));
 return;
@@ -105,17 +112,42 @@
 }
 
 void simpleMoveCtorTest() {
-  A a;
-  A b;
-  b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
-  a.foo();  // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+  {
+A a;
+A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+a.foo();// expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+  }
+  {
+A a;
+A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+b = a;  // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+  }
+  {
+A a;
+A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+b = std::move(a);   // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}}
+  }
 }
 
 void simpleMoveAssignementTest() {
-  A a;
-  A b;
-  b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
-  a.foo();  // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+  {
+A a;
+A b;
+b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+a.foo();  // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+  }
+  {
+A a;
+A b;
+b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+A c(a);   // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+  }
+  {
+A a;
+A b;
+b = std::move(a);  // expected-note {{'a' became 'moved-from' here}}
+A c(std::move(a)); // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}}
+  }
 }
 
 void moveInInitListTest() {
@@ -270,7 +302,7 @@
   {
 A a;
 for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is true.  Entering loop body}} expected-note {{Loop condition is true.  Entering loop body}}
-  constCopyOrMoveCall(std::move(a)); // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+  constCopyOrMoveCall(std::move(a)); // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}}
   // expected-note@-1 {{'a' became 'moved-from' here}}
 }
   }
@@ -447,7 +479,7 @@
   // Same thing, but with a switch statement.
   {
 A a, b;
-switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 451}}
+switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 483}}
 case 1:
   b = std::move(a); // no-warning
   break;// expected-note {{Execution jumps to the end of the function}}
@@ -459,7 +491,7 @@
   // However, if there's a fallthrough, we do warn.
   {
 A a, b;
-switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 463}}
+switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 495}}
 case 1:
   b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
 case 2:
Index: cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
@@ -60,6 +60,7 @@
   const char *NL, const char *Sep) const override;
 
 private:
+  enum MisuseKind {MK_FunCall, MK_Copy, MK_Move};
   class MovedBugVisitor : public BugReporterVisitorImpl {
   public:
 MovedBugVisitor(const MemRegion *R) : Region(R), 

[PATCH] D38922: [analyzer] LoopUnrolling: check the bitwidth of the used numbers (pr34943)

2017-10-28 Thread Peter Szecsi via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL316830: [analyzer] LoopUnrolling: check the bitwidth of the 
used numbers (pr34943) (authored by szepet).

Changed prior to commit:
  https://reviews.llvm.org/D38922?vs=119019=120733#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D38922

Files:
  cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  cfe/trunk/test/Analysis/loop-unrolling.cpp


Index: cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -208,9 +208,16 @@
 return false;
 
   auto CounterVar = Matches[0].getNodeAs("initVarName");
-  auto BoundNum = Matches[0].getNodeAs("boundNum")->getValue();
-  auto InitNum = Matches[0].getNodeAs("initNum")->getValue();
+  llvm::APInt BoundNum =
+  Matches[0].getNodeAs("boundNum")->getValue();
+  llvm::APInt InitNum =
+  Matches[0].getNodeAs("initNum")->getValue();
   auto CondOp = Matches[0].getNodeAs("conditionOperator");
+  if (InitNum.getBitWidth() != BoundNum.getBitWidth()) {
+InitNum = InitNum.zextOrSelf(BoundNum.getBitWidth());
+BoundNum = BoundNum.zextOrSelf(InitNum.getBitWidth());
+  }
+
   if (CondOp->getOpcode() == BO_GE || CondOp->getOpcode() == BO_LE)
 maxStep = (BoundNum - InitNum + 1).abs().getZExtValue();
   else
Index: cfe/trunk/test/Analysis/loop-unrolling.cpp
===
--- cfe/trunk/test/Analysis/loop-unrolling.cpp
+++ cfe/trunk/test/Analysis/loop-unrolling.cpp
@@ -373,3 +373,9 @@
   return 0;
 }
 
+
+void pr34943() {
+  for (int i = 0; i < 6L; ++i) {
+clang_analyzer_numTimesReached(); // expected-warning {{6}}
+  }
+}


Index: cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -208,9 +208,16 @@
 return false;
 
   auto CounterVar = Matches[0].getNodeAs("initVarName");
-  auto BoundNum = Matches[0].getNodeAs("boundNum")->getValue();
-  auto InitNum = Matches[0].getNodeAs("initNum")->getValue();
+  llvm::APInt BoundNum =
+  Matches[0].getNodeAs("boundNum")->getValue();
+  llvm::APInt InitNum =
+  Matches[0].getNodeAs("initNum")->getValue();
   auto CondOp = Matches[0].getNodeAs("conditionOperator");
+  if (InitNum.getBitWidth() != BoundNum.getBitWidth()) {
+InitNum = InitNum.zextOrSelf(BoundNum.getBitWidth());
+BoundNum = BoundNum.zextOrSelf(InitNum.getBitWidth());
+  }
+
   if (CondOp->getOpcode() == BO_GE || CondOp->getOpcode() == BO_LE)
 maxStep = (BoundNum - InitNum + 1).abs().getZExtValue();
   else
Index: cfe/trunk/test/Analysis/loop-unrolling.cpp
===
--- cfe/trunk/test/Analysis/loop-unrolling.cpp
+++ cfe/trunk/test/Analysis/loop-unrolling.cpp
@@ -373,3 +373,9 @@
   return 0;
 }
 
+
+void pr34943() {
+  for (int i = 0; i < 6L; ++i) {
+clang_analyzer_numTimesReached(); // expected-warning {{6}}
+  }
+}
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38921: [analyzer] LoopUnrolling: update the matched assignment operators

2017-10-28 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 120732.
szepet added a comment.

Updated to use a custom AST matcher for assignment operator check. (More 
structured and efficient.)


https://reviews.llvm.org/D38921

Files:
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  test/Analysis/loop-unrolling.cpp

Index: test/Analysis/loop-unrolling.cpp
===
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -98,13 +98,101 @@
   return 0;
 }
 
+int no_unroll_assignment() {
+  for (int i = 0; i < 9; i++) {
+i = i + 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment2() {
+  for (int i = 0; i < 9; i++) {
+i *= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment3() {
+  for (int i = 128; i > 0; i--) {
+i /= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment4() {
+  for (int i = 0; i < 9; i++) {
+i -= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment5() {
+  for (int i = 0; i < 9; i++) {
+i += 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment6() {
+  for (int i = 128; i > 0; i--) {
+i >>= 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment7() {
+  for (int i = 0; i < 512; i++) {
+i <<= 1;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment8() {
+  for (int i = 0; i < 9; i++) {
+i %= 8;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment9() {
+  for (int i = 0; i < 9; i++) {
+i &= 31;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment10() {
+  for (int i = 0; i < 9; i++) {
+i |= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int no_unroll_assignment11() {
+  for (int i = 0; i < 9; i++) {
+i ^= 2;
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
 int make_new_branches_loop_cached() {
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{4}}
-if(getNum()){
-(void) i; // Since this Stmt does not change the State the analyzer
-  // won't make a new execution path but reuse the earlier nodes.
-  }
+if (getNum()) {
+  (void)i; // Since this Stmt does not change the State the analyzer
+   // won't make a new execution path but reuse the earlier nodes.
+}
   }
   clang_analyzer_warnIfReached(); // no-warning
   return 0;
@@ -114,7 +202,7 @@
   int l = 2;
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{10}}
-if(getNum()){
+if (getNum()) {
   ++l;
 }
   }
@@ -126,7 +214,7 @@
   int l = 2;
   for (int i = 0; i < 8; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{10}}
-if(getNum()){
+if (getNum()) {
   ++l;
 }
 (void) // This ensures that the loop won't be unrolled.
@@ -184,7 +272,7 @@
 for (j = 0; j < 9; ++j) {
   clang_analyzer_numTimesReached(); // expected-warning {{4}}
   a[j] = 22;
-  (void)  // ensures that the inner loop won't be unrolled
+  (void) // ensures that the inner loop won't be unrolled
 }
 a[i] = 42;
   }
@@ -263,8 +351,8 @@
   int k = 2;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{13}}
-if(i == 0 && b) // Splits the state in the first iteration but the recursion
-// call will be unrolled anyway since the condition is known there.
+if (i == 0 && b)  // Splits the state in the first iteration but the recursion
+  // call will be unrolled anyway since the condition is known there.
   recursion_unroll1(false);
 clang_analyzer_numTimesReached(); // expected-warning {{14}}
   }
@@ -276,7 +364,7 @@
   int k = 0;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{9}}
-if(i == 0 && b)
+if (i == 0 && b)
   recursion_unroll2(false);
 clang_analyzer_numTimesReached(); // expected-warning {{9}}
   }
@@ -302,7 +390,7 @@
   int k = 2;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{13}}
-if(i == 0 && b) {
+if (i == 0 && b) {
   recursion_unroll4(false);
   continue;
 }
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ 

[PATCH] D39398: [CFG][Analyzer] Add LoopExit element to the CFG in more cases

2017-10-27 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 120726.
szepet added a comment.

Just removed some accidentally left changes from the patch.


https://reviews.llvm.org/D39398

Files:
  include/clang/Analysis/CFG.h
  lib/Analysis/CFG.cpp
  test/Analysis/loopexit-cfg-output.cpp

Index: test/Analysis/loopexit-cfg-output.cpp
===
--- test/Analysis/loopexit-cfg-output.cpp
+++ test/Analysis/loopexit-cfg-output.cpp
@@ -458,19 +458,540 @@
 
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
-void check_break()
-{
-  for(int i = 2; i < 6; i++) {
-if(i == 4)
+void check_break() {
+  for (int i = 2; i < 6; i++) {
+if (i == 4)
   break;
   }
 
   int i = 1;
-  while(i<5){
+  while (i < 5) {
 i++;
-if(i%2)
+if (i % 2)
   break;
   }
-  
+
+  return;
+}
+
+// CHECK:   [B11 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B10
+
+// CHECK:   [B1]
+// CHECK-NEXT:   1: ForStmt (LoopExit)
+// CHECK-NEXT:   2: return;
+// CHECK-NEXT:   Preds (1): B9
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:   [B2]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B2.1]++
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (1): B9
+
+// CHECK:   [B3]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   Preds (1): B7
+// CHECK-NEXT:   Succs (1): B2
+
+// CHECK:   [B4]
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B7
+
+// CHECK:   [B5]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   2: ForStmt (LoopExit)
+// CHECK-NEXT:   T: goto lab;
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B10
+
+// CHECK:   [B6]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B6.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 2
+// CHECK-NEXT:   4: [B6.2] % [B6.3]
+// CHECK-NEXT:   5: [B6.4] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT:   T: if [B6.5]
+// CHECK-NEXT:   Preds (1): B7
+// CHECK-NEXT:   Succs (2): B5 B4
+
+// CHECK:   [B7]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B7.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 12
+// CHECK-NEXT:   4: [B7.2] < [B7.3]
+// CHECK-NEXT:   T: while [B7.4]
+// CHECK-NEXT:   Preds (2): B4 B8
+// CHECK-NEXT:   Succs (2): B6 B3
+
+// CHECK:   [B8]
+// CHECK-NEXT:   1: 1
+// CHECK-NEXT:   2: int j = 1;
+// CHECK-NEXT:   Preds (1): B9
+// CHECK-NEXT:   Succs (1): B7
+
+// CHECK:   [B9]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B9.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 10
+// CHECK-NEXT:   4: [B9.2] < [B9.3]
+// CHECK-NEXT:   T: for (...; [B9.4]; ...)
+// CHECK-NEXT:   Preds (2): B2 B10
+// CHECK-NEXT:   Succs (2): B8 B1
+
+// CHECK:   [B10]
+// CHECK-NEXT:   lab:
+// CHECK-NEXT:   1: 0
+// CHECK-NEXT:   2: int i = 0;
+// CHECK-NEXT:   Preds (2): B5 B11
+// CHECK-NEXT:   Succs (1): B9
+
+// CHECK:   [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void check_goto() {
+lab:
+  for (int i = 0; i < 10; i++) {
+int j = 1;
+while (j < 12) {
+  if (j % 2)
+goto lab;
+}
+  }
+  return;
+}
+
+// CHECK:   [B11 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B10
+
+// CHECK:   [B1]
+// CHECK-NEXT:   1: ForStmt (LoopExit)
+// CHECK-NEXT:   2: return;
+// CHECK-NEXT:   Preds (1): B9
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:   [B2]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B2.1]++
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (1): B9
+
+// CHECK:   [B3]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   Preds (1): B7
+// CHECK-NEXT:   Succs (1): B2
+
+// CHECK:   [B4]
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B7
+
+// CHECK:   [B5]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   T: goto lab;
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B8
+
+// CHECK:   [B6]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B6.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 2
+// CHECK-NEXT:   4: [B6.2] % [B6.3]
+// CHECK-NEXT:   5: [B6.4] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT:   T: if [B6.5]
+// CHECK-NEXT:   Preds (1): B7
+// CHECK-NEXT:   Succs (2): B5 B4
+
+// CHECK:   [B7]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B7.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 12
+// CHECK-NEXT:   4: [B7.2] < [B7.3]
+// CHECK-NEXT:   T: while [B7.4]
+// CHECK-NEXT:   Preds (2): B4 B8
+// CHECK-NEXT:   Succs (2): B6 B3
+
+// CHECK:   [B8]
+// CHECK-NEXT:   lab:
+// CHECK-NEXT:   1: 1
+// CHECK-NEXT:   2: int j = 1;
+// CHECK-NEXT:   Preds (2): B9 B5
+// CHECK-NEXT:   Succs (1): B7
+
+// CHECK:   [B9]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B9.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 10
+// CHECK-NEXT:   4: [B9.2] < [B9.3]
+// CHECK-NEXT:   T: for (...; [B9.4]; ...)
+// CHECK-NEXT:   Preds (2): B2 B10
+// CHECK-NEXT:   Succs (2): B8 B1
+
+// CHECK:   [B10]
+// CHECK-NEXT:   1: 0
+// CHECK-NEXT:   2: int i = 0;
+// 

[PATCH] D39398: [CFG][Analyzer] Add LoopExit element to the CFG in more cases

2017-10-27 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.
Herald added subscribers: baloghadamsoftware, whisperity.

This patch adds a LoopExit element to the CFG whenever a loop is exited by a 
ReturnStmt, GotoStmt or IndirectGotoStmt.
The LoopExit element is consumed by the Static Analyzer in order to simulate 
the loops more precisely. This patch aims to ensure that the simulation will be 
always consistent. So, whenever a loop is entered a loop exit element will be 
encountered after leaving it.

The idea is the following: In cases where a 'jump' is made we check (by walking 
up on the AST) the containing loops for both (From and To) locations. Then, 
generate the LoopExit element for the exited loops (which is the difference of 
the two "containing loop" set.

Note: In case of IndirectGotoStmt, it could happen that we generate LoopExit 
elements even for loops which is not exited by that jump. However, it does not 
seem to be a problem. This could result that we can not apply some more precise 
modeling feature (like unrolling and widening) but not any more - as I can see. 
(Also, this is a rare case.)


https://reviews.llvm.org/D39398

Files:
  include/clang/Analysis/CFG.h
  lib/Analysis/CFG.cpp
  test/Analysis/loopexit-cfg-output.cpp

Index: test/Analysis/loopexit-cfg-output.cpp
===
--- test/Analysis/loopexit-cfg-output.cpp
+++ test/Analysis/loopexit-cfg-output.cpp
@@ -458,19 +458,540 @@
 
 // CHECK:   [B0 (EXIT)]
 // CHECK-NEXT:   Preds (1): B1
-void check_break()
-{
-  for(int i = 2; i < 6; i++) {
-if(i == 4)
+void check_break() {
+  for (int i = 2; i < 6; i++) {
+if (i == 4)
   break;
   }
 
   int i = 1;
-  while(i<5){
+  while (i < 5) {
 i++;
-if(i%2)
+if (i % 2)
   break;
   }
-  
+
+  return;
+}
+
+// CHECK:   [B11 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B10
+
+// CHECK:   [B1]
+// CHECK-NEXT:   1: ForStmt (LoopExit)
+// CHECK-NEXT:   2: return;
+// CHECK-NEXT:   Preds (1): B9
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:   [B2]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B2.1]++
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (1): B9
+
+// CHECK:   [B3]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   Preds (1): B7
+// CHECK-NEXT:   Succs (1): B2
+
+// CHECK:   [B4]
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B7
+
+// CHECK:   [B5]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   2: ForStmt (LoopExit)
+// CHECK-NEXT:   T: goto lab;
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B10
+
+// CHECK:   [B6]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B6.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 2
+// CHECK-NEXT:   4: [B6.2] % [B6.3]
+// CHECK-NEXT:   5: [B6.4] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT:   T: if [B6.5]
+// CHECK-NEXT:   Preds (1): B7
+// CHECK-NEXT:   Succs (2): B5 B4
+
+// CHECK:   [B7]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B7.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 12
+// CHECK-NEXT:   4: [B7.2] < [B7.3]
+// CHECK-NEXT:   T: while [B7.4]
+// CHECK-NEXT:   Preds (2): B4 B8
+// CHECK-NEXT:   Succs (2): B6 B3
+
+// CHECK:   [B8]
+// CHECK-NEXT:   1: 1
+// CHECK-NEXT:   2: int j = 1;
+// CHECK-NEXT:   Preds (1): B9
+// CHECK-NEXT:   Succs (1): B7
+
+// CHECK:   [B9]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B9.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 10
+// CHECK-NEXT:   4: [B9.2] < [B9.3]
+// CHECK-NEXT:   T: for (...; [B9.4]; ...)
+// CHECK-NEXT:   Preds (2): B2 B10
+// CHECK-NEXT:   Succs (2): B8 B1
+
+// CHECK:   [B10]
+// CHECK-NEXT:   lab:
+// CHECK-NEXT:   1: 0
+// CHECK-NEXT:   2: int i = 0;
+// CHECK-NEXT:   Preds (2): B5 B11
+// CHECK-NEXT:   Succs (1): B9
+
+// CHECK:   [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void check_goto() {
+lab:
+  for (int i = 0; i < 10; i++) {
+int j = 1;
+while (j < 12) {
+  if (j % 2)
+goto lab;
+}
+  }
+  return;
+}
+
+// CHECK:   [B11 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B10
+
+// CHECK:   [B1]
+// CHECK-NEXT:   1: ForStmt (LoopExit)
+// CHECK-NEXT:   2: return;
+// CHECK-NEXT:   Preds (1): B9
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:   [B2]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B2.1]++
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (1): B9
+
+// CHECK:   [B3]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   Preds (1): B7
+// CHECK-NEXT:   Succs (1): B2
+
+// CHECK:   [B4]
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B7
+
+// CHECK:   [B5]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   T: goto lab;
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B8
+
+// CHECK:   [B6]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B6.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 2
+// CHECK-NEXT:   4: [B6.2] % [B6.3]
+// CHECK-NEXT:   5: [B6.4] 

[PATCH] D38842: [CrossTU] Fix handling of Cross Translation Unit directory path

2017-10-27 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

LGTM as well, but same note applies.


https://reviews.llvm.org/D38842



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


[PATCH] D38843: [ASTImporter] Support importing CXXPseudoDestructorExpr

2017-10-19 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 119579.
szepet added a comment.

Checking for importing base updated to (!Imported && From) style.


https://reviews.llvm.org/D38843

Files:
  lib/AST/ASTImporter.cpp
  unittests/AST/ASTImporterTest.cpp


Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -535,5 +535,21 @@
  binaryOperator(has(cxxUnresolvedConstructExpr()));
 }
 
+const internal::VariadicDynCastAllOfMatcher
+cxxPseudoDestructorExpr;
+
+TEST(ImportExpr, ImportCXXPseudoDestructorExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(
+  testImport("typedef int T;"
+ "void declToImport(int *p) {"
+ "p->T::~T();"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(has(compoundStmt(has(
+ callExpr(has(cxxPseudoDestructorExpr();
+}
+
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -278,6 +278,7 @@
 Expr *VisitExprWithCleanups(ExprWithCleanups *EWC);
 Expr *VisitCXXThisExpr(CXXThisExpr *E);
 Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
+Expr *VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
 Expr *VisitMemberExpr(MemberExpr *E);
 Expr *VisitCallExpr(CallExpr *E);
 Expr *VisitInitListExpr(InitListExpr *E);
@@ -5540,6 +5541,38 @@
   E->isOverloaded(), ToDecls.begin(), ToDecls.end());
 }
 
+
+Expr *ASTNodeImporter::VisitCXXPseudoDestructorExpr(
+CXXPseudoDestructorExpr *E) {
+
+  Expr *BaseE = Importer.Import(E->getBase());
+  if (!BaseE && E->getBase())
+return nullptr;
+
+  TypeSourceInfo *ScopeInfo = Importer.Import(E->getScopeTypeInfo());
+
+  PseudoDestructorTypeStorage Storage;
+  if (IdentifierInfo *FromII = E->getDestroyedTypeIdentifier()) {
+IdentifierInfo *ToII = Importer.Import(FromII);
+if (!ToII)
+  return nullptr;
+Storage = PseudoDestructorTypeStorage(
+  ToII, Importer.Import(E->getDestroyedTypeLoc()));
+  } else {
+TypeSourceInfo *TI = Importer.Import(E->getDestroyedTypeInfo());
+if (!TI)
+  return nullptr;
+Storage = PseudoDestructorTypeStorage(TI);
+  }
+
+  return new (Importer.getToContext()) CXXPseudoDestructorExpr(
+Importer.getToContext(), BaseE, E->isArrow(),
+Importer.Import(E->getOperatorLoc()),
+Importer.Import(E->getQualifierLoc()),
+ScopeInfo, Importer.Import(E->getColonColonLoc()),
+Importer.Import(E->getTildeLoc()), Storage);
+}
+
 Expr *ASTNodeImporter::VisitCallExpr(CallExpr *E) {
   QualType T = Importer.Import(E->getType());
   if (T.isNull())


Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -535,5 +535,21 @@
  binaryOperator(has(cxxUnresolvedConstructExpr()));
 }
 
+const internal::VariadicDynCastAllOfMatcher
+cxxPseudoDestructorExpr;
+
+TEST(ImportExpr, ImportCXXPseudoDestructorExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(
+  testImport("typedef int T;"
+ "void declToImport(int *p) {"
+ "p->T::~T();"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(has(compoundStmt(has(
+ callExpr(has(cxxPseudoDestructorExpr();
+}
+
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -278,6 +278,7 @@
 Expr *VisitExprWithCleanups(ExprWithCleanups *EWC);
 Expr *VisitCXXThisExpr(CXXThisExpr *E);
 Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
+Expr *VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
 Expr *VisitMemberExpr(MemberExpr *E);
 Expr *VisitCallExpr(CallExpr *E);
 Expr *VisitInitListExpr(InitListExpr *E);
@@ -5540,6 +5541,38 @@
   E->isOverloaded(), ToDecls.begin(), ToDecls.end());
 }
 
+
+Expr *ASTNodeImporter::VisitCXXPseudoDestructorExpr(
+CXXPseudoDestructorExpr *E) {
+
+  Expr *BaseE = Importer.Import(E->getBase());
+  if (!BaseE && E->getBase())
+return nullptr;
+
+  TypeSourceInfo *ScopeInfo = Importer.Import(E->getScopeTypeInfo());
+
+  PseudoDestructorTypeStorage Storage;
+  if (IdentifierInfo *FromII = E->getDestroyedTypeIdentifier()) {
+IdentifierInfo *ToII = Importer.Import(FromII);
+if (!ToII)
+  return nullptr;
+Storage = PseudoDestructorTypeStorage(
+  ToII, 

[PATCH] D38843: [ASTImporter] Support importing CXXPseudoDestructorExpr

2017-10-19 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added inline comments.



Comment at: lib/AST/ASTImporter.cpp:5549
+  Expr *BaseE = Importer.Import(E->getBase());
+  if (!BaseE)
+return nullptr;

xazax.hun wrote:
> Does `E->getBase()` guaranteed to return non-null? What happens when this 
> node was constructed using EmptyShell? Shouldn't we check for that somehow? 
> When can that happen?
The import process of ArraySubscriptExpr and UnaryOperator (and probably more 
other classes) are not prepared for this case as well. Not sure if this can be 
encountered in a complete AST.
However, I think a lazy evaluated && operator won't hurt the performance and at 
least we are going to be prepared for this case.


https://reviews.llvm.org/D38843



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


[PATCH] D38845: [ASTImporter] Support importing UnresolvedMemberExpr, DependentNameType, DependentScopeDeclRefExpr

2017-10-19 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added inline comments.



Comment at: lib/AST/ASTImporter.cpp:5500
+
+  TemplateArgumentListInfo ToTAInfo;
+  TemplateArgumentListInfo *ResInfo = nullptr;

xazax.hun wrote:
> According to phabricator this code is very similar to a snippet starting from 
> line 4524 and some code bellow. Maybe it would be worth to have a function 
> instead of duplicating?
Good point, I would do it in a separate patch and add it as a dependency if it 
is OK.


https://reviews.llvm.org/D38845



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


[PATCH] D38675: [analyzer] MisusedMovedObjectChecker: Moving the checker out of alpha state

2017-10-14 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 119032.
szepet added a comment.

Test file (running line) update.


https://reviews.llvm.org/D38675

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  test/Analysis/MisusedMovedObject.cpp


Index: test/Analysis/MisusedMovedObject.cpp
===
--- test/Analysis/MisusedMovedObject.cpp
+++ test/Analysis/MisusedMovedObject.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze 
-analyzer-checker=alpha.cplusplus.MisusedMovedObject -std=c++11 -verify 
-analyzer-output=text %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=cplusplus.MisusedMovedObject 
-std=c++11 -verify -analyzer-output=text %s
 
 namespace std {
 
Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -272,6 +272,11 @@
   HelpText<"Checks C++ copy and move assignment operators for self 
assignment">,
   DescFile<"CXXSelfAssignmentChecker.cpp">;
 
+def MisusedMovedObjectChecker : Checker<"MisusedMovedObject">,
+  HelpText<"Method calls on a moved-from object and copying a moved-from "
+   "object will be reported">,
+  DescFile<"MisusedMovedObjectChecker.cpp">;
+
 } // end: "cplusplus"
 
 let ParentPackage = CplusplusOptIn in {
@@ -293,11 +298,6 @@
   HelpText<"Check for iterators used outside their valid ranges">,
   DescFile<"IteratorChecker.cpp">;
 
-def MisusedMovedObjectChecker: Checker<"MisusedMovedObject">,
- HelpText<"Method calls on a moved-from object and copying a moved-from "
-  "object will be reported">,
- DescFile<"MisusedMovedObjectChecker.cpp">;
-
 } // end: "alpha.cplusplus"
 
 


Index: test/Analysis/MisusedMovedObject.cpp
===
--- test/Analysis/MisusedMovedObject.cpp
+++ test/Analysis/MisusedMovedObject.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.MisusedMovedObject -std=c++11 -verify -analyzer-output=text %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=cplusplus.MisusedMovedObject -std=c++11 -verify -analyzer-output=text %s
 
 namespace std {
 
Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -272,6 +272,11 @@
   HelpText<"Checks C++ copy and move assignment operators for self assignment">,
   DescFile<"CXXSelfAssignmentChecker.cpp">;
 
+def MisusedMovedObjectChecker : Checker<"MisusedMovedObject">,
+  HelpText<"Method calls on a moved-from object and copying a moved-from "
+   "object will be reported">,
+  DescFile<"MisusedMovedObjectChecker.cpp">;
+
 } // end: "cplusplus"
 
 let ParentPackage = CplusplusOptIn in {
@@ -293,11 +298,6 @@
   HelpText<"Check for iterators used outside their valid ranges">,
   DescFile<"IteratorChecker.cpp">;
 
-def MisusedMovedObjectChecker: Checker<"MisusedMovedObject">,
- HelpText<"Method calls on a moved-from object and copying a moved-from "
-  "object will be reported">,
- DescFile<"MisusedMovedObjectChecker.cpp">;
-
 } // end: "alpha.cplusplus"
 
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38922: [analyzer] LoopUnrolling: check the bitwidth of the used numbers (pr34943)

2017-10-14 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.
Herald added subscribers: baloghadamsoftware, whisperity.

The loop unrolling feature aims to track the maximum possible steps a loop can 
make. In order to implement this, it investigates the initial value of the 
counter variable and the bound number. (There has to be known.) 
These numbers are used as llvm::APInts, however, it was not checked if their 
bitwidths are the same which lead to some crashes.
This revision solves this problem by extending the "shorter" one (to the length 
of the "longer" one).
For the detailed bug report, see: https://bugs.llvm.org/show_bug.cgi?id=34943


https://reviews.llvm.org/D38922

Files:
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  test/Analysis/loop-unrolling.cpp


Index: test/Analysis/loop-unrolling.cpp
===
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -373,3 +373,9 @@
   return 0;
 }
 
+
+void pr34943() {
+  for (int i = 0; i < 6L; ++i) {
+clang_analyzer_numTimesReached(); // expected-warning {{6}}
+  }
+}
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -208,9 +208,16 @@
 return false;
 
   auto CounterVar = Matches[0].getNodeAs("initVarName");
-  auto BoundNum = Matches[0].getNodeAs("boundNum")->getValue();
-  auto InitNum = Matches[0].getNodeAs("initNum")->getValue();
+  llvm::APInt BoundNum =
+  Matches[0].getNodeAs("boundNum")->getValue();
+  llvm::APInt InitNum =
+  Matches[0].getNodeAs("initNum")->getValue();
   auto CondOp = Matches[0].getNodeAs("conditionOperator");
+  if (InitNum.getBitWidth() != BoundNum.getBitWidth()) {
+InitNum = InitNum.zextOrSelf(BoundNum.getBitWidth());
+BoundNum = BoundNum.zextOrSelf(InitNum.getBitWidth());
+  }
+
   if (CondOp->getOpcode() == BO_GE || CondOp->getOpcode() == BO_LE)
 maxStep = (BoundNum - InitNum + 1).abs().getZExtValue();
   else


Index: test/Analysis/loop-unrolling.cpp
===
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -373,3 +373,9 @@
   return 0;
 }
 
+
+void pr34943() {
+  for (int i = 0; i < 6L; ++i) {
+clang_analyzer_numTimesReached(); // expected-warning {{6}}
+  }
+}
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -208,9 +208,16 @@
 return false;
 
   auto CounterVar = Matches[0].getNodeAs("initVarName");
-  auto BoundNum = Matches[0].getNodeAs("boundNum")->getValue();
-  auto InitNum = Matches[0].getNodeAs("initNum")->getValue();
+  llvm::APInt BoundNum =
+  Matches[0].getNodeAs("boundNum")->getValue();
+  llvm::APInt InitNum =
+  Matches[0].getNodeAs("initNum")->getValue();
   auto CondOp = Matches[0].getNodeAs("conditionOperator");
+  if (InitNum.getBitWidth() != BoundNum.getBitWidth()) {
+InitNum = InitNum.zextOrSelf(BoundNum.getBitWidth());
+BoundNum = BoundNum.zextOrSelf(InitNum.getBitWidth());
+  }
+
   if (CondOp->getOpcode() == BO_GE || CondOp->getOpcode() == BO_LE)
 maxStep = (BoundNum - InitNum + 1).abs().getZExtValue();
   else
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38921: [analyzer] LoopUnrolling: update the matched assignment operators

2017-10-14 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.
Herald added subscribers: baloghadamsoftware, whisperity.

Extended the matched assignment operators when checking for bound changes in a 
body of the loop. This updated list covers all the (current) possible 
assignments.


https://reviews.llvm.org/D38921

Files:
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp


Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -99,7 +99,10 @@
 declRefExpr(to(varDecl(VarNodeMatcher)),
   binaryOperator(anyOf(hasOperatorName("="), hasOperatorName("+="),
hasOperatorName("/="), hasOperatorName("*="),
-   hasOperatorName("-=")),
+   hasOperatorName("-="), hasOperatorName("%="),
+   hasOperatorName("&="), hasOperatorName("|="),
+   hasOperatorName("^="), hasOperatorName("<<="),
+   hasOperatorName(">>=")),
  hasLHS(ignoringParenImpCasts(
  declRefExpr(to(varDecl(VarNodeMatcher)));
 }


Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -99,7 +99,10 @@
 declRefExpr(to(varDecl(VarNodeMatcher)),
   binaryOperator(anyOf(hasOperatorName("="), hasOperatorName("+="),
hasOperatorName("/="), hasOperatorName("*="),
-   hasOperatorName("-=")),
+   hasOperatorName("-="), hasOperatorName("%="),
+   hasOperatorName("&="), hasOperatorName("|="),
+   hasOperatorName("^="), hasOperatorName("<<="),
+   hasOperatorName(">>=")),
  hasLHS(ignoringParenImpCasts(
  declRefExpr(to(varDecl(VarNodeMatcher)));
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38845: [ASTImporter] Support importing UnresolvedMemberExpr, DependentNameType, DependentScopeDeclRefExpr

2017-10-12 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.

The visit callback implementations for the 3 C++ AST Node added to the 
ASTImporter.

Note: Based on: 
https://github.com/haoNoQ/clang/blob/summary-ipa-draft/lib/AST/ASTImporter.cpp


https://reviews.llvm.org/D38845

Files:
  lib/AST/ASTImporter.cpp
  unittests/AST/ASTImporterTest.cpp

Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -551,5 +551,68 @@
 }
 
 
+const internal::VariadicDynCastAllOfMatcher
+unresolvedMemberExpr;
+TEST(ImportExpr, ImportUnresolvedMemberExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(testImport("struct S { template  void mem(); };"
+ "template  void declToImport() {"
+ "S s;"
+ "s.mem();"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(
+ has(callExpr(has(unresolvedMemberExpr()));
+}
+
+const internal::VariadicDynCastAllOfMatcher
+dependentScopeDeclRefExpr;
+TEST(ImportExpr, ImportDependentScopeDeclRefExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(testImport("template  struct S;"
+ "template  void declToImport() {"
+ "S::foo;"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(
+ has(dependentScopeDeclRefExpr();
+
+  EXPECT_TRUE(testImport("template  struct S;"
+ "template  void declToImport() {"
+ "S::template foo;"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(
+ has(dependentScopeDeclRefExpr();
+
+  EXPECT_TRUE(testImport("template  struct S;"
+ "template  void declToImport() {"
+ "S::template foo<>;"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(
+ has(dependentScopeDeclRefExpr();
+
+  EXPECT_TRUE(testImport("template  struct S;"
+ "template  void declToImport() {"
+ "S::template foo;"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(
+ has(dependentScopeDeclRefExpr();
+}
+
+const internal::VariadicDynCastAllOfMatcher
+dependentNameType;
+TEST(ImportExpr, DependentNameType) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(testImport("template  struct declToImport {"
+ "typedef typename T::type dependent_name;"
+ "};",
+ Lang_CXX11, "", Lang_CXX11, Verifier,
+ classTemplateDecl(has(cxxRecordDecl(
+ has(typedefDecl(has(dependentNameType();
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -76,7 +76,7 @@
 QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T);
 QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T);
 QualType VisitElaboratedType(const ElaboratedType *T);
-// FIXME: DependentNameType
+QualType VisitDependentNameType(const DependentNameType *T);
 // FIXME: DependentTemplateSpecializationType
 QualType VisitObjCInterfaceType(const ObjCInterfaceType *T);
 QualType VisitObjCObjectType(const ObjCObjectType *T);
@@ -273,8 +273,10 @@
 Expr *VisitCXXConstructExpr(CXXConstructExpr *E);
 Expr *VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
 Expr *VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
+Expr *VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E);
 Expr *VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *CE);
 Expr *VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E);
+Expr *VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E);
 Expr *VisitExprWithCleanups(ExprWithCleanups *EWC);
 Expr *VisitCXXThisExpr(CXXThisExpr *E);
 Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
@@ -774,6 +776,25 @@
ToQualifier, ToNamedType);
 }
 
+QualType 

[PATCH] D38843: [ASTImporter] Support importing CXXPseudoDestructorExpr

2017-10-12 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.

Adding VisitCXXPseudoDestructorExpr callback to the ASTImporter.

Note: This is based on: 
https://github.com/haoNoQ/clang/blob/summary-ipa-draft/lib/AST/ASTImporter.cpp#L7624
 .


https://reviews.llvm.org/D38843

Files:
  lib/AST/ASTImporter.cpp
  unittests/AST/ASTImporterTest.cpp


Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -535,5 +535,21 @@
  binaryOperator(has(cxxUnresolvedConstructExpr()));
 }
 
+const internal::VariadicDynCastAllOfMatcher
+cxxPseudoDestructorExpr;
+
+TEST(ImportExpr, ImportCXXPseudoDestructorExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(
+  testImport("typedef int T;"
+ "void declToImport(int *p) {"
+ "p->T::~T();"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(has(compoundStmt(has(
+ callExpr(has(cxxPseudoDestructorExpr();
+}
+
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -278,6 +278,7 @@
 Expr *VisitExprWithCleanups(ExprWithCleanups *EWC);
 Expr *VisitCXXThisExpr(CXXThisExpr *E);
 Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
+Expr *VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
 Expr *VisitMemberExpr(MemberExpr *E);
 Expr *VisitCallExpr(CallExpr *E);
 Expr *VisitInitListExpr(InitListExpr *E);
@@ -5540,6 +5541,38 @@
   E->isOverloaded(), ToDecls.begin(), ToDecls.end());
 }
 
+
+Expr *ASTNodeImporter::VisitCXXPseudoDestructorExpr(
+CXXPseudoDestructorExpr *E) {
+
+  Expr *BaseE = Importer.Import(E->getBase());
+  if (!BaseE)
+return nullptr;
+
+  TypeSourceInfo *ScopeInfo = Importer.Import(E->getScopeTypeInfo());
+
+  PseudoDestructorTypeStorage Storage;
+  if (IdentifierInfo *FromII = E->getDestroyedTypeIdentifier()) {
+IdentifierInfo *ToII = Importer.Import(FromII);
+if (!ToII)
+  return nullptr;
+Storage = PseudoDestructorTypeStorage(
+  ToII, Importer.Import(E->getDestroyedTypeLoc()));
+  } else {
+TypeSourceInfo *TI = Importer.Import(E->getDestroyedTypeInfo());
+if (!TI)
+  return nullptr;
+Storage = PseudoDestructorTypeStorage(TI);
+  }
+
+  return new (Importer.getToContext()) CXXPseudoDestructorExpr(
+Importer.getToContext(), BaseE, E->isArrow(),
+Importer.Import(E->getOperatorLoc()),
+Importer.Import(E->getQualifierLoc()),
+ScopeInfo, Importer.Import(E->getColonColonLoc()),
+Importer.Import(E->getTildeLoc()), Storage);
+}
+
 Expr *ASTNodeImporter::VisitCallExpr(CallExpr *E) {
   QualType T = Importer.Import(E->getType());
   if (T.isNull())


Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -535,5 +535,21 @@
  binaryOperator(has(cxxUnresolvedConstructExpr()));
 }
 
+const internal::VariadicDynCastAllOfMatcher
+cxxPseudoDestructorExpr;
+
+TEST(ImportExpr, ImportCXXPseudoDestructorExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(
+  testImport("typedef int T;"
+ "void declToImport(int *p) {"
+ "p->T::~T();"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(has(compoundStmt(has(
+ callExpr(has(cxxPseudoDestructorExpr();
+}
+
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -278,6 +278,7 @@
 Expr *VisitExprWithCleanups(ExprWithCleanups *EWC);
 Expr *VisitCXXThisExpr(CXXThisExpr *E);
 Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
+Expr *VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
 Expr *VisitMemberExpr(MemberExpr *E);
 Expr *VisitCallExpr(CallExpr *E);
 Expr *VisitInitListExpr(InitListExpr *E);
@@ -5540,6 +5541,38 @@
   E->isOverloaded(), ToDecls.begin(), ToDecls.end());
 }
 
+
+Expr *ASTNodeImporter::VisitCXXPseudoDestructorExpr(
+CXXPseudoDestructorExpr *E) {
+
+  Expr *BaseE = Importer.Import(E->getBase());
+  if (!BaseE)
+return nullptr;
+
+  TypeSourceInfo *ScopeInfo = Importer.Import(E->getScopeTypeInfo());
+
+  PseudoDestructorTypeStorage Storage;
+  if (IdentifierInfo *FromII = E->getDestroyedTypeIdentifier()) {
+IdentifierInfo *ToII = Importer.Import(FromII);
+if (!ToII)
+  return nullptr;
+Storage = PseudoDestructorTypeStorage(
+  

[PATCH] D38694: [ASTImporter] Support importing CXXUnresolvedConstructExpr and UnresolvedLookupExpr

2017-10-09 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.

This patch adds support for importing two different kind of C++ AST Node.
Note: This solution is based on 
https://github.com/haoNoQ/clang/blob/summary-ipa-draft/lib/AST/ASTImporter.cpp#L7605
 .


https://reviews.llvm.org/D38694

Files:
  lib/AST/ASTImporter.cpp
  unittests/AST/ASTImporterTest.cpp

Index: unittests/AST/ASTImporterTest.cpp
===
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -457,7 +457,6 @@
   vaArgExpr();
 }
 
-
 TEST(ImportType, ImportAtomicType) {
   MatchVerifier Verifier;
   EXPECT_TRUE(testImport("void declToImport() { typedef _Atomic(int) a_int; }",
@@ -502,5 +501,39 @@
  has(cxxDependentScopeMemberExpr();
 }
 
+TEST(ImportExpr, ImportUnresolvedLookupExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(testImport("template int foo();"
+ "template  void declToImport() {"
+ "  ::foo;"
+ "  ::template foo;"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(
+ compoundStmt(has(unresolvedLookupExpr();
+}
+
+TEST(ImportExpr, ImportCXXUnresolvedConstructExpr) {
+  MatchVerifier Verifier;
+  EXPECT_TRUE(
+  testImport("template  class C { T t; };"
+ "template  void declToImport() {"
+ "C d;"
+ "d.t = T()"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(has(
+ binaryOperator(has(cxxUnresolvedConstructExpr()));
+  EXPECT_TRUE(
+  testImport("template  class C { T t; };"
+ "template  void declToImport() {"
+ "C d;"
+ "()->t = T()"
+ "}",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionTemplateDecl(has(functionDecl(has(compoundStmt(has(
+ binaryOperator(has(cxxUnresolvedConstructExpr()));
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: lib/AST/ASTImporter.cpp
===
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -273,6 +273,8 @@
 Expr *VisitCXXConstructExpr(CXXConstructExpr *E);
 Expr *VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
 Expr *VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
+Expr *VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *CE);
+Expr *VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E);
 Expr *VisitExprWithCleanups(ExprWithCleanups *EWC);
 Expr *VisitCXXThisExpr(CXXThisExpr *E);
 Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
@@ -5464,6 +5466,80 @@
   MemberNameInfo, ResInfo);
 }
 
+Expr *ASTNodeImporter::VisitCXXUnresolvedConstructExpr(
+CXXUnresolvedConstructExpr *CE) {
+
+  unsigned NumArgs = CE->arg_size();
+
+  llvm::SmallVector ToArgs(NumArgs);
+
+  for (unsigned ai = 0, ae = NumArgs; ai != ae; ++ai) {
+Expr *FromArg = CE->getArg(ai);
+Expr *ToArg = Importer.Import(FromArg);
+if (!ToArg)
+  return nullptr;
+ToArgs[ai] = ToArg;
+  }
+
+  Expr **ToArgs_Copied = new (Importer.getToContext()) Expr *[NumArgs];
+
+  for (unsigned ai = 0, ae = NumArgs; ai != ae; ++ai)
+ToArgs_Copied[ai] = ToArgs[ai];
+
+  return CXXUnresolvedConstructExpr::Create(
+  Importer.getToContext(), Importer.Import(CE->getTypeSourceInfo()),
+  Importer.Import(CE->getLParenLoc()),
+  llvm::makeArrayRef(ToArgs_Copied, NumArgs),
+  Importer.Import(CE->getRParenLoc()));
+}
+
+Expr *ASTNodeImporter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
+  CXXRecordDecl *NamingClass =
+  cast_or_null(Importer.Import(E->getNamingClass()));
+  if (E->getNamingClass() && !NamingClass)
+return nullptr;
+
+  DeclarationName Name = Importer.Import(E->getName());
+  if (E->getName().isEmpty() && Name.isEmpty())
+return nullptr;
+  DeclarationNameInfo NameInfo(Name, Importer.Import(E->getNameLoc()));
+  // Import additional name location/type info.
+  ImportDeclarationNameLoc(E->getNameInfo(), NameInfo);
+
+  UnresolvedSet<8> ToDecls;
+  for (Decl *D : E->decls()) {
+if (NamedDecl *To = cast_or_null(Importer.Import(D)))
+  ToDecls.addDecl(To);
+else
+  return nullptr;
+  }
+
+  TemplateArgumentListInfo ToTAInfo;
+  TemplateArgumentListInfo *ResInfo = nullptr;
+  if (E->hasExplicitTemplateArgs()) {
+for (const auto  : E->template_arguments()) {
+  bool Error = false;
+  TemplateArgumentLoc ToTALoc = ImportTemplateArgumentLoc(FromLoc, Error);
+  if (Error)
+return nullptr;
+  ToTAInfo.addArgument(ToTALoc);
+}
+ResInfo = 
+  }
+
+  if (ResInfo || 

[PATCH] D38675: [analyzer] MisusedMovedObjectChecker: Moving the checker out of alpha state

2017-10-08 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.
Herald added subscribers: baloghadamsoftware, whisperity.

First, I am not exactly sure what are the requirements for moving a checker out 
of alpha. However, the checker seems to work with a low false positive rate. 
(<15 on the LLVM, 6 effectively different) Also found a true positive (well, it 
was only example code but still!) which fixes was sent and accepted in patch 
https://reviews.llvm.org/D32939 .

Is it enough or should I check it on other open source projects? If so, what 
results are acceptable? ( @NoQ  probably has already used it as well, maybe can 
have some more comments on the results.)


https://reviews.llvm.org/D38675

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td


Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -272,6 +272,11 @@
   HelpText<"Checks C++ copy and move assignment operators for self 
assignment">,
   DescFile<"CXXSelfAssignmentChecker.cpp">;
 
+def MisusedMovedObjectChecker : Checker<"MisusedMovedObject">,
+  HelpText<"Method calls on a moved-from object and copying a moved-from "
+   "object will be reported">,
+  DescFile<"MisusedMovedObjectChecker.cpp">;
+
 } // end: "cplusplus"
 
 let ParentPackage = CplusplusOptIn in {
@@ -293,11 +298,6 @@
   HelpText<"Check for iterators used outside their valid ranges">,
   DescFile<"IteratorChecker.cpp">;
 
-def MisusedMovedObjectChecker: Checker<"MisusedMovedObject">,
- HelpText<"Method calls on a moved-from object and copying a moved-from "
-  "object will be reported">,
- DescFile<"MisusedMovedObjectChecker.cpp">;
-
 } // end: "alpha.cplusplus"
 
 


Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -272,6 +272,11 @@
   HelpText<"Checks C++ copy and move assignment operators for self assignment">,
   DescFile<"CXXSelfAssignmentChecker.cpp">;
 
+def MisusedMovedObjectChecker : Checker<"MisusedMovedObject">,
+  HelpText<"Method calls on a moved-from object and copying a moved-from "
+   "object will be reported">,
+  DescFile<"MisusedMovedObjectChecker.cpp">;
+
 } // end: "cplusplus"
 
 let ParentPackage = CplusplusOptIn in {
@@ -293,11 +298,6 @@
   HelpText<"Check for iterators used outside their valid ranges">,
   DescFile<"IteratorChecker.cpp">;
 
-def MisusedMovedObjectChecker: Checker<"MisusedMovedObject">,
- HelpText<"Method calls on a moved-from object and copying a moved-from "
-  "object will be reported">,
- DescFile<"MisusedMovedObjectChecker.cpp">;
-
 } // end: "alpha.cplusplus"
 
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38674: [analyzer] MisusedMovedObjectChecker: More precise warning message

2017-10-08 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.
Herald added subscribers: baloghadamsoftware, whisperity.

Added new enum in order to differentiate the warning messages on "misusing" 
into 3 categories: function calls, moving an object, copying an object. (At the 
moment the checker gives the same message in case of copying and moving.)

Additional test cases added as well.

Note: The dependency is only added for the reason not having conflict problems 
on the test cases.


https://reviews.llvm.org/D38674

Files:
  lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
  test/Analysis/MisusedMovedObject.cpp

Index: test/Analysis/MisusedMovedObject.cpp
===
--- test/Analysis/MisusedMovedObject.cpp
+++ test/Analysis/MisusedMovedObject.cpp
@@ -38,6 +38,7 @@
   B() = default;
   B(const B &) = default;
   B(B &&) = default;
+  B& operator=(const B ) = default;
   void operator=(B &) {
 return;
   }
@@ -70,6 +71,12 @@
   A(A &, char *k) {
 moveconstruct(std::move(other));
   }
+  void operator=(const A ) {
+i = other.i;
+d = other.d;
+b = other.b;
+return;
+  }
   void operator=(A &) {
 moveconstruct(std::move(other));
 return;
@@ -105,17 +112,42 @@
 }
 
 void simpleMoveCtorTest() {
-  A a;
-  A b;
-  b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
-  a.foo();  // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+  {
+A a;
+A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+a.foo();// expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+  }
+  {
+A a;
+A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+b = a;  // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+  }
+  {
+A a;
+A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+b = std::move(a);   // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}}
+  }
 }
 
 void simpleMoveAssignementTest() {
-  A a;
-  A b;
-  b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
-  a.foo();  // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+  {
+A a;
+A b;
+b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+a.foo();  // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+  }
+  {
+A a;
+A b;
+b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+A c(a);   // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+  }
+  {
+A a;
+A b;
+b = std::move(a);  // expected-note {{'a' became 'moved-from' here}}
+A c(std::move(a)); // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}}
+  }
 }
 
 void moveInInitListTest() {
@@ -270,7 +302,7 @@
   {
 A a;
 for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is true.  Entering loop body}} expected-note {{Loop condition is true.  Entering loop body}}
-  constCopyOrMoveCall(std::move(a)); // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+  constCopyOrMoveCall(std::move(a)); // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}}
   // expected-note@-1 {{'a' became 'moved-from' here}}
 }
   }
@@ -447,7 +479,7 @@
   // Same thing, but with a switch statement.
   {
 A a, b;
-switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 451}}
+switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 483}}
 case 1:
   b = std::move(a); // no-warning
   break;// expected-note {{Execution jumps to the end of the function}}
@@ -459,7 +491,7 @@
   // However, if there's a fallthrough, we do warn.
   {
 A a, b;
-switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 463}}
+switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 495}}
 case 1:
   b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
 case 2:
Index: lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
@@ -58,6 +58,7 @@
  const LocationContext *LCtx, const CallEvent *Call) const;
 
 private:
+  enum MisuseKind {MK_FunCall, MK_Copy, MK_Move};
   class MovedBugVisitor : 

[PATCH] D37897: [StaticAnalyzer] Fix ProgramState for static variables that are not written

2017-10-06 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

Hello Daniel!

It is a great feature to add, thanks for working on this!
I have just small comments (rather questions) on the code.




Comment at: lib/StaticAnalyzer/Core/ExprEngine.cpp:155
+  Children.push(FuncBody);
+  while (!Children.empty()) {
+const Stmt *Child = Children.top();

I think instead of this logic it would be better to use ConstStmtVisitor. In 
this case it does quite the same thing in a (maybe?) more structured manner. 
What do you think?



Comment at: lib/StaticAnalyzer/Core/ExprEngine.cpp:168
+  VD->getStorageClass() == SC_Static &&
+  !VD->getType()->isPointerType()) {
+Vars->insert(VD);

Is it possible that a type is an IntegerType and a  PointerType at the same 
time? If these are excluding cases then the check for !isPointer could be 
removed.


Repository:
  rL LLVM

https://reviews.llvm.org/D37897



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


[PATCH] D31538: [analyzer] MisusedMovedObjectChecker: Fix a false positive on state-resetting a base-class sub-object.

2017-10-06 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

Hello Artem!

Could you please commit these changes? (And https://reviews.llvm.org/D31541 as 
well.) Thanks in advance!


https://reviews.llvm.org/D31538



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


[PATCH] D32981: [ASTImporter] Improve handling of incomplete types

2017-10-05 Thread Peter Szecsi via Phabricator via cfe-commits
szepet closed this revision.
szepet added a comment.

This patch was commited in r302975. (https://reviews.llvm.org/rL302975)


https://reviews.llvm.org/D32981



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


[PATCH] D37572: [clang-tidy] SuspiciousEnumUsageCheck bugfix

2017-09-12 Thread Peter Szecsi via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL313016: [clang-tidy] SuspiciousEnumUsageCheck bugfix 
(authored by szepet).

Changed prior to commit:
  https://reviews.llvm.org/D37572?vs=114567=114788#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D37572

Files:
  clang-tools-extra/trunk/clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
  clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-enum-usage.cpp


Index: clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-enum-usage.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-enum-usage.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-enum-usage.cpp
@@ -54,7 +54,7 @@
   int emptytest = EmptyVal | B;
   if (bestDay() | A)
 return 1;
-  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different 
enum types 
+  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different 
enum types
   if (I | Y)
 return 1;
   // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different 
enum types
@@ -88,3 +88,9 @@
 return 1;
   return 42;
 }
+
+namespace PR34400 {
+enum { E1 = 0 };
+enum { E2 = -1 };
+enum { l = E1 | E2 };
+}
Index: clang-tools-extra/trunk/clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
@@ -42,7 +42,8 @@
 const auto MinMaxVal = std::minmax_element(
 EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
 [](const EnumConstantDecl *E1, const EnumConstantDecl *E2) {
-  return E1->getInitVal() < E2->getInitVal();
+  return llvm::APSInt::compareValues(E1->getInitVal(),
+ E2->getInitVal()) < 0;
 });
 MinVal = MinMaxVal.first->getInitVal();
 MaxVal = MinMaxVal.second->getInitVal();
@@ -57,7 +58,8 @@
 static bool hasDisjointValueRange(const EnumDecl *Enum1,
   const EnumDecl *Enum2) {
   ValueRange Range1(Enum1), Range2(Enum2);
-  return (Range1.MaxVal < Range2.MinVal) || (Range2.MaxVal < Range1.MinVal);
+  return llvm::APSInt::compareValues(Range1.MaxVal, Range2.MinVal) < 0 ||
+ llvm::APSInt::compareValues(Range2.MaxVal, Range1.MinVal) < 0;
 }
 
 static bool isNonPowerOf2NorNullLiteral(const EnumConstantDecl *EnumConst) {


Index: clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-enum-usage.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-enum-usage.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-enum-usage.cpp
@@ -54,7 +54,7 @@
   int emptytest = EmptyVal | B;
   if (bestDay() | A)
 return 1;
-  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different enum types 
+  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different enum types
   if (I | Y)
 return 1;
   // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different enum types
@@ -88,3 +88,9 @@
 return 1;
   return 42;
 }
+
+namespace PR34400 {
+enum { E1 = 0 };
+enum { E2 = -1 };
+enum { l = E1 | E2 };
+}
Index: clang-tools-extra/trunk/clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
@@ -42,7 +42,8 @@
 const auto MinMaxVal = std::minmax_element(
 EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
 [](const EnumConstantDecl *E1, const EnumConstantDecl *E2) {
-  return E1->getInitVal() < E2->getInitVal();
+  return llvm::APSInt::compareValues(E1->getInitVal(),
+ E2->getInitVal()) < 0;
 });
 MinVal = MinMaxVal.first->getInitVal();
 MaxVal = MinMaxVal.second->getInitVal();
@@ -57,7 +58,8 @@
 static bool hasDisjointValueRange(const EnumDecl *Enum1,
   const EnumDecl *Enum2) {
   ValueRange Range1(Enum1), Range2(Enum2);
-  return (Range1.MaxVal < Range2.MinVal) || (Range2.MaxVal < Range1.MinVal);
+  return llvm::APSInt::compareValues(Range1.MaxVal, Range2.MinVal) < 0 ||
+ llvm::APSInt::compareValues(Range2.MaxVal, Range1.MinVal) < 0;
 }
 
 static bool isNonPowerOf2NorNullLiteral(const EnumConstantDecl *EnumConst) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D37572: [clang-tidy] SuspiciousEnumUsageCheck bugfix

2017-09-11 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 114567.
szepet marked 3 inline comments as done.
szepet added a comment.

Updates based on the comments. Thanks for the reduced test case and the fast 
review!

Not sure if in these cases am I allowed to commit (since it was accepted) or 
since it was accepted a lot of comments ago I should wait for another response?


https://reviews.llvm.org/D37572

Files:
  clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
  test/clang-tidy/misc-suspicious-enum-usage.cpp


Index: test/clang-tidy/misc-suspicious-enum-usage.cpp
===
--- test/clang-tidy/misc-suspicious-enum-usage.cpp
+++ test/clang-tidy/misc-suspicious-enum-usage.cpp
@@ -54,7 +54,7 @@
   int emptytest = EmptyVal | B;
   if (bestDay() | A)
 return 1;
-  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different 
enum types 
+  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different 
enum types
   if (I | Y)
 return 1;
   // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different 
enum types
@@ -88,3 +88,9 @@
 return 1;
   return 42;
 }
+
+namespace PR34400 {
+enum { E1 = 0 };
+enum { E2 = -1 };
+enum { l = E1 | E2 };
+}
Index: clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
===
--- clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
+++ clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
@@ -42,7 +42,8 @@
 const auto MinMaxVal = std::minmax_element(
 EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
 [](const EnumConstantDecl *E1, const EnumConstantDecl *E2) {
-  return E1->getInitVal() < E2->getInitVal();
+  return llvm::APSInt::compareValues(E1->getInitVal(),
+ E2->getInitVal()) < 0;
 });
 MinVal = MinMaxVal.first->getInitVal();
 MaxVal = MinMaxVal.second->getInitVal();
@@ -57,7 +58,8 @@
 static bool hasDisjointValueRange(const EnumDecl *Enum1,
   const EnumDecl *Enum2) {
   ValueRange Range1(Enum1), Range2(Enum2);
-  return (Range1.MaxVal < Range2.MinVal) || (Range2.MaxVal < Range1.MinVal);
+  return llvm::APSInt::compareValues(Range1.MaxVal, Range2.MinVal) < 0 ||
+ llvm::APSInt::compareValues(Range2.MaxVal, Range1.MinVal) < 0;
 }
 
 static bool isNonPowerOf2NorNullLiteral(const EnumConstantDecl *EnumConst) {


Index: test/clang-tidy/misc-suspicious-enum-usage.cpp
===
--- test/clang-tidy/misc-suspicious-enum-usage.cpp
+++ test/clang-tidy/misc-suspicious-enum-usage.cpp
@@ -54,7 +54,7 @@
   int emptytest = EmptyVal | B;
   if (bestDay() | A)
 return 1;
-  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different enum types 
+  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different enum types
   if (I | Y)
 return 1;
   // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different enum types
@@ -88,3 +88,9 @@
 return 1;
   return 42;
 }
+
+namespace PR34400 {
+enum { E1 = 0 };
+enum { E2 = -1 };
+enum { l = E1 | E2 };
+}
Index: clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
===
--- clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
+++ clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
@@ -42,7 +42,8 @@
 const auto MinMaxVal = std::minmax_element(
 EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
 [](const EnumConstantDecl *E1, const EnumConstantDecl *E2) {
-  return E1->getInitVal() < E2->getInitVal();
+  return llvm::APSInt::compareValues(E1->getInitVal(),
+ E2->getInitVal()) < 0;
 });
 MinVal = MinMaxVal.first->getInitVal();
 MaxVal = MinMaxVal.second->getInitVal();
@@ -57,7 +58,8 @@
 static bool hasDisjointValueRange(const EnumDecl *Enum1,
   const EnumDecl *Enum2) {
   ValueRange Range1(Enum1), Range2(Enum2);
-  return (Range1.MaxVal < Range2.MinVal) || (Range2.MaxVal < Range1.MinVal);
+  return llvm::APSInt::compareValues(Range1.MaxVal, Range2.MinVal) < 0 ||
+ llvm::APSInt::compareValues(Range2.MaxVal, Range1.MinVal) < 0;
 }
 
 static bool isNonPowerOf2NorNullLiteral(const EnumConstantDecl *EnumConst) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D37572: [clang-tidy] SuspiciousEnumUsageCheck bugfix

2017-09-07 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.
Herald added subscribers: baloghadamsoftware, whisperity, JDevlieghere.

There is a reported bug on the checker not handling the some APSInt values 
correctly: https://bugs.llvm.org/show_bug.cgi?id=34400

This patch fixes it, however, it shows a false positive. (Added to the test 
cases)
I am not sure if it's a checker or AST problem. The AST dump shows the 
following:

  -BinaryOperator 0x1195b98  'int' '|'
   |-ImplicitCastExpr 0x1195b68  'int' 
   | `-DeclRefExpr 0x1195b18  'enum j 
>::(anonymous at dude.cpp:15:3)' EnumConstant 0x1193b98 'ah' 'enum a, struct c, 0> 
>::(anonymous at dude.cpp:29:3)'
   `-ImplicitCastExpr 0x1195b80  'int' 
 `-DeclRefExpr 0x1195b40  'enum j 
>::(anonymous at dude.cpp:15:3)' EnumConstant 0x1195ad0 'ai' 'enum a, struct c, 0> 
>::(anonymous at dude.cpp:29:3)'

I am not sure if this is right since this belongs to the following code snippet 
(maybe I am just missing something):

  enum { ah = ad::m, ai = ae::m, l = ah | ai };

What do you think?


https://reviews.llvm.org/D37572

Files:
  clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
  test/clang-tidy/misc-suspicious-enum-usage.cpp


Index: test/clang-tidy/misc-suspicious-enum-usage.cpp
===
--- test/clang-tidy/misc-suspicious-enum-usage.cpp
+++ test/clang-tidy/misc-suspicious-enum-usage.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s misc-suspicious-enum-usage %t -- 
-config="{CheckOptions: [{key: misc-suspicious-enum-usage.StrictMode, value: 
0}]}" --
+// RUN: %check_clang_tidy %s misc-suspicious-enum-usage %t -- 
-config="{CheckOptions: [{key: misc-suspicious-enum-usage.StrictMode, value: 
0}]}" -- -std=c++11
 
 enum Empty {
 };
@@ -54,7 +54,7 @@
   int emptytest = EmptyVal | B;
   if (bestDay() | A)
 return 1;
-  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different 
enum types 
+  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different 
enum types
   if (I | Y)
 return 1;
   // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different 
enum types
@@ -88,3 +88,41 @@
 return 1;
   return 42;
 }
+
+// Bug #34400
+template 
+struct a;
+template 
+struct c;
+template 
+struct e;
+template 
+struct f;
+template 
+struct h {
+  typedef e i;
+};
+template 
+struct j {
+  enum { k = a::l,
+ m };
+};
+template 
+struct e : j {};
+template 
+struct r : h::i {};
+template 
+struct a> {
+  enum { l = q };
+};
+template 
+struct c : r> {};
+template 
+struct a> {
+  enum { ah = ad::m,
+ ai = ae::m,
+ l = ah | ai };
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: enum values are from different 
enum types
+};
+template 
+struct f : e, c, 0>> {};
Index: clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
===
--- clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
+++ clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
@@ -42,7 +42,8 @@
 const auto MinMaxVal = std::minmax_element(
 EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
 [](const EnumConstantDecl *E1, const EnumConstantDecl *E2) {
-  return E1->getInitVal() < E2->getInitVal();
+  return llvm::APSInt::compareValues(E1->getInitVal(),
+ E2->getInitVal()) == -1;
 });
 MinVal = MinMaxVal.first->getInitVal();
 MaxVal = MinMaxVal.second->getInitVal();
@@ -57,7 +58,9 @@
 static bool hasDisjointValueRange(const EnumDecl *Enum1,
   const EnumDecl *Enum2) {
   ValueRange Range1(Enum1), Range2(Enum2);
-  return (Range1.MaxVal < Range2.MinVal) || (Range2.MaxVal < Range1.MinVal);
+  bool Less1 = llvm::APSInt::compareValues(Range1.MaxVal, Range2.MinVal) == -1;
+  bool Less2 = llvm::APSInt::compareValues(Range2.MaxVal, Range1.MinVal) == -1;
+  return Less1 || Less2;
 }
 
 static bool isNonPowerOf2NorNullLiteral(const EnumConstantDecl *EnumConst) {


Index: test/clang-tidy/misc-suspicious-enum-usage.cpp
===
--- test/clang-tidy/misc-suspicious-enum-usage.cpp
+++ test/clang-tidy/misc-suspicious-enum-usage.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s misc-suspicious-enum-usage %t -- -config="{CheckOptions: [{key: misc-suspicious-enum-usage.StrictMode, value: 0}]}" --
+// RUN: %check_clang_tidy %s misc-suspicious-enum-usage %t -- -config="{CheckOptions: [{key: misc-suspicious-enum-usage.StrictMode, value: 0}]}" -- -std=c++11
 
 enum Empty {
 };
@@ -54,7 +54,7 @@
   int emptytest = EmptyVal | B;
   if (bestDay() | A)
 return 1;
-  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from 

[PATCH] D37187: [Analyzer] Fix Bug 25609 - Assertion UNREACHABLE: 'Unexpected ProgramPoint' with widen-loops=true

2017-08-31 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

Thanks for the update!
It looks good to me! (Probably somebody else (most likely NoQ) will have some 
additional comment but I think it's great!)


https://reviews.llvm.org/D37187



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


[PATCH] D37187: [Analyzer] Fix Bug 25609 - Assertion UNREACHABLE: 'Unexpected ProgramPoint' with widen-loops=true

2017-08-30 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a reviewer: szepet.
szepet edited subscribers, added: cfe-commits; removed: szepet.
szepet added a comment.

Hello MTC,

Thanks for working on this! I planned to add a change like this in D36690 
 but it worths an individual patch (did not 
know it was a reported bug).
Just some thoughts:

- I think the current display information is ambiguous. If I did not know the 
code then I would not understand what this stands for. (That is just my 
opinon.)  I think Artem's "Contents of <...> are wiped" idea is better but I 
would go with something like this: "Invalidated previously known information on 
<...>". (Maybe remove the word 'previously' if its too long.) It still can be 
weird for the user that why this happened but at least in case of a false 
positive he/she can see that why this was even considered by the analyzer.
- Right now there is a "race condition" between your patch and D36690 
. So in order to avoid "conflicts" I'd ask you 
to add some variable changing effect to the body of the loop. For example in 
the last test case the variable 'num' is the one which you use to show the 
effect of widening. In this case a line like `num++` or `num = i` would ensure 
that the more precise widening invalidates it as well. Other thing is that 
handling loops which contains pointer operation or nested loops will be a 
little bit more conservative, so you these will not be widened like now. 
(However, test_for_bug_25609()) still should be valid.
- Please upload the diff with context (git flag: -U9) since it is really 
helpful for the review.
- +1 inline comment below.




Comment at: lib/StaticAnalyzer/Core/PathDiagnostic.cpp:694
+  } else if (Optional BE = P.getAs()) {
+CFGElement BlockFront = BE->getBlock()->front();
+if (BlockFront.getKind() == CFGElement::Statement) {

I think it would be more correct to use the location what is used in case of 
the BlockEdge. (So on the entranced block terminator condition.) The reason is 
because the BlockEntrance display message will be displayed before the message 
of the BlockEdge (since it is an "earlier" node in the ExplodedGraph). So it 
would result that if check these notes in a viewer then the earlier note would 
belong to the later location which could be confusing.


https://reviews.llvm.org/D37187



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


[PATCH] D37181: {StaticAnalyzer} LoopUnrolling: Keep track the maximum number of steps for each loop

2017-08-28 Thread Peter Szecsi via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL311883: [StaticAnalyzer] LoopUnrolling: Keep track the 
maximum number of steps for each… (authored by szepet).

Changed prior to commit:
  https://reviews.llvm.org/D37181?vs=112866=112877#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D37181

Files:
  cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
  cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
  cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  cfe/trunk/test/Analysis/loop-unrolling.cpp

Index: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1523,10 +1523,11 @@
   // If we reach a loop which has a known bound (and meets
   // other constraints) then consider completely unrolling it.
   if(AMgr.options.shouldUnrollLoops()) {
+unsigned maxBlockVisitOnPath = AMgr.options.maxBlockVisitOnPath;
 const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator();
 if (Term) {
   ProgramStateRef NewState = updateLoopStack(Term, AMgr.getASTContext(),
- Pred);
+ Pred, maxBlockVisitOnPath);
   if (NewState != Pred->getState()) {
 ExplodedNode *UpdatedNode = nodeBuilder.generateNode(NewState, Pred);
 if (!UpdatedNode)
Index: cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -23,22 +23,28 @@
 using namespace ento;
 using namespace clang::ast_matchers;
 
+static const int MAXIMUM_STEP_UNROLLED = 128;
+
 struct LoopState {
 private:
   enum Kind { Normal, Unrolled } K;
   const Stmt *LoopStmt;
   const LocationContext *LCtx;
-  LoopState(Kind InK, const Stmt *S, const LocationContext *L)
-  : K(InK), LoopStmt(S), LCtx(L) {}
+  unsigned maxStep;
+  LoopState(Kind InK, const Stmt *S, const LocationContext *L, unsigned N)
+  : K(InK), LoopStmt(S), LCtx(L), maxStep(N) {}
 
 public:
-  static LoopState getNormal(const Stmt *S, const LocationContext *L) {
-return LoopState(Normal, S, L);
+  static LoopState getNormal(const Stmt *S, const LocationContext *L,
+ unsigned N) {
+return LoopState(Normal, S, L, N);
   }
-  static LoopState getUnrolled(const Stmt *S, const LocationContext *L) {
-return LoopState(Unrolled, S, L);
+  static LoopState getUnrolled(const Stmt *S, const LocationContext *L,
+   unsigned N) {
+return LoopState(Unrolled, S, L, N);
   }
   bool isUnrolled() const { return K == Unrolled; }
+  unsigned getMaxStep() const { return maxStep; }
   const Stmt *getLoopStmt() const { return LoopStmt; }
   const LocationContext *getLocationContext() const { return LCtx; }
   bool operator==(const LoopState ) const {
@@ -48,6 +54,7 @@
 ID.AddInteger(K);
 ID.AddPointer(LoopStmt);
 ID.AddPointer(LCtx);
+ID.AddInteger(maxStep);
   }
 };
 
@@ -74,12 +81,14 @@
 }
 
 static internal::Matcher simpleCondition(StringRef BindName) {
-  return binaryOperator(
-  anyOf(hasOperatorName("<"), hasOperatorName(">"), hasOperatorName("<="),
-hasOperatorName(">="), hasOperatorName("!=")),
-  hasEitherOperand(ignoringParenImpCasts(
-  declRefExpr(to(varDecl(hasType(isInteger())).bind(BindName),
-  hasEitherOperand(ignoringParenImpCasts(integerLiteral(;
+  return binaryOperator(anyOf(hasOperatorName("<"), hasOperatorName(">"),
+  hasOperatorName("<="), hasOperatorName(">="),
+  hasOperatorName("!=")),
+hasEitherOperand(ignoringParenImpCasts(declRefExpr(
+to(varDecl(hasType(isInteger())).bind(BindName),
+hasEitherOperand(ignoringParenImpCasts(
+integerLiteral().bind("boundNum"
+  .bind("conditionOperator");
 }
 
 static internal::Matcher
@@ -134,13 +143,13 @@
   return forStmt(
  hasCondition(simpleCondition("initVarName")),
  // Initialization should match the form: 'int i = 6' or 'i = 42'.
- hasLoopInit(
- anyOf(declStmt(hasSingleDecl(
-   varDecl(allOf(hasInitializer(integerLiteral()),
- equalsBoundNode("initVarName"),
-   binaryOperator(hasLHS(declRefExpr(to(varDecl(
-  equalsBoundNode("initVarName"),
-  hasRHS(integerLiteral(),
+ hasLoopInit(anyOf(
+ declStmt(hasSingleDecl(varDecl(
+ 

[PATCH] D36962: [StaticAnalyzer] LoopUnrolling: Excluding loops which splits the state (make more branches)

2017-08-28 Thread Peter Szecsi via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL311881: [StaticAnalyzer] LoopUnrolling: Excluding loops 
which splits the state (authored by szepet).

Changed prior to commit:
  https://reviews.llvm.org/D36962?vs=112710=112874#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D36962

Files:
  cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  cfe/trunk/test/Analysis/loop-unrolling.cpp

Index: cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -204,6 +204,26 @@
   return !isPossiblyEscaped(CounterVar->getCanonicalDecl(), Pred);
 }
 
+bool madeNewBranch(ExplodedNode* N, const Stmt* LoopStmt) {
+  const Stmt* S = nullptr;
+  while (!N->pred_empty())
+  {
+if (N->succ_size() > 1)
+  return true;
+
+ProgramPoint P = N->getLocation();
+if (Optional BE = P.getAs())
+  S = BE->getBlock()->getTerminator();
+
+if (S == LoopStmt)
+  return false;
+
+N = N->getFirstPred();
+  }
+
+  llvm_unreachable("Reached root without encountering the previous step");
+}
+
 // updateLoopStack is called on every basic block, therefore it needs to be fast
 ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext ,
 ExplodedNode* Pred) {
@@ -215,8 +235,13 @@
 
   auto LS = State->get();
   if (!LS.isEmpty() && LoopStmt == LS.getHead().getLoopStmt() &&
-  LCtx == LS.getHead().getLocationContext())
+  LCtx == LS.getHead().getLocationContext()) {
+if (LS.getHead().isUnrolled() && madeNewBranch(Pred, LoopStmt)) {
+  State = State->set(LS.getTail());
+  State = State->add(LoopState::getNormal(LoopStmt, LCtx));
+}
 return State;
+  }
 
   if (!shouldCompletelyUnroll(LoopStmt, ASTCtx, Pred)) {
 State = State->add(LoopState::getNormal(LoopStmt, LCtx));
Index: cfe/trunk/test/Analysis/loop-unrolling.cpp
===
--- cfe/trunk/test/Analysis/loop-unrolling.cpp
+++ cfe/trunk/test/Analysis/loop-unrolling.cpp
@@ -1,6 +1,7 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config unroll-loops=true,cfg-loopexit=true -verify -std=c++11 %s
 
 void clang_analyzer_numTimesReached();
+void clang_analyzer_warnIfReached();
 
 int getNum();
 void foo(int &);
@@ -62,8 +63,7 @@
 int simple_no_unroll3() {
   int a[9];
   int k = 42;
-  int i;
-  for (i = 0; i < 9; i++) {
+  for (int i = 0; i < 9; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{4}}
 a[i] = 42;
 (void)
@@ -98,6 +98,44 @@
   return 0;
 }
 
+int make_new_branches_loop_cached() {
+  for (int i = 0; i < 8; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+if(getNum()){
+(void) i; // Since this Stmt does not change the State the analyzer
+  // won't make a new execution path but reuse the earlier nodes.
+  }
+  }
+  clang_analyzer_warnIfReached(); // no-warning
+  return 0;
+}
+
+int make_new_branches_loop_uncached() {
+  int l = 2;
+  for (int i = 0; i < 8; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{10}}
+if(getNum()){
+  ++l;
+}
+  }
+  clang_analyzer_warnIfReached(); // no-warning
+  return 0;
+}
+
+int make_new_branches_loop_uncached2() {
+  int l = 2;
+  for (int i = 0; i < 8; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{10}}
+if(getNum()){
+  ++l;
+}
+(void) // This ensures that the loop won't be unrolled.
+  }
+  clang_analyzer_warnIfReached(); // no-warning
+  return 0;
+}
+
+
 int escape_before_loop_no_unroll1() {
   int a[9];
   int k = 42;
@@ -142,10 +180,11 @@
   int k = 42;
   int j = 0;
   for (int i = 0; i < 9; i++) {
-clang_analyzer_numTimesReached(); // expected-warning {{16}}
-for (j = 0; j < getNum(); ++j) {
-  clang_analyzer_numTimesReached(); // expected-warning {{15}}
+clang_analyzer_numTimesReached(); // expected-warning {{1}}
+for (j = 0; j < 9; ++j) {
+  clang_analyzer_numTimesReached(); // expected-warning {{4}}
   a[j] = 22;
+  (void)  // ensures that the inner loop won't be unrolled
 }
 a[i] = 42;
   }
@@ -213,8 +252,8 @@
 int nested_inlined_no_unroll1() {
   int k;
   for (int i = 0; i < 9; i++) {
-clang_analyzer_numTimesReached(); // expected-warning {{26}}
-k = simple_unknown_bound_loop();  // reevaluation without inlining
+clang_analyzer_numTimesReached(); // expected-warning {{15}}
+k = simple_unknown_bound_loop();  // reevaluation without inlining, splits the state as well
   }
   int a = 22 / k; // no-warning
   return 0;
@@ -224,22 +263,23 @@
 int recursion_unroll1(bool b) {
   int k = 2;
   for (int i = 0; i < 5; i++) {
-clang_analyzer_numTimesReached(); // expected-warning {{14}}
-if(i == 0 && b)
+

[PATCH] D37103: [StaticAnalyzer] LoopUnrolling fixes

2017-08-28 Thread Peter Szecsi via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL311880: [StaticAnalyzer] LoopUnrolling fixes (authored by 
szepet).

Changed prior to commit:
  https://reviews.llvm.org/D37103?vs=112824=112872#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D37103

Files:
  cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp
  cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
  cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  cfe/trunk/test/Analysis/loop-unrolling.cpp


Index: cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -27,7 +27,9 @@
   /*AddInitializers=*/true,
   Options.includeTemporaryDtorsInCFG(),
Options.includeLifetimeInCFG(),
-  Options.includeLoopExitInCFG(),
+  // Adding LoopExit elements to the CFG is a requirement for loop
+  // unrolling.
+  Options.includeLoopExitInCFG() || Options.shouldUnrollLoops(),
   Options.shouldSynthesizeBodies(),
   Options.shouldConditionalizeStaticInitializers(),
   /*addCXXNewAllocator=*/true,
Index: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1527,8 +1527,11 @@
 if (Term) {
   ProgramStateRef NewState = updateLoopStack(Term, AMgr.getASTContext(),
  Pred);
-  if (NewState != Pred->getState()){
-Pred = nodeBuilder.generateNode(NewState, Pred);
+  if (NewState != Pred->getState()) {
+ExplodedNode *UpdatedNode = nodeBuilder.generateNode(NewState, Pred);
+if (!UpdatedNode)
+  return;
+Pred = UpdatedNode;
   }
 }
 // Is we are inside an unrolled loop then no need the check the counters.
Index: cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -13,15 +13,11 @@
 ///
 
//===--===//
 
-#include "clang/Analysis/CFGStmtMap.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/AST/StmtVisitor.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
-#include "llvm/ADT/Statistic.h"
 
 using namespace clang;
 using namespace ento;
@@ -72,11 +68,8 @@
 
 ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State) {
   auto LS = State->get();
-  assert(!LS.isEmpty() && "Loop not added to the stack.");
-  assert(LoopStmt == LS.getHead().getLoopStmt() &&
- "Loop is not on top of the stack.");
-
-  State = State->set(LS.getTail());
+  if (!LS.isEmpty() && LS.getHead().getLoopStmt() == LoopStmt)
+State = State->set(LS.getTail());
   return State;
 }
 
Index: cfe/trunk/test/Analysis/loop-unrolling.cpp
===
--- cfe/trunk/test/Analysis/loop-unrolling.cpp
+++ cfe/trunk/test/Analysis/loop-unrolling.cpp
@@ -272,3 +272,10 @@
   int a = 22 / k;
   return 0;
 }
+
+int loop_exit_while_empty_loop_stack() {
+  if (getNum())
+for (int i = 1; i < 8; i++)
+  ;
+  return 0;
+}


Index: cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -27,7 +27,9 @@
   /*AddInitializers=*/true,
   Options.includeTemporaryDtorsInCFG(),
 	Options.includeLifetimeInCFG(),
-  Options.includeLoopExitInCFG(),
+  // Adding LoopExit elements to the CFG is a requirement for loop
+  // unrolling.
+  Options.includeLoopExitInCFG() || Options.shouldUnrollLoops(),
   Options.shouldSynthesizeBodies(),
   Options.shouldConditionalizeStaticInitializers(),
   /*addCXXNewAllocator=*/true,
Index: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1527,8 +1527,11 @@
 if (Term) {
   ProgramStateRef NewState = updateLoopStack(Term, AMgr.getASTContext(),
  Pred);
-  if 

[PATCH] D37181: {StaticAnalyzer} LoopUnrolling: Keep track the maximum number of steps for each loop

2017-08-28 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 112866.
szepet marked an inline comment as done.
szepet added a comment.

Updated to use static int.


https://reviews.llvm.org/D37181

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  test/Analysis/loop-unrolling.cpp

Index: test/Analysis/loop-unrolling.cpp
===
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -5,7 +5,7 @@
 
 int getNum();
 void foo(int &);
-// Testing for loops.
+
 int simple_unroll1() {
   int a[9];
   int k = 42;
@@ -259,7 +259,6 @@
   return 0;
 }
 
-
 int recursion_unroll1(bool b) {
   int k = 2;
   for (int i = 0; i < 5; i++) {
@@ -289,7 +288,7 @@
   int k = 2;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{10}}
-if(i == 4 && b) {
+if (i == 4 && b) {
   recursion_unroll3(false);
   break;
 }
@@ -319,3 +318,57 @@
   ;
   return 0;
 }
+
+int num_steps_on_limit() {
+  for (int i = 0; i < 128; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{128}}
+  }
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
+  return 0;
+}
+
+int num_steps_over_limit1() {
+  for (int i = 0; i < 129; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int num_steps_on_limit2() {
+  for (int i = 0; i < 2; i++) {
+for (int j = 0; j < 64; j++) {
+  clang_analyzer_numTimesReached(); // expected-warning {{128}}
+}
+  }
+  return 0;
+}
+
+int num_steps_over_limit2() {
+  for (int i = 0; i < 2; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{1}}
+for (int j = 0; j <= 64; j++) {
+  clang_analyzer_numTimesReached(); // expected-warning {{4}}
+}
+  }
+  return 0;
+}
+
+int num_steps_on_limit3() {
+  for (int i = 0; i < getNum(); i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+for (int j = 0; j < 32; j++) {
+  clang_analyzer_numTimesReached(); // expected-warning {{128}}
+}
+  }
+  return 0;
+}
+
+int num_steps_over_limit3() {
+  for (int i = 0; i < getNum(); i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{1}}
+for (int j = 0; j < 33; j++) {
+  clang_analyzer_numTimesReached(); // expected-warning {{4}}
+}
+  }
+  return 0;
+}
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -23,22 +23,28 @@
 using namespace ento;
 using namespace clang::ast_matchers;
 
+static const int MAXIMUM_STEP_UNROLLED = 128;
+
 struct LoopState {
 private:
   enum Kind { Normal, Unrolled } K;
   const Stmt *LoopStmt;
   const LocationContext *LCtx;
-  LoopState(Kind InK, const Stmt *S, const LocationContext *L)
-  : K(InK), LoopStmt(S), LCtx(L) {}
+  unsigned maxStep;
+  LoopState(Kind InK, const Stmt *S, const LocationContext *L, unsigned N)
+  : K(InK), LoopStmt(S), LCtx(L), maxStep(N) {}
 
 public:
-  static LoopState getNormal(const Stmt *S, const LocationContext *L) {
-return LoopState(Normal, S, L);
+  static LoopState getNormal(const Stmt *S, const LocationContext *L,
+ unsigned N) {
+return LoopState(Normal, S, L, N);
   }
-  static LoopState getUnrolled(const Stmt *S, const LocationContext *L) {
-return LoopState(Unrolled, S, L);
+  static LoopState getUnrolled(const Stmt *S, const LocationContext *L,
+   unsigned N) {
+return LoopState(Unrolled, S, L, N);
   }
   bool isUnrolled() const { return K == Unrolled; }
+  unsigned getMaxStep() const { return maxStep; }
   const Stmt *getLoopStmt() const { return LoopStmt; }
   const LocationContext *getLocationContext() const { return LCtx; }
   bool operator==(const LoopState ) const {
@@ -48,6 +54,7 @@
 ID.AddInteger(K);
 ID.AddPointer(LoopStmt);
 ID.AddPointer(LCtx);
+ID.AddInteger(maxStep);
   }
 };
 
@@ -74,12 +81,14 @@
 }
 
 static internal::Matcher simpleCondition(StringRef BindName) {
-  return binaryOperator(
-  anyOf(hasOperatorName("<"), hasOperatorName(">"), hasOperatorName("<="),
-hasOperatorName(">="), hasOperatorName("!=")),
-  hasEitherOperand(ignoringParenImpCasts(
-  declRefExpr(to(varDecl(hasType(isInteger())).bind(BindName),
-  hasEitherOperand(ignoringParenImpCasts(integerLiteral(;
+  return binaryOperator(anyOf(hasOperatorName("<"), hasOperatorName(">"),
+  hasOperatorName("<="), hasOperatorName(">="),
+  hasOperatorName("!=")),
+hasEitherOperand(ignoringParenImpCasts(declRefExpr(
+to(varDecl(hasType(isInteger())).bind(BindName),
+

[PATCH] D37103: [StaticAnalyzer] LoopUnrolling fixes

2017-08-27 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 112824.
szepet added a comment.

Update based on comments.


https://reviews.llvm.org/D37103

Files:
  lib/StaticAnalyzer/Core/AnalysisManager.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  test/Analysis/loop-unrolling.cpp


Index: test/Analysis/loop-unrolling.cpp
===
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -272,3 +272,10 @@
   int a = 22 / k;
   return 0;
 }
+
+int loop_exit_while_empty_loop_stack() {
+  if (getNum())
+for (int i = 1; i < 8; i++)
+  ;
+  return 0;
+}
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -13,15 +13,11 @@
 ///
 
//===--===//
 
-#include "clang/Analysis/CFGStmtMap.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/AST/StmtVisitor.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
-#include "llvm/ADT/Statistic.h"
 
 using namespace clang;
 using namespace ento;
@@ -72,11 +68,8 @@
 
 ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State) {
   auto LS = State->get();
-  assert(!LS.isEmpty() && "Loop not added to the stack.");
-  assert(LoopStmt == LS.getHead().getLoopStmt() &&
- "Loop is not on top of the stack.");
-
-  State = State->set(LS.getTail());
+  if (!LS.isEmpty() && LS.getHead().getLoopStmt() == LoopStmt)
+State = State->set(LS.getTail());
   return State;
 }
 
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1527,8 +1527,11 @@
 if (Term) {
   ProgramStateRef NewState = updateLoopStack(Term, AMgr.getASTContext(),
  Pred);
-  if (NewState != Pred->getState()){
-Pred = nodeBuilder.generateNode(NewState, Pred);
+  if (NewState != Pred->getState()) {
+ExplodedNode *UpdatedNode = nodeBuilder.generateNode(NewState, Pred);
+if (!UpdatedNode)
+  return;
+Pred = UpdatedNode;
   }
 }
 // Is we are inside an unrolled loop then no need the check the counters.
Index: lib/StaticAnalyzer/Core/AnalysisManager.cpp
===
--- lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -27,7 +27,9 @@
   /*AddInitializers=*/true,
   Options.includeTemporaryDtorsInCFG(),
Options.includeLifetimeInCFG(),
-  Options.includeLoopExitInCFG(),
+  // Adding LoopExit elements to the CFG is a requirement for loop
+  // unrolling.
+  Options.includeLoopExitInCFG() || Options.shouldUnrollLoops(),
   Options.shouldSynthesizeBodies(),
   Options.shouldConditionalizeStaticInitializers(),
   /*addCXXNewAllocator=*/true,


Index: test/Analysis/loop-unrolling.cpp
===
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -272,3 +272,10 @@
   int a = 22 / k;
   return 0;
 }
+
+int loop_exit_while_empty_loop_stack() {
+  if (getNum())
+for (int i = 1; i < 8; i++)
+  ;
+  return 0;
+}
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -13,15 +13,11 @@
 ///
 //===--===//
 
-#include "clang/Analysis/CFGStmtMap.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/AST/StmtVisitor.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
-#include "llvm/ADT/Statistic.h"
 
 using namespace clang;
 using namespace ento;
@@ -72,11 +68,8 @@
 
 ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State) {
   auto LS = State->get();
-  assert(!LS.isEmpty() && "Loop not added to the stack.");
-  assert(LoopStmt == LS.getHead().getLoopStmt() &&
- "Loop is not on top of the stack.");
-
-  State = State->set(LS.getTail());
+  if (!LS.isEmpty() && LS.getHead().getLoopStmt() == 

[PATCH] D37181: {StaticAnalyzer} LoopUnrolling: Keep track the maximum number of steps for each loop

2017-08-26 Thread Peter Szecsi via Phabricator via cfe-commits
szepet created this revision.
Herald added subscribers: baloghadamsoftware, whisperity.

This way the unrolling can be restricted for loops which will take at most a 
given number of steps. It is defined as 128 in this patch and it seems to have 
a good number for that purpose.


https://reviews.llvm.org/D37181

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  test/Analysis/loop-unrolling.cpp

Index: test/Analysis/loop-unrolling.cpp
===
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -5,7 +5,7 @@
 
 int getNum();
 void foo(int &);
-// Testing for loops.
+
 int simple_unroll1() {
   int a[9];
   int k = 42;
@@ -259,7 +259,6 @@
   return 0;
 }
 
-
 int recursion_unroll1(bool b) {
   int k = 2;
   for (int i = 0; i < 5; i++) {
@@ -289,7 +288,7 @@
   int k = 2;
   for (int i = 0; i < 5; i++) {
 clang_analyzer_numTimesReached(); // expected-warning {{10}}
-if(i == 4 && b) {
+if (i == 4 && b) {
   recursion_unroll3(false);
   break;
 }
@@ -319,3 +318,57 @@
   ;
   return 0;
 }
+
+int num_steps_on_limit() {
+  for (int i = 0; i < 128; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{128}}
+  }
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
+  return 0;
+}
+
+int num_steps_over_limit1() {
+  for (int i = 0; i < 129; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+  }
+  return 0;
+}
+
+int num_steps_on_limit2() {
+  for (int i = 0; i < 2; i++) {
+for (int j = 0; j < 64; j++) {
+  clang_analyzer_numTimesReached(); // expected-warning {{128}}
+}
+  }
+  return 0;
+}
+
+int num_steps_over_limit2() {
+  for (int i = 0; i < 2; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{1}}
+for (int j = 0; j <= 64; j++) {
+  clang_analyzer_numTimesReached(); // expected-warning {{4}}
+}
+  }
+  return 0;
+}
+
+int num_steps_on_limit3() {
+  for (int i = 0; i < getNum(); i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+for (int j = 0; j < 32; j++) {
+  clang_analyzer_numTimesReached(); // expected-warning {{128}}
+}
+  }
+  return 0;
+}
+
+int num_steps_over_limit3() {
+  for (int i = 0; i < getNum(); i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{1}}
+for (int j = 0; j < 33; j++) {
+  clang_analyzer_numTimesReached(); // expected-warning {{4}}
+}
+  }
+  return 0;
+}
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -23,22 +23,28 @@
 using namespace ento;
 using namespace clang::ast_matchers;
 
+#define MAXIMUM_STEP_UNROLLED 128
+
 struct LoopState {
 private:
   enum Kind { Normal, Unrolled } K;
   const Stmt *LoopStmt;
   const LocationContext *LCtx;
-  LoopState(Kind InK, const Stmt *S, const LocationContext *L)
-  : K(InK), LoopStmt(S), LCtx(L) {}
+  unsigned maxStep;
+  LoopState(Kind InK, const Stmt *S, const LocationContext *L, unsigned N)
+  : K(InK), LoopStmt(S), LCtx(L), maxStep(N) {}
 
 public:
-  static LoopState getNormal(const Stmt *S, const LocationContext *L) {
-return LoopState(Normal, S, L);
+  static LoopState getNormal(const Stmt *S, const LocationContext *L,
+ unsigned N) {
+return LoopState(Normal, S, L, N);
   }
-  static LoopState getUnrolled(const Stmt *S, const LocationContext *L) {
-return LoopState(Unrolled, S, L);
+  static LoopState getUnrolled(const Stmt *S, const LocationContext *L,
+   unsigned N) {
+return LoopState(Unrolled, S, L, N);
   }
   bool isUnrolled() const { return K == Unrolled; }
+  unsigned getMaxStep() const { return maxStep; }
   const Stmt *getLoopStmt() const { return LoopStmt; }
   const LocationContext *getLocationContext() const { return LCtx; }
   bool operator==(const LoopState ) const {
@@ -48,6 +54,7 @@
 ID.AddInteger(K);
 ID.AddPointer(LoopStmt);
 ID.AddPointer(LCtx);
+ID.AddInteger(maxStep);
   }
 };
 
@@ -74,12 +81,14 @@
 }
 
 static internal::Matcher simpleCondition(StringRef BindName) {
-  return binaryOperator(
-  anyOf(hasOperatorName("<"), hasOperatorName(">"), hasOperatorName("<="),
-hasOperatorName(">="), hasOperatorName("!=")),
-  hasEitherOperand(ignoringParenImpCasts(
-  declRefExpr(to(varDecl(hasType(isInteger())).bind(BindName),
-  hasEitherOperand(ignoringParenImpCasts(integerLiteral(;
+  return binaryOperator(anyOf(hasOperatorName("<"), hasOperatorName(">"),
+  hasOperatorName("<="), hasOperatorName(">="),
+  hasOperatorName("!=")),
+hasEitherOperand(ignoringParenImpCasts(declRefExpr(
+  

[PATCH] D35670: [StaticAnalyzer] Handle LoopExit CFGElement in the analyzer

2017-08-21 Thread Peter Szecsi via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL311344: [StaticAnalyzer] Handle LoopExit CFGElement in the 
analyzer (authored by szepet).

Changed prior to commit:
  https://reviews.llvm.org/D35670?vs=110981=111993#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D35670

Files:
  cfe/trunk/include/clang/Analysis/ProgramPoint.h
  cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp
  cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp

Index: cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -274,7 +274,8 @@
   assert(Loc.getAs() ||
  Loc.getAs() ||
  Loc.getAs() ||
- Loc.getAs());
+ Loc.getAs() ||
+ Loc.getAs());
   HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
   break;
   }
@@ -566,7 +567,8 @@
 
   // Do not create extra nodes. Move to the next CFG element.
   if (N->getLocation().getAs() ||
-  N->getLocation().getAs()) {
+  N->getLocation().getAs()||
+  N->getLocation().getAs()) {
 WList->enqueue(N, Block, Idx+1);
 return;
   }
Index: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -364,8 +364,10 @@
 case CFGElement::TemporaryDtor:
   ProcessImplicitDtor(E.castAs(), Pred);
   return;
-case CFGElement::LifetimeEnds:
 case CFGElement::LoopExit:
+  ProcessLoopExit(E.castAs().getLoopStmt(), Pred);
+  return;
+case CFGElement::LifetimeEnds:
   return;
   }
 }
@@ -510,6 +512,21 @@
   Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
 }
 
+void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) {
+  PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+S->getLocStart(),
+"Error evaluating end of the loop");
+  ExplodedNodeSet Dst;
+  Dst.Add(Pred);
+  NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+
+  LoopExit PP(S, Pred->getLocationContext());
+  Bldr.generateNode(PP, Pred->getState(), Pred);
+
+  // Enqueue the new nodes onto the work list.
+  Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
+}
+
 void ExprEngine::ProcessInitializer(const CFGInitializer Init,
 ExplodedNode *Pred) {
   const CXXCtorInitializer *BMI = Init.getInitializer();
@@ -2689,6 +2706,12 @@
 Out << "Epsilon Point";
 break;
 
+  case ProgramPoint::LoopExitKind: {
+LoopExit LE = Loc.castAs();
+Out << "LoopExit: " << LE.getLoopStmt()->getStmtClassName();
+break;
+  }
+
   case ProgramPoint::PreImplicitCallKind: {
 ImplicitCallPoint PC = Loc.castAs();
 Out << "PreCall: ";
Index: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
===
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -196,6 +196,8 @@
 
   void ProcessStmt(const CFGStmt S, ExplodedNode *Pred);
 
+  void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred);
+
   void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred);
 
   void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred);
Index: cfe/trunk/include/clang/Analysis/ProgramPoint.h
===
--- cfe/trunk/include/clang/Analysis/ProgramPoint.h
+++ cfe/trunk/include/clang/Analysis/ProgramPoint.h
@@ -83,6 +83,7 @@
   PostImplicitCallKind,
   MinImplicitCallKind = PreImplicitCallKind,
   MaxImplicitCallKind = PostImplicitCallKind,
+  LoopExitKind,
   EpsilonKind};
 
 private:
@@ -654,6 +655,29 @@
   }
 };
 
+/// Represents a point when we exit a loop.
+/// When this ProgramPoint is encountered we can be sure that the symbolic
+/// execution of the corresponding LoopStmt is finished on the given path.
+/// Note: It is possible to encounter a LoopExit element when we haven't even
+/// encountered the loop itself. At the current state not all loop exits will
+/// result in a LoopExit program point.
+class LoopExit : public ProgramPoint {
+public:
+LoopExit(const Stmt *LoopStmt, const LocationContext *LC)
+: ProgramPoint(LoopStmt, nullptr, LoopExitKind, LC) {}
+
+const Stmt *getLoopStmt() const {
+  return static_cast(getData1());
+}
+
+private:
+friend class ProgramPoint;
+LoopExit() {}
+static bool isKind(const ProgramPoint ) {
+  return Location.getKind() == LoopExitKind;

[PATCH] D35670: [StaticAnalyzer] Handle LoopExit CFGElement in the analyzer

2017-08-14 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added inline comments.



Comment at: include/clang/Analysis/ProgramPoint.h:658
 
+class LoopExit : public ProgramPoint {
+public:

dcoughlin wrote:
> Can you add a comment explaining what meaning of this program point is.
Can you help me with that? I am not sure what is important to say about this 
point to understand it better than from its name.



Comment at: lib/StaticAnalyzer/Core/CoreEngine.cpp:586
 
+  if ((*Block)[Idx].getKind() == CFGElement::LoopExit) {
+WList->enqueue(N, Block, Idx+1);

dcoughlin wrote:
> I'm surprised both this and the checks for N's location above are needed. How 
> does this arise?
We don't need both of the checks, I just left it by mistake.


https://reviews.llvm.org/D35670



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


[PATCH] D35670: [StaticAnalyzer] Handle LoopExit CFGElement in the analyzer

2017-08-14 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 110981.
szepet marked an inline comment as done.
szepet added a comment.

Updates based on comments.


https://reviews.llvm.org/D35670

Files:
  include/clang/Analysis/ProgramPoint.h
  include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  lib/StaticAnalyzer/Core/CoreEngine.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp

Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -364,8 +364,10 @@
 case CFGElement::TemporaryDtor:
   ProcessImplicitDtor(E.castAs(), Pred);
   return;
-case CFGElement::LifetimeEnds:
 case CFGElement::LoopExit:
+  ProcessLoopExit(E.castAs().getLoopStmt(), Pred);
+  return;
+case CFGElement::LifetimeEnds:
   return;
   }
 }
@@ -510,6 +512,21 @@
   Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
 }
 
+void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) {
+  PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+S->getLocStart(),
+"Error evaluating end of the loop");
+  ExplodedNodeSet Dst;
+  Dst.Add(Pred);
+  NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+
+  LoopExit PP(S, Pred->getLocationContext());
+  Bldr.generateNode(PP, Pred->getState(), Pred);
+
+  // Enqueue the new nodes onto the work list.
+  Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
+}
+
 void ExprEngine::ProcessInitializer(const CFGInitializer Init,
 ExplodedNode *Pred) {
   const CXXCtorInitializer *BMI = Init.getInitializer();
@@ -2689,6 +2706,12 @@
 Out << "Epsilon Point";
 break;
 
+  case ProgramPoint::LoopExitKind: {
+LoopExit LE = Loc.castAs();
+Out << "LoopExit: " << LE.getLoopStmt()->getStmtClassName();
+break;
+  }
+
   case ProgramPoint::PreImplicitCallKind: {
 ImplicitCallPoint PC = Loc.castAs();
 Out << "PreCall: ";
Index: lib/StaticAnalyzer/Core/CoreEngine.cpp
===
--- lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -274,7 +274,8 @@
   assert(Loc.getAs() ||
  Loc.getAs() ||
  Loc.getAs() ||
- Loc.getAs());
+ Loc.getAs() ||
+ Loc.getAs());
   HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
   break;
   }
@@ -566,7 +567,8 @@
 
   // Do not create extra nodes. Move to the next CFG element.
   if (N->getLocation().getAs() ||
-  N->getLocation().getAs()) {
+  N->getLocation().getAs()||
+  N->getLocation().getAs()) {
 WList->enqueue(N, Block, Idx+1);
 return;
   }
Index: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
===
--- include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -196,6 +196,8 @@
 
   void ProcessStmt(const CFGStmt S, ExplodedNode *Pred);
 
+  void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred);
+
   void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred);
 
   void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred);
Index: include/clang/Analysis/ProgramPoint.h
===
--- include/clang/Analysis/ProgramPoint.h
+++ include/clang/Analysis/ProgramPoint.h
@@ -83,6 +83,7 @@
   PostImplicitCallKind,
   MinImplicitCallKind = PreImplicitCallKind,
   MaxImplicitCallKind = PostImplicitCallKind,
+  LoopExitKind,
   EpsilonKind};
 
 private:
@@ -654,6 +655,24 @@
   }
 };
 
+/// Represents a point when we exit a loop.
+class LoopExit : public ProgramPoint {
+public:
+LoopExit(const Stmt *LoopStmt, const LocationContext *LC)
+: ProgramPoint(LoopStmt, nullptr, LoopExitKind, LC) {}
+
+const Stmt *getLoopStmt() const {
+  return static_cast(getData1());
+}
+
+private:
+friend class ProgramPoint;
+LoopExit() {}
+static bool isKind(const ProgramPoint ) {
+  return Location.getKind() == LoopExitKind;
+}
+};
+
 /// This is a meta program point, which should be skipped by all the diagnostic
 /// reasoning etc.
 class EpsilonPoint : public ProgramPoint {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35670: [StaticAnalyzer] Handle LoopExit CFGElement in the analyzer

2017-07-26 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 108312.
szepet added a subscriber: cfe-commits.
szepet added a comment.

Accidentally left debug print removed.


https://reviews.llvm.org/D35670

Files:
  include/clang/Analysis/ProgramPoint.h
  include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  lib/StaticAnalyzer/Core/CoreEngine.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp

Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -364,8 +364,10 @@
 case CFGElement::TemporaryDtor:
   ProcessImplicitDtor(E.castAs(), Pred);
   return;
-case CFGElement::LifetimeEnds:
 case CFGElement::LoopExit:
+  ProcessLoopExit(E.castAs().getLoopStmt(), Pred);
+  return;
+case CFGElement::LifetimeEnds:
   return;
   }
 }
@@ -510,6 +512,21 @@
   Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
 }
 
+void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) {
+  PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+S->getLocStart(),
+"Error evaluating end of the loop");
+  ExplodedNodeSet Dst;
+  Dst.Add(Pred);
+  NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+
+  LoopExit PP(S, Pred->getLocationContext());
+  Bldr.generateNode(PP, Pred->getState(), Pred);
+
+  // Enqueue the new nodes onto the work list.
+  Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
+}
+
 void ExprEngine::ProcessInitializer(const CFGInitializer Init,
 ExplodedNode *Pred) {
   const CXXCtorInitializer *BMI = Init.getInitializer();
@@ -2689,6 +2706,12 @@
 Out << "Epsilon Point";
 break;
 
+  case ProgramPoint::LoopExitKind: {
+LoopExit LE = Loc.castAs();
+Out << "LoopExit: " << LE.getLoopStmt()->getStmtClassName();
+break;
+  }
+
   case ProgramPoint::PreImplicitCallKind: {
 ImplicitCallPoint PC = Loc.castAs();
 Out << "PreCall: ";
Index: lib/StaticAnalyzer/Core/CoreEngine.cpp
===
--- lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -274,7 +274,8 @@
   assert(Loc.getAs() ||
  Loc.getAs() ||
  Loc.getAs() ||
- Loc.getAs());
+ Loc.getAs() ||
+ Loc.getAs());
   HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
   break;
   }
@@ -566,7 +567,8 @@
 
   // Do not create extra nodes. Move to the next CFG element.
   if (N->getLocation().getAs() ||
-  N->getLocation().getAs()) {
+  N->getLocation().getAs()||
+  N->getLocation().getAs()) {
 WList->enqueue(N, Block, Idx+1);
 return;
   }
@@ -581,6 +583,11 @@
 return;
   }
 
+  if ((*Block)[Idx].getKind() == CFGElement::LoopExit) {
+WList->enqueue(N, Block, Idx+1);
+return;
+  }
+
   // At this point, we know we're processing a normal statement.
   CFGStmt CS = (*Block)[Idx].castAs();
   PostStmt Loc(CS.getStmt(), N->getLocationContext());
Index: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
===
--- include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -196,6 +196,8 @@
 
   void ProcessStmt(const CFGStmt S, ExplodedNode *Pred);
 
+  void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred);
+
   void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred);
 
   void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred);
Index: include/clang/Analysis/ProgramPoint.h
===
--- include/clang/Analysis/ProgramPoint.h
+++ include/clang/Analysis/ProgramPoint.h
@@ -83,6 +83,7 @@
   PostImplicitCallKind,
   MinImplicitCallKind = PreImplicitCallKind,
   MaxImplicitCallKind = PostImplicitCallKind,
+  LoopExitKind,
   EpsilonKind};
 
 private:
@@ -654,6 +655,23 @@
   }
 };
 
+class LoopExit : public ProgramPoint {
+public:
+LoopExit(const Stmt *LoopStmt, const LocationContext *LC)
+: ProgramPoint(LoopStmt, nullptr, LoopExitKind, LC) {}
+
+const Stmt *getLoopStmt() const {
+  return static_cast(getData1());
+}
+
+private:
+LoopExit() {}
+friend class ProgramPoint;
+static bool isKind(const ProgramPoint ) {
+  return Location.getKind() == LoopExitKind;
+}
+};
+
 /// This is a meta program point, which should be skipped by all the diagnostic
 /// reasoning etc.
 class EpsilonPoint : public ProgramPoint {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34260: [StaticAnalyzer] Completely unrolling specific loops with known bound option

2017-07-26 Thread Peter Szecsi via Phabricator via cfe-commits
szepet closed this revision.
szepet added a comment.

So the fixes seem to work. The problem was the line 'StackFrame = 
StackFrame->getParent()->getCurrentStackFrame();' since I havent checked if the 
parent of the StackFrame is nullptr. (It is quite interesting that it just not 
crashed on my computer.)


https://reviews.llvm.org/D34260



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


[PATCH] D34260: [StaticAnalyzer] Completely unrolling specific loops with known bound option

2017-07-26 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

In https://reviews.llvm.org/D34260#821186, @teemperor wrote:

> Try fixing this invalid read and the buildbots (and my builds :) ) should be 
> working again.


Yeah, thanks for the help! :)
I already sent a fix for that: https://reviews.llvm.org/rL309036 and another 
one: https://reviews.llvm.org/rL309061 which I think was not necessary but the 
buildbot failed on the first try (I still think it just haven't picked up the 
commit)
For me it seems that these fixes solved the problem as the address sanitizer 
tests passes as well on clang (and nobody reverted the commits^^).


https://reviews.llvm.org/D34260



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


[PATCH] D34260: [StaticAnalyzer] Completely unrolling specific loops with known bound option

2017-07-25 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

In https://reviews.llvm.org/D34260#819721, @NoQ wrote:

> ...  and add the extra run-line that'd show you the backtrace. We made 
> changes, so the issue might have been wiped out accidentally (or maybe you're 
> actually right!), and if it wasn't, at least we'd have the backtrace for the 
> crash.


Hmm I removed the statistics checks so I guess it should print the stacktrace 
in case of a crash anyway. Am I right? (The whole point of the statistics check 
was to count the number of loops unrolled but  
'clang_analyzer_numTimesReached();' is much more powerful.


https://reviews.llvm.org/D34260



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


[PATCH] D34260: [StaticAnalyzer] Completely unrolling specific loops with known bound option

2017-07-24 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 107976.
szepet added a subscriber: cfe-commits.
szepet added a comment.

Accidentally left typo removed.
OK so I am not sure but am I allowed to commit it again? I mean I made some 
notable changes. Not on the functionality of the feature but the stored data.
So should i wait for a quick review or could I commit it right now? (It is 
something that would be useful to know for future commits too.)


https://reviews.llvm.org/D34260

Files:
  include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
  include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
  lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
  lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
  lib/StaticAnalyzer/Core/CMakeLists.txt
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  test/Analysis/analyzer-config.c
  test/Analysis/analyzer-config.cpp
  test/Analysis/loop-unrolling.cpp

Index: test/Analysis/loop-unrolling.cpp
===
--- /dev/null
+++ test/Analysis/loop-unrolling.cpp
@@ -0,0 +1,176 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config unroll-loops=true -analyzer-stats -verify -std=c++11 %s
+
+void clang_analyzer_numTimesReached();
+
+int getNum();
+void foo(int &);
+// Testing for loops.
+int simple_unroll1() {
+  int a[9];
+  int k = 42;
+  for (int i = 0; i < 9; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{9}}
+a[i] = 42;
+  }
+  int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+  return 0;
+}
+
+int simple_unroll2() {
+  int a[9];
+  int k = 42;
+  int i;
+  for (i = 0; i < 9; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{9}}
+a[i] = 42;
+  }
+  int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+  return 0;
+}
+
+int simple_no_unroll1() {
+  int a[9];
+  int k = 42;
+  for (int i = 0; i < 9; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+a[i] = 42;
+foo(i);
+  }
+  int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+  return 0;
+}
+
+int simple_no_unroll2() {
+  int a[9];
+  int k = 42;
+  int i;
+  for (i = 0; i < 9; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+a[i] = 42;
+i += getNum();
+  }
+  int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+  return 0;
+}
+
+int simple_no_unroll3() {
+  int a[9];
+  int k = 42;
+  int i;
+  for (i = 0; i < 9; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+a[i] = 42;
+(void)
+  }
+  int b = 22 / (k - 42); // no-warning
+  return 0;
+}
+
+int simple_no_unroll4() {
+  int a[9];
+  int k = 42;
+  int i;
+  for (i = 0; i < 9; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+a[i] = 42;
+int  = i;
+  }
+  int b = 22 / (k - 42); // no-warning
+  return 0;
+}
+
+int simple_no_unroll5() {
+  int a[9];
+  int k = 42;
+  int i;
+  for (i = 0; i < 9; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+a[i] = 42;
+int {i};
+  }
+  int b = 22 / (k - 42); // no-warning
+  return 0;
+}
+
+int nested_outer_unrolled() {
+  int a[9];
+  int k = 42;
+  int j = 0;
+  for (int i = 0; i < 9; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{16}}
+for (j = 0; j < getNum(); ++j) {
+  clang_analyzer_numTimesReached(); // expected-warning {{15}}
+  a[j] = 22;
+}
+a[i] = 42;
+  }
+  int b = 22 / (k - 42); // no-warning
+  return 0;
+}
+
+int nested_inner_unrolled() {
+  int a[9];
+  int k = 42;
+  int j = 0;
+  for (int i = 0; i < getNum(); i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{4}}
+for (j = 0; j < 8; ++j) {
+  clang_analyzer_numTimesReached(); // expected-warning {{32}}
+  a[j] = 22;
+}
+a[i] = 42;
+  }
+  int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+  return 0;
+}
+
+int nested_both_unrolled() {
+  int a[9];
+  int k = 42;
+  int j = 0;
+  for (int i = 0; i < 7; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{7}}
+for (j = 0; j < 6; ++j) {
+  clang_analyzer_numTimesReached(); // expected-warning {{42}}
+  a[j] = 22;
+}
+a[i] = 42;
+  }
+  int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+  return 0;
+}
+
+int simple_known_bound_loop() {
+  for (int i = 2; i < 12; i++) {
+// This function is inlined in nested_inlined_unroll1()
+clang_analyzer_numTimesReached(); // expected-warning {{90}}
+  }
+  return 0;
+}
+
+int simple_unknown_bound_loop() {
+  for (int i = 2; i < getNum(); i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{10}}
+  }
+  return 0;
+}
+
+int nested_inlined_unroll1() {
+  int k;
+  for (int i = 0; i < 9; i++) {
+clang_analyzer_numTimesReached(); // expected-warning {{9}}
+k = simple_known_bound_loop();// no reevaluation without inlining
+  }
+  int a = 22 / k; // 

[PATCH] D16403: Add scope information to CFG for If/While/For/Do/Compound/CXXRangeFor statements

2017-07-13 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

Hello Maxim!
Thanks for working on this!

> Ugh, yeah, SwitchStmt is tricky (thank you for pointing to Duff's device 
> example!). I've tried to resolve several issues with switch revealed by this 
> testcase, but didn't succeed for now :(. So, it was decided to remove 
> SwitchStmt support in this patch.

I think this is a great decision! It can build up incremental and the patch can 
be more easily reviewed. When do you plan to upload a patch wihtout casestmt 
support? (As far as I see there is switchstmt related code but maybe Im missing 
something.)


Repository:
  rL LLVM

https://reviews.llvm.org/D16403



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


[PATCH] D32751: [ASTImporter] Support new kinds of declarations (mostly Using*)

2017-05-28 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

Some nits added, other than these it looks good to me.  Thank you!
Just more one question, I can see 3 different cases how the import returns are 
handled:

- if(!ToDecl) return nullptr;
- if(!ToDecl && FromDecl) return nullptr;
- no handling: ObjectXY::Create(...Import(FromDecl))

My question is the following: which cases require a check and which decls can 
be imported without checking the return value of the **import **function?
(Yepp, it could be asked in more general about the Importer, since things like 
this would be great to follow a convention. I have found some cases where it 
was not obivous to me which way to check. )




Comment at: lib/AST/ASTImporter.cpp:2993
+  return nullptr;
+  }
+

nit: As I see these cases typically handled in the way:

```
FrPattern = .;
ToPattern = ..;
if(FrPattern && !ToPattern)
```
Just to avoid the nested ifstmt.



Comment at: lib/AST/ASTImporter.cpp:3000
+else
+  // FIXME: We return a nullptr here but the definition is already created
+  // and available with lookups. How to fix this?..

I dont see the problem with moving these up , collect nad investigate them in a 
smallset before the Create function, then adding them to the created ToUsing 
decl. It could be done as a follow up patch, dont want to mark it as a blocking 
issue.



Comment at: lib/AST/ASTImporter.cpp:3042
+  return nullptr;
+  }
+

the same nit as above



Comment at: lib/AST/ASTImporter.cpp:3043
+  }
+
+  LexicalDC->addDeclInternal(ToShadow);

Does not this causes the same FIXME problem as above?


https://reviews.llvm.org/D32751



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


[PATCH] D32751: [ASTImporter] Support new kinds of declarations (mostly Using*)

2017-05-16 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added inline comments.



Comment at: lib/AST/ASTImporter.cpp:1464
+
+  NamespaceDecl *TargetDecl = cast(
+Importer.Import(D->getNamespace()));

Since the Import can result nullptr (which is checked 2 lines below) this 
should be a cast_or_null as I see.


https://reviews.llvm.org/D32751



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


[PATCH] D31538: [analyzer] MisusedMovedObjectChecker: Fix a false positive on state-resetting a base-class sub-object.

2017-04-15 Thread Peter Szecsi via Phabricator via cfe-commits
szepet accepted this revision.
szepet added inline comments.
This revision is now accepted and ready to land.



Comment at: lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp:426
+
+State = State->remove(WholeObjectRegion);
 C.addTransition(State);

szepet wrote:
> szepet wrote:
> > I am wondering if I made a mistake but I think this should be 
> > removeFromState() function call. (We should remove every marked subregions 
> > of the object too.)
> > So I suspect a code like this would result a false positive:
> > ```
> > struct A{
> > B b;
> > void clear();
> > };
> > 
> > void test(){
> > A a;
> > B b = std::move(a.b);
> > a.clear();
> > b = std::move(a); //report a bug
> > }
> > ```
> > 
> > I mean it is probably a report we do not want to have.
> Shame on the test file writer that he does not covered this, though. ^^
Okay, I have checked it and yes, it produces a bugreport (false positive) on 
the code snippet above (which contains a misspelled variable name so let me 
write it again):

```
struct B{};

struct A{
B b;
void clear();
};

void test(){
A a;
B b = std::move(a.b);
a.clear();
b = std::move(a.b); //report a bug
}
```

In order to eliminate these type of bugs I suggest using here the 
removeFromState function and move this "WholeObjectRegion algorithm" (the for 
loop) to the removeFromState function.
It is probably out of scope from this patch. Anyway, I accept this since it is 
great to fix this bug and a good step to a follow-up patch. (Well, if you would 
like to make these changes in this patch. I'm not gonna hold you back. It is 
highly appreciated and I would certainly review and all the stuff but I would 
do it gladly in a follow-up too.) 
Again, thank you for pointing this out and making the checker more precise!


https://reviews.llvm.org/D31538



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


[PATCH] D31541: [analyzer] MisusedMovedObjectChecker: Add a printState() method.

2017-03-31 Thread Peter Szecsi via Phabricator via cfe-commits
szepet accepted this revision.
szepet added a comment.
This revision is now accepted and ready to land.

LGTM, thank you (again)!


https://reviews.llvm.org/D31541



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


[PATCH] D31538: [analyzer] MisusedMovedObjectChecker: Fix a false positive on state-resetting a base-class sub-object.

2017-03-31 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added inline comments.



Comment at: lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp:426
+
+State = State->remove(WholeObjectRegion);
 C.addTransition(State);

szepet wrote:
> I am wondering if I made a mistake but I think this should be 
> removeFromState() function call. (We should remove every marked subregions of 
> the object too.)
> So I suspect a code like this would result a false positive:
> ```
> struct A{
> B b;
> void clear();
> };
> 
> void test(){
> A a;
> B b = std::move(a.b);
> a.clear();
> b = std::move(a); //report a bug
> }
> ```
> 
> I mean it is probably a report we do not want to have.
Shame on the test file writer that he does not covered this, though. ^^


https://reviews.llvm.org/D31538



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


[PATCH] D31538: [analyzer] MisusedMovedObjectChecker: Fix a false positive on state-resetting a base-class sub-object.

2017-03-31 Thread Peter Szecsi via Phabricator via cfe-commits
szepet added a comment.

Thank you for working on that, Artem!
The changes look good, just one comment about that suspicious remove.




Comment at: lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp:426
+
+State = State->remove(WholeObjectRegion);
 C.addTransition(State);

I am wondering if I made a mistake but I think this should be removeFromState() 
function call. (We should remove every marked subregions of the object too.)
So I suspect a code like this would result a false positive:
```
struct A{
B b;
void clear();
};

void test(){
A a;
B b = std::move(a.b);
a.clear();
b = std::move(a); //report a bug
}
```

I mean it is probably a report we do not want to have.


https://reviews.llvm.org/D31538



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


[PATCH] D22507: Clang-tidy - Enum misuse check

2016-12-25 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 82488.
szepet marked 6 inline comments as done.
szepet added a comment.

The requested changes have been made.
Some more refactor on the Case2 since it is the same as the LHS/RHS case. Moved 
more common statements out of the branch (Case2-3) for better readabilty. (And 
less code duplication.)


https://reviews.llvm.org/D22507

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
  clang-tidy/misc/SuspiciousEnumUsageCheck.h
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-suspicious-enum-usage.rst
  test/clang-tidy/misc-suspicious-enum-usage-strict.cpp
  test/clang-tidy/misc-suspicious-enum-usage.cpp

Index: test/clang-tidy/misc-suspicious-enum-usage.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-suspicious-enum-usage.cpp
@@ -0,0 +1,90 @@
+// RUN: %check_clang_tidy %s misc-suspicious-enum-usage %t -- -config="{CheckOptions: [{key: misc-suspicious-enum-usage.StrictMode, value: 0}]}" --
+
+enum Empty {
+};
+
+enum A {
+  A = 1,
+  B = 2,
+  C = 4,
+  D = 8,
+  E = 16,
+  F = 32,
+  G = 63
+};
+
+enum X {
+  X = 8,
+  Y = 16,
+  Z = 4
+};
+
+enum {
+  P = 2,
+  Q = 3,
+  R = 4,
+  S = 8,
+  T = 16
+};
+
+enum {
+  H,
+  I,
+  J,
+  K,
+  L
+};
+
+enum Days {
+  Monday,
+  Tuesday,
+  Wednesday,
+  Thursday,
+  Friday,
+  Saturday,
+  Sunday
+};
+
+Days bestDay() {
+  return Friday;
+}
+
+int trigger() {
+  Empty EmptyVal;
+  int emptytest = EmptyVal | B;
+  if (bestDay() | A)
+return 1;
+  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different enum types 
+  if (I | Y)
+return 1;
+  // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different enum types
+}
+
+int dont_trigger() {
+  unsigned p;
+  p = Q | P;
+
+  if (A + G == E)
+return 1;
+  else if ((Q | R) == T)
+return 1;
+  else
+int k = T | Q;
+
+  Empty EmptyVal;
+  int emptytest = EmptyVal | B;
+
+  int a = 1, b = 5;
+  int c = a + b;
+  int d = c | H, e = b * a;
+  a = B | C;
+  b = X | Z;
+  
+  if (Tuesday != Monday + 1 ||
+  Friday - Thursday != 1 ||
+  Sunday + Wednesday == (Sunday | Wednesday))
+return 1;
+  if (H + I + L == 42)
+return 1;
+  return 42;
+}
Index: test/clang-tidy/misc-suspicious-enum-usage-strict.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-suspicious-enum-usage-strict.cpp
@@ -0,0 +1,98 @@
+// RUN: %check_clang_tidy %s misc-suspicious-enum-usage %t -- -config="{CheckOptions: [{key: misc-suspicious-enum-usage.StrictMode, value: 1}]}" --
+
+enum A {
+  A = 1,
+  B = 2,
+  C = 4,
+  D = 8,
+  E = 16,
+  F = 32,
+  G = 63
+};
+
+// CHECK-MESSAGES: :[[@LINE+2]]:1: warning: enum type seems like a bitmask (contains mostly power-of-2 literals) but a literal is not power-of-2
+// CHECK-MESSAGES: :76:7: note: used here as a bitmask
+enum X {
+  X = 8,
+  Y = 16,
+  Z = 4,
+  ZZ = 3
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: enum type seems like a bitmask (contains mostly power-of-2 literals), but this literal is not a power-of-2 [misc-suspicious-enum-usage]
+// CHECK-MESSAGES: :70:13: note: used here as a bitmask
+};
+// CHECK-MESSAGES: :[[@LINE+2]]:1: warning: enum type seems like a bitmask (contains mostly power-of-2 literals) but some literals are not power-of-2
+// CHECK-MESSAGES: :73:8: note: used here as a bitmask
+enum PP {
+  P = 2,
+  Q = 3,
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: enum type seems like a bitmask (contains mostly power-of-2 literals), but this literal is not a power-of-2
+  // CHECK-MESSAGES: :65:11: note: used here as a bitmask
+  R = 4,
+  S = 8,
+  T = 16,
+  U = 31
+};
+
+enum {
+  H,
+  I,
+  J,
+  K,
+  L
+};
+
+enum Days {
+  Monday,
+  Tuesday,
+  Wednesday,
+  Thursday,
+  Friday,
+  Saturday,
+  Sunday
+};
+
+Days bestDay() {
+  return Friday;
+}
+
+int trigger() {
+  if (bestDay() | A)
+return 1;
+  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different enum types
+  if (I | Y)
+return 1;
+  // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different enum types
+  if (P + Q == R)
+return 1;
+  else if ((Q | R) == T)
+return 1;
+  else
+int k = ZZ | Z;
+  unsigned p = R;
+  PP pp = Q;
+  p |= pp;
+  
+  enum X x = Z;
+  p = x | ZZ;
+  return 0;
+}
+
+int dont_trigger() {
+  int a = 1, b = 5;
+  int c = a + b;
+  int d = c | H, e = b * a;
+  a = B | C;
+  b = X | Z;
+
+  unsigned bitflag;
+  enum A aa = B;
+  bitflag = aa | C;
+
+  if (Tuesday != Monday + 1 ||
+  Friday - Thursday != 1 ||
+  Sunday + Wednesday == (Sunday | Wednesday))
+return 1;
+  if (H + I + L == 42)
+return 1;
+  return 42;
+}
Index: docs/clang-tidy/checks/misc-suspicious-enum-usage.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-suspicious-enum-usage.rst
@@ -0,0 

[PATCH] D22507: Clang-tidy - Enum misuse check

2016-12-17 Thread Peter Szecsi via Phabricator via cfe-commits
szepet updated this revision to Diff 81848.
szepet added a comment.
Herald added a subscriber: JDevlieghere.

Minor changes to improve the readability of the code according to comments.


https://reviews.llvm.org/D22507

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/SuspiciousEnumUsageCheck.cpp
  clang-tidy/misc/SuspiciousEnumUsageCheck.h
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-suspicious-enum-usage.rst
  test/clang-tidy/misc-suspicious-enum-usage-strict.cpp
  test/clang-tidy/misc-suspicious-enum-usage.cpp

Index: test/clang-tidy/misc-suspicious-enum-usage.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-suspicious-enum-usage.cpp
@@ -0,0 +1,90 @@
+// RUN: %check_clang_tidy %s misc-suspicious-enum-usage %t -- -config="{CheckOptions: [{key: misc-suspicious-enum-usage.StrictMode, value: 0}]}" --
+
+enum Empty {
+};
+
+enum A {
+  A = 1,
+  B = 2,
+  C = 4,
+  D = 8,
+  E = 16,
+  F = 32,
+  G = 63
+};
+
+enum X {
+  X = 8,
+  Y = 16,
+  Z = 4
+};
+
+enum {
+  P = 2,
+  Q = 3,
+  R = 4,
+  S = 8,
+  T = 16
+};
+
+enum {
+  H,
+  I,
+  J,
+  K,
+  L
+};
+
+enum Days {
+  Monday,
+  Tuesday,
+  Wednesday,
+  Thursday,
+  Friday,
+  Saturday,
+  Sunday
+};
+
+Days bestDay() {
+  return Friday;
+}
+
+int trigger() {
+  Empty EmptyVal;
+  int emptytest = EmptyVal | B;
+  if (bestDay() | A)
+return 1;
+  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different enum types 
+  if (I | Y)
+return 1;
+  // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different enum types
+}
+
+int dont_trigger() {
+  unsigned p;
+  p = Q | P;
+
+  if (A + G == E)
+return 1;
+  else if ((Q | R) == T)
+return 1;
+  else
+int k = T | Q;
+
+  Empty EmptyVal;
+  int emptytest = EmptyVal | B;
+
+  int a = 1, b = 5;
+  int c = a + b;
+  int d = c | H, e = b * a;
+  a = B | C;
+  b = X | Z;
+  
+  if (Tuesday != Monday + 1 ||
+  Friday - Thursday != 1 ||
+  Sunday + Wednesday == (Sunday | Wednesday))
+return 1;
+  if (H + I + L == 42)
+return 1;
+  return 42;
+}
Index: test/clang-tidy/misc-suspicious-enum-usage-strict.cpp
===
--- /dev/null
+++ test/clang-tidy/misc-suspicious-enum-usage-strict.cpp
@@ -0,0 +1,94 @@
+// RUN: %check_clang_tidy %s misc-suspicious-enum-usage %t -- -config="{CheckOptions: [{key: misc-suspicious-enum-usage.StrictMode, value: 1}]}" --
+
+enum A {
+  A = 1,
+  B = 2,
+  C = 4,
+  D = 8,
+  E = 16,
+  F = 32,
+  G = 63
+};
+
+enum X {
+  X = 8,
+  Y = 16,
+  Z = 4,
+  ZZ = 3
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: enum type seems like a bitmask (contains mostly power-of-2 literals), but this literal is not a power-of-2 [misc-suspicious-enum-usage]
+// CHECK-MESSAGES: :68:13: note: used here as a bitmask
+};
+// CHECK-MESSAGES: :[[@LINE+2]]:1: warning: enum type seems like a bitmask (contains mostly power-of-2 literals) but some literal(s) are not a power-of-2
+  // CHECK-MESSAGES: :71:8: note: used here as a bitmask
+enum PP {
+  P = 2,
+  Q = 3,
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: enum type seems like a bitmask (contains mostly power-of-2 literals), but this literal is not a power-of-2
+  // CHECK-MESSAGES: :63:7: note: used here as a bitmask
+  R = 4,
+  S = 8,
+  T = 16,
+  U = 31
+};
+
+enum {
+  H,
+  I,
+  J,
+  K,
+  L
+};
+
+enum Days {
+  Monday,
+  Tuesday,
+  Wednesday,
+  Thursday,
+  Friday,
+  Saturday,
+  Sunday
+};
+
+Days bestDay() {
+  return Friday;
+}
+
+int trigger() {
+  if (bestDay() | A)
+return 1;
+  // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different enum types
+  if (I | Y)
+return 1;
+  // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different enum types
+  if (P + Q == R)
+return 1;
+  else if ((Q | R) == T)
+return 1;
+  else
+int k = ZZ | Z;
+  unsigned p = R;
+  PP pp = Q;
+  p |= pp;
+  p = A | G;
+  return 0;
+}
+
+int dont_trigger() {
+  int a = 1, b = 5;
+  int c = a + b;
+  int d = c | H, e = b * a;
+  a = B | C;
+  b = X | Z;
+
+  unsigned bitflag;
+  enum A aa = B;
+  bitflag = aa | C;
+
+  if (Tuesday != Monday + 1 ||
+  Friday - Thursday != 1 ||
+  Sunday + Wednesday == (Sunday | Wednesday))
+return 1;
+  if (H + I + L == 42)
+return 1;
+  return 42;
+}
Index: docs/clang-tidy/checks/misc-suspicious-enum-usage.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/misc-suspicious-enum-usage.rst
@@ -0,0 +1,80 @@
+.. title:: clang-tidy - misc-suspicious-enum-usage
+
+misc-suspicious-enum-usage
+==
+
+The checker detects various cases when an enum is probably misused (as a bitmask
+).
+  
+1. When "ADD" or "bitwise OR" is used between two enum which come from different
+   types and these types value ranges are not disjoint.
+
+The following 

  1   2   >