[clang] [-Wcompletion-handler] Fix a non-termination issue (PR #78380)

2024-01-25 Thread Valeriy Savchenko via cfe-commits

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

Awesome! Thank you for fixing the problem and for describing it so in detail. 

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


[clang] [-Wcompletion-handler] Fix a non-termination issue (PR #78380)

2024-01-17 Thread Valeriy Savchenko via cfe-commits

SavchenkoValeriy wrote:

Hey @ziqingluo-90, thank you for such a detailed description of the problem. It 
helped me to get up to speed quickly.  
However, I must say that I find this change too intrusive a this point, while 
not being 100% convinced that it is necessary.

Considering these rules (even be it for joining multiple paths), we shouldn't 
override `Reported` with `Escaped`. At the same time, we do that within a 
single block thanks to this code:
https://github.com/llvm/llvm-project/blob/5fcf907b34355980f77d7665a175b05fea7a6b7b/clang/lib/Analysis/CalledOnceCheck.cpp#L935
We do consider `Reported` to be an error state, and overwrite it. Maybe 
changing this logic and excluding `Reported` from that condition (i.e. 
`x.isErrorStatus() && x != Reported`) is the way to go? The reason for that is 
that we already found a problem on that path and the fact that it escaped 
before it shouldn't affect our conclusion. Another reason is more formal, 
`Reported` is supposed to be a top element of the lattice and this logic defies 
it.

Thanks again!

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


[clang] 9e02f58 - [analyzer] Highlight arrows for currently selected event

2021-08-02 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-08-02T19:15:01+03:00
New Revision: 9e02f58780ab8734e5d27a0138bd477d18ae64a1

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

LOG: [analyzer] Highlight arrows for currently selected event

In some cases, when the execution path of the diagnostic
goes back and forth, arrows can overlap and create a mess.
Dimming arrows that are not relevant at the moment, solves this issue.
They are still visible, but don't draw too much attention.

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

Added: 


Modified: 
clang/lib/Rewrite/HTMLRewrite.cpp
clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
clang/test/Analysis/html_diagnostics/control-arrows.cpp

Removed: 




diff  --git a/clang/lib/Rewrite/HTMLRewrite.cpp 
b/clang/lib/Rewrite/HTMLRewrite.cpp
index 496b8c575dfcb..371557a624c9c 100644
--- a/clang/lib/Rewrite/HTMLRewrite.cpp
+++ b/clang/lib/Rewrite/HTMLRewrite.cpp
@@ -392,7 +392,7 @@ h1 { font-size:14pt }
 .CodeInsertionHint { font-weight: bold; background-color: #10dd10 }
 .CodeRemovalHint { background-color:#de1010 }
 .CodeRemovalHint { border-bottom:1px solid #6F9DBE }
-.selected{ background-color:orange !important; }
+.msg.selected{ background-color:orange !important; }
 
 table.simpletable {
   padding: 5px;

diff  --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp 
b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index f301378c02d6c..3ee12c0bdf651 100644
--- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -27,6 +27,7 @@
 #include "clang/Rewrite/Core/Rewriter.h"
 #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Sequence.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
@@ -58,6 +59,8 @@ using namespace ento;
 
 namespace {
 
+class ArrowMap;
+
 class HTMLDiagnostics : public PathDiagnosticConsumer {
   PathDiagnosticConsumerOptions DiagOpts;
   std::string Directory;
@@ -119,7 +122,8 @@ class HTMLDiagnostics : public PathDiagnosticConsumer {
   }
 
 private:
-  void addArrowSVGs(Rewriter , FileID BugFileID, unsigned NumberOfArrows);
+  void addArrowSVGs(Rewriter , FileID BugFileID,
+const ArrowMap );
 
   /// \return Javascript for displaying shortcuts help;
   StringRef showHelpJavascript();
@@ -150,6 +154,20 @@ unsigned getPathSizeWithoutArrows(const PathPieces ) {
   return TotalPieces - TotalArrowPieces;
 }
 
+class ArrowMap : public std::vector {
+  using Base = std::vector;
+
+public:
+  ArrowMap(unsigned Size) : Base(Size, 0) {}
+  unsigned getTotalNumberOfArrows() const { return at(0); }
+};
+
+llvm::raw_ostream <<(llvm::raw_ostream , const ArrowMap ) {
+  OS << "[ ";
+  llvm::interleave(Indices, OS, ",");
+  return OS << " ]";
+}
+
 } // namespace
 
 void ento::createHTMLDiagnosticConsumer(
@@ -761,6 +779,7 @@ void HTMLDiagnostics::RewriteFile(Rewriter , const 
PathPieces ,
   unsigned NumberOfArrows = 0;
   // Stores the count of the regular piece indices.
   std::map IndexMap;
+  ArrowMap ArrowIndices(TotalRegularPieces + 1);
 
   // Stores the 
diff erent ranges where we have reported something.
   std::vector PopUpRanges;
@@ -779,13 +798,30 @@ void HTMLDiagnostics::RewriteFile(Rewriter , const 
PathPieces ,
 } else if (isArrowPiece(Piece)) {
   NumberOfArrows = ProcessControlFlowPiece(
   R, FID, cast(Piece), NumberOfArrows);
+  ArrowIndices[NumRegularPieces] = NumberOfArrows;
 
 } else {
   HandlePiece(R, FID, Piece, PopUpRanges, NumRegularPieces,
   TotalRegularPieces);
   --NumRegularPieces;
+  ArrowIndices[NumRegularPieces] = ArrowIndices[NumRegularPieces + 1];
 }
   }
+  ArrowIndices[0] = NumberOfArrows;
+
+  // At this point ArrowIndices represent the following data structure:
+  //   [a_0, a_1, ..., a_N]
+  // where N is the number of events in the path.
+  //
+  // Then for every event with index i \in [0, N - 1], we can say that
+  // arrows with indices \in [a_(i+1), a_i) correspond to that event.
+  // We can say that because arrows with these indices appeared in the
+  // path in between the i-th and the (i+1)-th events.
+  assert(ArrowIndices.back() == 0 &&
+ "No arrows should be after the last event");
+  // This assertion also guarantees that all indices in are <= NumberOfArrows.
+  assert(llvm::is_sorted(ArrowIndices, std::greater()) &&
+ "Incorrect arrow indices map");
 
   // Secondary indexing if we are having multiple pop-ups between two notes.
   // (e.g. [(13) 'a' is 'true'];  [(13.1) 'b' is 'false'];  [(13.2) 'c' is...)
@@ -819,7 +855,7 @@ void HTMLDiagnostics::RewriteFile(Rewriter , const 
PathPieces ,
   

[clang] 97bcafa - [analyzer] Add control flow arrows to the analyzer's HTML reports

2021-08-02 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-08-02T19:15:00+03:00
New Revision: 97bcafa28deb95ad32f83fe339d78454d899ca1b

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

LOG: [analyzer] Add control flow arrows to the analyzer's HTML reports

This commit adds a very first version of this feature.
It is off by default and has to be turned on by checking the
corresponding box.  For this reason, HTML reports still keep
control notes (aka grey bubbles).

Further on, we plan on attaching arrows to events and having all arrows
not related to a currently selected event barely visible.  This will
help with reports where control flow goes back and forth (eg in loops).
Right now, it can get pretty crammed with all the arrows.

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

Added: 
clang/test/Analysis/html_diagnostics/control-arrows.cpp

Modified: 
clang/include/clang/Analysis/PathDiagnostic.h
clang/lib/Rewrite/HTMLRewrite.cpp
clang/lib/StaticAnalyzer/Core/BugReporter.cpp
clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/PathDiagnostic.h 
b/clang/include/clang/Analysis/PathDiagnostic.h
index 539aa20b81682..04bef1fa5334d 100644
--- a/clang/include/clang/Analysis/PathDiagnostic.h
+++ b/clang/include/clang/Analysis/PathDiagnostic.h
@@ -151,11 +151,14 @@ class PathDiagnosticConsumer {
 /// Only runs visitors, no output generated.
 None,
 
-/// Used for HTML, SARIF, and text output.
+/// Used for SARIF and text output.
 Minimal,
 
 /// Used for plist output, used for "arrows" generation.
 Extensive,
+
+/// Used for HTML, shows both "arrows" and control notes.
+Everything
   };
 
   virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
@@ -164,7 +167,11 @@ class PathDiagnosticConsumer {
 return getGenerationScheme() != None;
   }
 
-  bool shouldAddPathEdges() const { return getGenerationScheme() == Extensive; 
}
+  bool shouldAddPathEdges() const { return getGenerationScheme() >= Extensive; 
}
+  bool shouldAddControlNotes() const {
+return getGenerationScheme() == Minimal ||
+   getGenerationScheme() == Everything;
+  }
 
   virtual bool supportsLogicalOpControlFlow() const { return false; }
 

diff  --git a/clang/lib/Rewrite/HTMLRewrite.cpp 
b/clang/lib/Rewrite/HTMLRewrite.cpp
index 2f5f2734aa46b..496b8c575dfcb 100644
--- a/clang/lib/Rewrite/HTMLRewrite.cpp
+++ b/clang/lib/Rewrite/HTMLRewrite.cpp
@@ -371,6 +371,7 @@ h1 { font-size:14pt }
 .msg { border-radius:5px }
 .msg { font-family:Helvetica, sans-serif; font-size:8pt }
 .msg { float:left }
+.msg { position:relative }
 .msg { padding:0.25em 1ex 0.25em 1ex }
 .msg { margin-top:10px; margin-bottom:10px }
 .msg { font-weight:bold }

diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
index d6f69ae03afe5..da441dcdf0183 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -188,6 +188,9 @@ class PathDiagnosticConstruct {
   PathPieces () { return PD->getMutablePieces(); }
 
   bool shouldAddPathEdges() const { return Consumer->shouldAddPathEdges(); }
+  bool shouldAddControlNotes() const {
+return Consumer->shouldAddControlNotes();
+  }
   bool shouldGenerateDiagnostics() const {
 return Consumer->shouldGenerateDiagnostics();
   }
@@ -1232,8 +1235,11 @@ void 
PathDiagnosticBuilder::generatePathDiagnosticsForNode(
 
   } else if (auto BE = P.getAs()) {
 
-if (!C.shouldAddPathEdges()) {
+if (C.shouldAddControlNotes()) {
   generateMinimalDiagForBlockEdge(C, *BE);
+}
+
+if (!C.shouldAddPathEdges()) {
   return;
 }
 
@@ -1254,12 +1260,14 @@ void 
PathDiagnosticBuilder::generatePathDiagnosticsForNode(
   // do-while statements are explicitly excluded here
 
   auto p = std::make_shared(
-  L, "Looping back to the head "
-  "of the loop");
+  L, "Looping back to the head of the loop");
   p->setPrunable(true);
 
   addEdgeToPath(C.getActivePath(), PrevLoc, p->getLocation());
-  C.getActivePath().push_front(std::move(p));
+  // We might've added a very similar control node already
+  if (!C.shouldAddControlNotes()) {
+C.getActivePath().push_front(std::move(p));
+  }
 
   if (const auto *CS = dyn_cast_or_null(Body)) {
 addEdgeToPath(C.getActivePath(), PrevLoc,
@@ -1300,10 +1308,14 @@ void 
PathDiagnosticBuilder::generatePathDiagnosticsForNode(
   auto PE = std::make_shared(L, str);
   PE->setPrunable(true);
   addEdgeToPath(C.getActivePath(), PrevLoc, PE->getLocation());
-  C.getActivePath().push_front(std::move(PE));
+
+  // We might've added 

[clang] f26deb4 - [analyzer][solver][NFC] Introduce ConstraintAssignor

2021-07-13 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-07-13T21:00:30+03:00
New Revision: f26deb4e6ba7e00c57b4be888c4d20c95a881154

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

LOG: [analyzer][solver][NFC] Introduce ConstraintAssignor

The new component is a symmetric response to SymbolicRangeInferrer.
While the latter is the unified component, which answers all the
questions what does the solver knows about a particular symbolic
expression, assignor associates new constraints (aka "assumes")
with symbolic expressions and can imply additional knowledge that
the solver can extract and use later on.

- Why do we need it and why is SymbolicRangeInferrer not enough?

As it is noted before, the inferrer only helps us to get the most
precise range information based on the existing knowledge and on the
mathematical foundations of different operations that symbolic
expressions actually represent.  It doesn't introduce new constraints.

The assignor, on the other hand, can impose constraints on other
symbols using the same domain knowledge.

- But for some expressions, SymbolicRangeInferrer looks into constraints
  for similar expressions, why can't we do that for all the cases?

That's correct!  But in order to do something like this, we should
have a finite number of possible "similar expressions".

Let's say we are asked about `$a - $b` and we know something about
`$b - $a`.  The inferrer can invert this expression and check
constraints for `$b - $a`.  This is simple!
But let's say we are asked about `$a` and we know that `$a * $b != 0`.
In this situation, we can imply that `$a != 0`, but the inferrer shouldn't
try every possible symbolic expression `X` to check if `$a * X` or
`X * $a` is constrained to non-zero.

With the assignor mechanism, we can catch this implication right at
the moment we associate `$a * $b` with non-zero range, and set similar
constraints for `$a` and `$b` as well.

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index bc8c83132c5d7..803cc5efd0c1e 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -669,6 +669,17 @@ LLVM_NODISCARD inline const RangeSet 
*getConstraint(ProgramStateRef State,
   return getConstraint(State, EquivalenceClass::find(State, Sym));
 }
 
+LLVM_NODISCARD ProgramStateRef setConstraint(ProgramStateRef State,
+ EquivalenceClass Class,
+ RangeSet Constraint) {
+  return State->set(Class, Constraint);
+}
+
+LLVM_NODISCARD ProgramStateRef setConstraints(ProgramStateRef State,
+  ConstraintRangeTy Constraints) {
+  return State->set(Constraints);
+}
+
 
//===--===//
 //   Equality/diseqiality abstraction
 
//===--===//
@@ -1373,6 +1384,182 @@ RangeSet 
SymbolicRangeInferrer::VisitBinaryOperator(Range LHS,
   return {RangeFactory, ValueFactory.getValue(Min), 
ValueFactory.getValue(Max)};
 }
 
+//===--===//
+// Constraint assignment logic
+//===--===//
+
+/// ConstraintAssignorBase is a small utility class that unifies visitor
+/// for ranges with a visitor for constraints (rangeset/range/constant).
+///
+/// It is designed to have one derived class, but generally it can have more.
+/// Derived class can control which types we handle by defining methods of the
+/// following form:
+///
+///   bool handle${SYMBOL}To${CONSTRAINT}(const SYMBOL *Sym,
+///   CONSTRAINT Constraint);
+///
+/// where SYMBOL is the type of the symbol (e.g. SymSymExpr, SymbolCast, etc.)
+///   CONSTRAINT is the type of constraint (RangeSet/Range/Const)
+///   return value signifies whether we should try other handle methods
+///  (i.e. false would mean to stop right after calling this method)
+template  class ConstraintAssignorBase {
+public:
+  using Const = const llvm::APSInt &;
+
+#define DISPATCH(CLASS) return assign##CLASS##Impl(cast(Sym), 
Constraint)
+
+#define ASSIGN(CLASS, TO, SYM, CONSTRAINT) 
\
+  if (!static_cast(this)->assign##CLASS##To##TO(SYM, CONSTRAINT))   
\
+  return false
+
+  void assign(SymbolRef Sym, RangeSet Constraint) {
+  

[clang] 60bd8cb - [analyzer][solver][NFC] Refactor how we detect (dis)equalities

2021-07-13 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-07-13T21:00:30+03:00
New Revision: 60bd8cbc0c84a41146b1ad6c832fa75f48cd2568

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

LOG: [analyzer][solver][NFC] Refactor how we detect (dis)equalities

This patch simplifies the way we deal with (dis)equalities.
Due to the symmetry between constraint handler and range inferrer,
we can have very similar implementations of logic handling
questions about (dis)equality and assumptions involving (dis)equality.

It also helps us to remove one more visitor, and removes uncertainty
that we got all the right places to put `trackNE` and `trackEQ`.

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/test/Analysis/equality_tracking.c

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 803cc5efd0c1..9e014e9fce4e 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -684,58 +684,30 @@ LLVM_NODISCARD ProgramStateRef 
setConstraints(ProgramStateRef State,
 //   Equality/diseqiality abstraction
 
//===--===//
 
-/// A small helper structure representing symbolic equality.
+/// A small helper function for detecting symbolic (dis)equality.
 ///
 /// Equality check can have 
diff erent forms (like a == b or a - b) and this
 /// class encapsulates those away if the only thing the user wants to check -
-/// whether it's equality/diseqiality or not and have an easy access to the
-/// compared symbols.
-struct EqualityInfo {
-public:
-  SymbolRef Left, Right;
-  // true for equality and false for disequality.
-  bool IsEquality = true;
-
-  void invert() { IsEquality = !IsEquality; }
-  /// Extract equality information from the given symbol and the constants.
-  ///
-  /// This function assumes the following expression Sym + Adjustment != Int.
-  /// It is a default because the most widespread case of the equality check
-  /// is (A == B) + 0 != 0.
-  static Optional extract(SymbolRef Sym, const llvm::APSInt ,
-const llvm::APSInt ) {
-// As of now, the only equality form supported is Sym + 0 != 0.
-if (!Int.isNullValue() || !Adjustment.isNullValue())
-  return llvm::None;
-
-return extract(Sym);
-  }
-  /// Extract equality information from the given symbol.
-  static Optional extract(SymbolRef Sym) {
-return EqualityExtractor().Visit(Sym);
+/// whether it's equality/diseqiality or not.
+///
+/// \returns true if assuming this Sym to be true means equality of operands
+///  false if it means disequality of operands
+///  None otherwise
+Optional meansEquality(const SymSymExpr *Sym) {
+  switch (Sym->getOpcode()) {
+  case BO_Sub:
+// This case is: A - B != 0 -> disequality check.
+return false;
+  case BO_EQ:
+// This case is: A == B != 0 -> equality check.
+return true;
+  case BO_NE:
+// This case is: A != B != 0 -> diseqiality check.
+return false;
+  default:
+return llvm::None;
   }
-
-private:
-  class EqualityExtractor
-  : public SymExprVisitor> {
-  public:
-Optional VisitSymSymExpr(const SymSymExpr *Sym) const {
-  switch (Sym->getOpcode()) {
-  case BO_Sub:
-// This case is: A - B != 0 -> disequality check.
-return EqualityInfo{Sym->getLHS(), Sym->getRHS(), false};
-  case BO_EQ:
-// This case is: A == B != 0 -> equality check.
-return EqualityInfo{Sym->getLHS(), Sym->getRHS(), true};
-  case BO_NE:
-// This case is: A != B != 0 -> diseqiality check.
-return EqualityInfo{Sym->getLHS(), Sym->getRHS(), false};
-  default:
-return llvm::None;
-  }
-}
-  };
-};
+}
 
 
//===--===//
 //Intersection functions
@@ -866,7 +838,13 @@ class SymbolicRangeInferrer
   }
 
   RangeSet VisitSymSymExpr(const SymSymExpr *Sym) {
-return VisitBinaryOperator(Sym);
+return intersect(
+RangeFactory,
+// If Sym is (dis)equality, we might have some information
+// on that in our equality classes data structure.
+getRangeForEqualities(Sym),
+// And we should always check what we can get from the operands.
+VisitBinaryOperator(Sym));
   }
 
 private:
@@ -907,9 +885,6 @@ class SymbolicRangeInferrer
 // calculate the effective range set by intersecting the range set
 // for A - B and the negated range set of B - A.
 

[clang] 1af97c9 - [analyzer] LoopUnrolling: fix crash when a loop counter is captured in a lambda by reference

2021-07-12 Thread Valeriy Savchenko via cfe-commits

Author: Abbas Sabra
Date: 2021-07-12T17:06:07+03:00
New Revision: 1af97c9d0b02002586473b4b9845b0c390504a27

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

LOG: [analyzer] LoopUnrolling: fix crash when a loop counter is captured in a 
lambda by reference

Reviewed By: vsavchenko

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

Added: 


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

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp 
b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
index dc268e562237f..e5f4e9ea30c97 100644
--- a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -79,14 +79,17 @@ ProgramStateRef processLoopEnd(const Stmt *LoopStmt, 
ProgramStateRef State) {
   return State;
 }
 
-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().bind("boundNum"
+static internal::Matcher simpleCondition(StringRef BindName,
+   StringRef RefName) {
+  return binaryOperator(
+ anyOf(hasOperatorName("<"), hasOperatorName(">"),
+   hasOperatorName("<="), hasOperatorName(">="),
+   hasOperatorName("!=")),
+ hasEitherOperand(ignoringParenImpCasts(
+ declRefExpr(to(varDecl(hasType(isInteger())).bind(BindName)))
+ .bind(RefName))),
+ hasEitherOperand(
+ ignoringParenImpCasts(integerLiteral().bind("boundNum"
   .bind("conditionOperator");
 }
 
@@ -138,7 +141,7 @@ static internal::Matcher hasSuspiciousStmt(StringRef 
NodeName) {
 
 static internal::Matcher forLoopMatcher() {
   return forStmt(
- hasCondition(simpleCondition("initVarName")),
+ hasCondition(simpleCondition("initVarName", "initVarRef")),
  // Initialization should match the form: 'int i = 6' or 'i = 42'.
  hasLoopInit(
  anyOf(declStmt(hasSingleDecl(
@@ -156,17 +159,52 @@ static internal::Matcher forLoopMatcher() {
  hasUnaryOperand(declRefExpr(
  to(varDecl(allOf(equalsBoundNode("initVarName"),
   hasType(isInteger(),
- 
unless(hasBody(hasSuspiciousStmt("initVarName".bind("forLoop");
+ unless(hasBody(hasSuspiciousStmt("initVarName"
+  .bind("forLoop");
 }
 
-static bool isPossiblyEscaped(const VarDecl *VD, ExplodedNode *N) {
-  // Global variables assumed as escaped variables.
+static bool isCapturedByReference(ExplodedNode *N, const DeclRefExpr *DR) {
+
+  // Get the lambda CXXRecordDecl
+  assert(DR->refersToEnclosingVariableOrCapture());
+  const LocationContext *LocCtxt = N->getLocationContext();
+  const Decl *D = LocCtxt->getDecl();
+  const auto *MD = cast(D);
+  assert(MD && MD->getParent()->isLambda() &&
+ "Captured variable should only be seen while evaluating a lambda");
+  const CXXRecordDecl *LambdaCXXRec = MD->getParent();
+
+  // Lookup the fields of the lambda
+  llvm::DenseMap LambdaCaptureFields;
+  FieldDecl *LambdaThisCaptureField;
+  LambdaCXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField);
+
+  // Check if the counter is captured by reference
+  const VarDecl *VD = cast(DR->getDecl()->getCanonicalDecl());
+  assert(VD);
+  const FieldDecl *FD = LambdaCaptureFields[VD];
+  assert(FD && "Captured variable without a corresponding field");
+  return FD->getType()->isReferenceType();
+}
+
+// A loop counter is considered escaped if:
+// case 1: It is a global variable.
+// case 2: It is a reference parameter or a reference capture.
+// case 3: It is assigned to a non-const reference variable or parameter.
+// case 4: Has its address taken.
+static bool isPossiblyEscaped(ExplodedNode *N, const DeclRefExpr *DR) {
+  const VarDecl *VD = cast(DR->getDecl()->getCanonicalDecl());
+  assert(VD);
+  // Case 1:
   if (VD->hasGlobalStorage())
 return true;
 
-  const bool isParm = isa(VD);
-  // Reference parameters are assumed as escaped variables.
-  if (isParm && VD->getType()->isReferenceType())
+  const bool IsRefParamOrCapture =
+  isa(VD) || DR->refersToEnclosingVariableOrCapture();
+  // Case 2:
+  if 

[clang] 6017cb3 - [analyzer][solver] Use all sources of constraints

2021-07-06 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-07-06T11:09:08+03:00
New Revision: 6017cb31bb3548641465ea66219e11abc3106d38

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

LOG: [analyzer][solver] Use all sources of constraints

Prior to this patch, we always gave priority to constraints that we
actually know about symbols in question.  However, these can get
outdated and we can get better results if we look at all possible
sources of knowledge, including sub-expressions.

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/test/Analysis/constant-folding.c

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 0e57a1a5040fc..bc8c83132c5d7 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -884,26 +884,28 @@ class SymbolicRangeInferrer
   }
 
   RangeSet infer(SymbolRef Sym) {
-if (Optional ConstraintBasedRange = intersect(
-RangeFactory, getConstraint(State, Sym),
-// If Sym is a 
diff erence of symbols A - B, then maybe we have range
-// set stored for B - A.
-//
-// If we have range set stored for both A - B and B - A then
-// calculate the effective range set by intersecting the range set
-// for A - B and the negated range set of B - A.
-getRangeForNegatedSub(Sym), getRangeForEqualities(Sym))) {
-  return *ConstraintBasedRange;
-}
-
-// If Sym is a comparison expression (except <=>),
-// find any other comparisons with the same operands.
-// See function description.
-if (Optional CmpRangeSet = getRangeForComparisonSymbol(Sym)) {
-  return *CmpRangeSet;
-}
-
-return Visit(Sym);
+return intersect(
+RangeFactory,
+// Of course, we should take the constraint directly associated with
+// this symbol into consideration.
+getConstraint(State, Sym),
+// If Sym is a 
diff erence of symbols A - B, then maybe we have range
+// set stored for B - A.
+//
+// If we have range set stored for both A - B and B - A then
+// calculate the effective range set by intersecting the range set
+// for A - B and the negated range set of B - A.
+getRangeForNegatedSub(Sym),
+// If Sym is (dis)equality, we might have some information on that
+// in our equality classes data structure.
+getRangeForEqualities(Sym),
+// If Sym is a comparison expression (except <=>),
+// find any other comparisons with the same operands.
+// See function description.
+getRangeForComparisonSymbol(Sym),
+// Apart from the Sym itself, we can infer quite a lot if we look
+// into subexpressions of Sym.
+Visit(Sym));
   }
 
   RangeSet infer(EquivalenceClass Class) {

diff  --git a/clang/test/Analysis/constant-folding.c 
b/clang/test/Analysis/constant-folding.c
index 08a7accfba641..116e74b746b4e 100644
--- a/clang/test/Analysis/constant-folding.c
+++ b/clang/test/Analysis/constant-folding.c
@@ -179,6 +179,36 @@ void testBitwiseRules(unsigned int a, int b, int c) {
   }
 }
 
+unsigned reset();
+
+void testCombinedSources(unsigned a, unsigned b) {
+  if (b >= 10 && (a | b) <= 30) {
+// Check that we can merge constraints from (a | b), a, and b.
+// Because of the order of assumptions, we already know that (a | b) is 
[10, 30].
+clang_analyzer_eval((a | b) >= 10 && (a | b) <= 30); // 
expected-warning{{TRUE}}
+  }
+
+  a = reset();
+  b = reset();
+
+  if ((a | b) <= 30 && b >= 10) {
+// Check that we can merge constraints from (a | b), a, and b.
+// At this point, we know that (a | b) is [0, 30], but the knowledge
+// of b >= 10 added later can help us to refine it and change it to [10, 
30].
+clang_analyzer_eval(10 <= (a | b) && (a | b) <= 30); // 
expected-warning{{TRUE}}
+  }
+
+  a = reset();
+  b = reset();
+
+  unsigned c = (a | b) & (a != b);
+  if (c <= 40 && a == b) {
+// Even though we have a directo constraint for c [0, 40],
+// we can get a more precise range by looking at the expression itself.
+clang_analyzer_eval(c == 0); // expected-warning{{TRUE}}
+  }
+}
+
 void testRemainderRules(unsigned int a, unsigned int b, int c, int d) {
   // Check that we know that remainder of zero divided by any number is still 
0.
   clang_analyzer_eval((0 % c) == 0); // expected-warning{{TRUE}}



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

[clang] c818cb9 - [analyzer][satest][NFC] Relax dependencies requirements

2021-06-30 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-30T12:50:21+03:00
New Revision: c818cb96ad4aa65bceadc72199677c852e8c22bd

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

LOG: [analyzer][satest][NFC] Relax dependencies requirements

Added: 


Modified: 
clang/utils/analyzer/Dockerfile

Removed: 




diff  --git a/clang/utils/analyzer/Dockerfile b/clang/utils/analyzer/Dockerfile
index f74ff8aa95c25..bb1dd60eeb9b8 100644
--- a/clang/utils/analyzer/Dockerfile
+++ b/clang/utils/analyzer/Dockerfile
@@ -13,16 +13,16 @@ RUN apt-add-repository -y 'deb 
https://apt.kitware.com/ubuntu/ bionic main'
 
 # test system dependencies
 RUN apt-get update && apt-get install -y \
-git=1:2.17.1-1ubuntu0.7 \
-gettext=0.19.8.1-6ubuntu0.3 \
+git=1:2.17.1* \
+gettext=0.19.8.1* \
 python3=3.6.7-1~18.04 \
-python3-pip=9.0.1-2.3~ubuntu1.18.04.1 \
-cmake=3.17.3-0kitware1 \
+python3-pip=9.0.1-2.3* \
+cmake=3.20.5* \
 ninja-build=1.8.2-1
 
 # box2d dependencies
 RUN apt-get install -y \
-libx11-dev=2:1.6.4-3ubuntu0.2 \
+libx11-dev=2:1.6.4-3* \
 libxrandr-dev=2:1.5.1-1 \
 libxinerama-dev=2:1.1.3-1 \
 libxcursor-dev=1:1.1.15-1 \
@@ -35,22 +35,22 @@ RUN apt-get install -y \
 
 # simbody dependencies
 RUN apt-get install -y \
-liblapack-dev=3.7.1-4ubuntu1
+liblapack-dev=3.7.1-4*
 
 # drogon dependencies
 RUN apt-get install -y \
-libjsonrpccpp-dev=0.7.0-1build2 \
-uuid-dev=2.31.1-0.4ubuntu3.6
+libjsonrpccpp-dev=0.7.0-1* \
+uuid-dev=2.31.1-0.4*
 
 # tmux dependencies
 RUN apt-get install -y \
 autotools-dev=20180224.1 \
-automake=1:1.15.1-3ubuntu2 \
-libncurses5-dev=6.1-1ubuntu1.18.04 \
-libevent-dev=2.1.8-stable-4build1 \
-pkg-config=0.29.1-0ubuntu2 \
+automake=1:1.15.1-3* \
+libncurses5-dev=6.1-1* \
+libevent-dev=2.1.8* \
+pkg-config=0.29.1-0* \
 flex=2.6.4-6 \
-bison=2:3.0.4.dfsg-1build1
+bison=2:3.0.4.*
 
 RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 1
 



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


[clang] b284229 - [analyzer] Fix SValTest for LocAsInt test

2021-06-29 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-29T13:01:41+03:00
New Revision: b2842298cebf420ecb3750bf309021a7f37870c1

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

LOG: [analyzer] Fix SValTest for LocAsInt test

Added: 


Modified: 
clang/unittests/StaticAnalyzer/SValTest.cpp

Removed: 




diff  --git a/clang/unittests/StaticAnalyzer/SValTest.cpp 
b/clang/unittests/StaticAnalyzer/SValTest.cpp
index 0956984868384..ea10d69d2804e 100644
--- a/clang/unittests/StaticAnalyzer/SValTest.cpp
+++ b/clang/unittests/StaticAnalyzer/SValTest.cpp
@@ -166,7 +166,7 @@ void foo(int *x) {
   SVal A = getByName("a");
   ASSERT_FALSE(A.getType(Context).isNull());
   // TODO: Turn it into signed long
-  EXPECT_EQ(Context.UnsignedLongTy, A.getType(Context));
+  EXPECT_EQ(Context.getUIntPtrType(), A.getType(Context));
 
   SVal B = getByName("b");
   ASSERT_FALSE(B.getType(Context).isNull());



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


[clang] 159024c - [analyzer] Implement getType for SVal

2021-06-29 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-29T12:11:19+03:00
New Revision: 159024ce231502d4d68825c35c3548a14577f0fd

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

LOG: [analyzer] Implement getType for SVal

This commit adds a function to the top-class of SVal hierarchy to
provide type information about the value.  That can be extremely
useful when this is the only piece of information that the user is
actually caring about.

Additionally, this commit introduces a testing framework for writing
unit-tests for symbolic values.

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

Added: 
clang/unittests/StaticAnalyzer/SValTest.cpp

Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
clang/lib/StaticAnalyzer/Core/SVals.cpp
clang/unittests/StaticAnalyzer/CMakeLists.txt

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index f59b254094db8..bb598af681666 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -52,6 +52,8 @@ class CompoundValData : public llvm::FoldingSetNode {
   iterator begin() const { return L.begin(); }
   iterator end() const { return L.end(); }
 
+  QualType getType() const { return T; }
+
   static void Profile(llvm::FoldingSetNodeID& ID, QualType T,
   llvm::ImmutableList L);
 

diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index b1c33713febd9..6199c8d8d179c 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -201,6 +201,19 @@ class SVal {
   SymExpr::symbol_iterator symbol_end() const {
 return SymExpr::symbol_end();
   }
+
+  /// Try to get a reasonable type for the given value.
+  ///
+  /// \returns The best approximation of the value type or Null.
+  /// In theory, all symbolic values should be typed, but this function
+  /// is still a WIP and might have a few blind spots.
+  ///
+  /// \note This function should not be used when the user has access to the
+  /// bound expression AST node as well, since AST always has exact types.
+  ///
+  /// \note Loc values are interpreted as pointer rvalues for the purposes of
+  /// this method.
+  QualType getType(const ASTContext &) const;
 };
 
 inline raw_ostream <<(raw_ostream , clang::ento::SVal V) {

diff  --git a/clang/lib/StaticAnalyzer/Core/SVals.cpp 
b/clang/lib/StaticAnalyzer/Core/SVals.cpp
index 252596887e4f1..117546e43b1a1 100644
--- a/clang/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SVals.cpp
@@ -12,6 +12,7 @@
 
//===--===//
 
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/Expr.h"
@@ -21,6 +22,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
 #include "llvm/ADT/Optional.h"
@@ -136,6 +138,63 @@ const MemRegion *SVal::getAsRegion() const {
   return nullptr;
 }
 
+namespace {
+class TypeRetrievingVisitor
+: public FullSValVisitor {
+private:
+  const ASTContext 
+
+public:
+  TypeRetrievingVisitor(const ASTContext ) : Context(Context) {}
+
+  QualType VisitLocMemRegionVal(loc::MemRegionVal MRV) {
+return Visit(MRV.getRegion());
+  }
+  QualType VisitLocGotoLabel(loc::GotoLabel GL) {
+return QualType{Context.VoidPtrTy};
+  }
+  template  QualType VisitConcreteInt(ConcreteInt CI) {
+const llvm::APSInt  = CI.getValue();
+return Context.getIntTypeForBitwidth(Value.getBitWidth(), 
Value.isSigned());
+  }
+  QualType VisitLocConcreteInt(loc::ConcreteInt CI) {
+return VisitConcreteInt(CI);
+  }
+  QualType VisitNonLocConcreteInt(nonloc::ConcreteInt CI) {
+return VisitConcreteInt(CI);
+  }
+  QualType VisitNonLocLocAsInteger(nonloc::LocAsInteger LI) {
+QualType NestedType = Visit(LI.getLoc());
+if (NestedType.isNull())
+  return NestedType;
+
+return Context.getIntTypeForBitwidth(LI.getNumBits(),
+ 

[clang] 8474bb1 - [analyzer][solver][NFC] Simplify function signatures

2021-06-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-28T14:20:06+03:00
New Revision: 8474bb13c3270d4195a663013b95e6065075ce56

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

LOG: [analyzer][solver][NFC] Simplify function signatures

Since RangeSet::Factory actually contains BasicValueFactory, we can
remove value factory from many function signatures inside the solver.

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

Added: 


Modified: 

clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
index bf00fd98a4616..c67df1e51b4ff 100644
--- 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
+++ 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -213,6 +213,9 @@ class RangeSet {
 /// where N = size(What)
 RangeSet negate(RangeSet What);
 
+/// Return associated value factory.
+BasicValueFactory () const { return ValueFactory; }
+
   private:
 /// Return a persistent version of the given container.
 RangeSet makePersistent(ContainerType &);

diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 27367ff5ae80c..c3d8a0a87635d 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -549,14 +549,13 @@ class EquivalenceClass : public llvm::FoldingSetNode {
  SymbolRef Sym);
 
   /// Merge classes for the given symbols and return a new state.
-  LLVM_NODISCARD static inline ProgramStateRef
-  merge(BasicValueFactory , RangeSet::Factory , ProgramStateRef State,
-SymbolRef First, SymbolRef Second);
+  LLVM_NODISCARD static inline ProgramStateRef merge(RangeSet::Factory ,
+ ProgramStateRef State,
+ SymbolRef First,
+ SymbolRef Second);
   // Merge this class with the given class and return a new state.
-  LLVM_NODISCARD inline ProgramStateRef merge(BasicValueFactory ,
-  RangeSet::Factory ,
-  ProgramStateRef State,
-  EquivalenceClass Other);
+  LLVM_NODISCARD inline ProgramStateRef
+  merge(RangeSet::Factory , ProgramStateRef State, EquivalenceClass Other);
 
   /// Return a set of class members for the given state.
   LLVM_NODISCARD inline SymbolSet getClassMembers(ProgramStateRef State) const;
@@ -567,15 +566,14 @@ class EquivalenceClass : public llvm::FoldingSetNode {
  SymbolReaper ) const;
 
   LLVM_NODISCARD static inline ProgramStateRef
-  markDisequal(BasicValueFactory , RangeSet::Factory ,
-   ProgramStateRef State, SymbolRef First, SymbolRef Second);
+  markDisequal(RangeSet::Factory , ProgramStateRef State, SymbolRef First,
+   SymbolRef Second);
   LLVM_NODISCARD static inline ProgramStateRef
-  markDisequal(BasicValueFactory , RangeSet::Factory ,
-   ProgramStateRef State, EquivalenceClass First,
-   EquivalenceClass Second);
+  markDisequal(RangeSet::Factory , ProgramStateRef State,
+   EquivalenceClass First, EquivalenceClass Second);
   LLVM_NODISCARD inline ProgramStateRef
-  markDisequal(BasicValueFactory , RangeSet::Factory ,
-   ProgramStateRef State, EquivalenceClass Other) const;
+  markDisequal(RangeSet::Factory , ProgramStateRef State,
+   EquivalenceClass Other) const;
   LLVM_NODISCARD static inline ClassSet
   getDisequalClasses(ProgramStateRef State, SymbolRef Sym);
   LLVM_NODISCARD inline ClassSet
@@ -641,15 +639,13 @@ class EquivalenceClass : public llvm::FoldingSetNode {
   }
   static inline SymbolSet::Factory (ProgramStateRef State);
 
-  inline ProgramStateRef mergeImpl(BasicValueFactory , RangeSet::Factory ,
-   ProgramStateRef State, SymbolSet Members,
-   EquivalenceClass Other,
+  inline ProgramStateRef mergeImpl(RangeSet::Factory , ProgramStateRef State,
+   SymbolSet Members, EquivalenceClass Other,
SymbolSet OtherMembers);
   static inline bool
   addToDisequalityInfo(DisequalityMapTy , ConstraintRangeTy ,
- 

[clang] d646157 - [analyzer] Fix assertion failure on code with transparent unions

2021-06-25 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-25T23:09:16+03:00
New Revision: d646157146ccda93cd72dcbaff4a554c61ed9586

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

LOG: [analyzer] Fix assertion failure on code with transparent unions

rdar://76948312

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

Added: 
clang/test/Analysis/transparent_union_bug.c

Modified: 
clang/lib/StaticAnalyzer/Core/CallEvent.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp 
b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index ecf1d1b5f0688..3785f498414f9 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -47,6 +47,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/ImmutableList.h"
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/PointerIntPair.h"
@@ -466,6 +467,42 @@ bool CallEvent::isVariadic(const Decl *D) {
   llvm_unreachable("unknown callable kind");
 }
 
+static bool isTransparentUnion(QualType T) {
+  const RecordType *UT = T->getAsUnionType();
+  return UT && UT->getDecl()->hasAttr();
+}
+
+// In some cases, symbolic cases should be transformed before we associate
+// them with parameters.  This function incapsulates such cases.
+static SVal processArgument(SVal Value, const Expr *ArgumentExpr,
+const ParmVarDecl *Parameter, SValBuilder ) {
+  QualType ParamType = Parameter->getType();
+  QualType ArgumentType = ArgumentExpr->getType();
+
+  // Transparent unions allow users to easily convert values of union field
+  // types into union-typed objects.
+  //
+  // Also, more importantly, they allow users to define functions with 
diff erent
+  // 
diff erent parameter types, substituting types matching transparent union
+  // field types with the union type itself.
+  //
+  // Here, we check specifically for latter cases and prevent binding
+  // field-typed values to union-typed regions.
+  if (isTransparentUnion(ParamType) &&
+  // Let's check that we indeed trying to bind 
diff erent types.
+  !isTransparentUnion(ArgumentType)) {
+BasicValueFactory  = SVB.getBasicValueFactory();
+
+llvm::ImmutableList CompoundSVals = BVF.getEmptySValList();
+CompoundSVals = BVF.prependSVal(Value, CompoundSVals);
+
+// Wrap it with compound value.
+return SVB.makeCompoundVal(ParamType, CompoundSVals);
+  }
+
+  return Value;
+}
+
 static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
  CallEvent::BindingsTy ,
  SValBuilder ,
@@ -490,10 +527,12 @@ static void addParameterValuesToBindings(const 
StackFrameContext *CalleeCtx,
 // determined in compile-time but not represented as arg-expressions,
 // which makes getArgSVal() fail and return UnknownVal.
 SVal ArgVal = Call.getArgSVal(Idx);
+const Expr *ArgExpr = Call.getArgExpr(Idx);
 if (!ArgVal.isUnknown()) {
   Loc ParamLoc = SVB.makeLoc(
   MRMgr.getParamVarRegion(Call.getOriginExpr(), Idx, CalleeCtx));
-  Bindings.push_back(std::make_pair(ParamLoc, ArgVal));
+  Bindings.push_back(
+  std::make_pair(ParamLoc, processArgument(ArgVal, ArgExpr, *I, SVB)));
 }
   }
 

diff  --git a/clang/test/Analysis/transparent_union_bug.c 
b/clang/test/Analysis/transparent_union_bug.c
new file mode 100644
index 0..b6069c6a59b19
--- /dev/null
+++ b/clang/test/Analysis/transparent_union_bug.c
@@ -0,0 +1,40 @@
+// RUN: %clang_analyze_cc1 -analyze -triple x86_64-apple-darwin10 \
+// RUN:  -analyzer-checker=core,debug.ExprInspection -verify %s
+
+void clang_analyzer_warnIfReached();
+
+typedef struct {
+  int value;
+} Struct;
+
+typedef union {
+  Struct *ptr;
+  long num;
+} __attribute__((transparent_union)) Alias;
+
+void foo(Struct *x);
+void foo(Alias y) {
+  if (y.ptr == 0) {
+// no-crash
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+void foobar(long z);
+void foobar(Alias z) {
+  if (z.num != 42) {
+// no-crash
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void foobaz(Alias x) {
+  if (x.ptr == 0) {
+// no-crash
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+void bar(Struct arg) {
+  foo();
+  foobar(42);
+  foobaz();
+}



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


[clang] cc2ef19 - [analyzer] Handle NTTP invocation in CallContext.getCalleeDecl()

2021-06-18 Thread Valeriy Savchenko via cfe-commits

Author: Tomasz Kamiński
Date: 2021-06-18T16:32:19+03:00
New Revision: cc2ef195560999d0690a8d8805ea811270e38f26

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

LOG: [analyzer] Handle NTTP invocation in CallContext.getCalleeDecl()

This fixes a crash in MallocChecker for the situation when operator new 
(delete) is invoked via NTTP  and makes the behavior of 
CallContext.getCalleeDecl(Expr) identical to CallEvent.getDecl().

Reviewed By: vsavchenko

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
clang/test/Analysis/NewDelete-checker-test.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp 
b/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
index 3d44d2cbc069d..3d64ce453479f 100644
--- a/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -19,6 +19,10 @@ using namespace clang;
 using namespace ento;
 
 const FunctionDecl *CheckerContext::getCalleeDecl(const CallExpr *CE) const {
+  const FunctionDecl *D = CE->getDirectCallee();
+  if (D)
+return D;
+
   const Expr *Callee = CE->getCallee();
   SVal L = Pred->getSVal(Callee);
   return L.getAsFunctionDecl();

diff  --git a/clang/test/Analysis/NewDelete-checker-test.cpp 
b/clang/test/Analysis/NewDelete-checker-test.cpp
index 5a8711fa8a7ad..86df9d01dfb01 100644
--- a/clang/test/Analysis/NewDelete-checker-test.cpp
+++ b/clang/test/Analysis/NewDelete-checker-test.cpp
@@ -421,3 +421,36 @@ void shouldNotReportLeak() {
   Derived *p = (Derived *)allocate();
   delete p;
 }
+
+template
+void* allocate_via_nttp(size_t n) {
+  return allocate_fn(n);
+}
+
+template
+void deallocate_via_nttp(void* ptr) {
+  deallocate_fn(ptr);
+}
+
+void testNTTPNewNTTPDelete() {
+  void* p = allocate_via_nttp<::operator new>(10);
+  deallocate_via_nttp<::operator delete>(p);
+} // no warn
+
+void testNTTPNewDirectDelete() {
+  void* p = allocate_via_nttp<::operator new>(10);
+  ::operator delete(p);
+} // no warn
+
+void testDirectNewNTTPDelete() {
+  void* p = ::operator new(10);
+  deallocate_via_nttp<::operator delete>(p);
+}
+
+void not_free(void*) {
+}
+
+void testLeakBecauseNTTPIsNotDeallocation() {
+  void* p = ::operator new(10);
+  deallocate_via_nttp(p);
+}  // leak-warning{{Potential leak of memory pointed to by 'p'}}



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


[clang] eadd54f - [analyzer] Decouple NoteTag from its Factory

2021-06-15 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-15T11:58:13+03:00
New Revision: eadd54f2741f9dc7307512382a7c8fb49aa840d0

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

LOG: [analyzer] Decouple NoteTag from its Factory

This allows us to create other types of tags that carry useful
bits of information alongside.

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

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
clang/lib/StaticAnalyzer/Core/CoreEngine.cpp

Removed: 




diff  --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h 
b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 0b12ff7075780..99cd24a52f2df 100644
--- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -725,14 +725,43 @@ class BugReporterContext {
   }
 };
 
+/// The tag that carries some information with it.
+///
+/// It can be valuable to produce tags with some bits of information and later
+/// reuse them for a better diagnostic.
+///
+/// Please make sure that derived class' constuctor is private and that the 
user
+/// can only create objects using DataTag::Factory.  This also means that
+/// DataTag::Factory should be friend for every derived class.
+class DataTag : public ProgramPointTag {
+public:
+  StringRef getTagDescription() const override { return "Data Tag"; }
+
+  // Manage memory for DataTag objects.
+  class Factory {
+std::vector> Tags;
+
+  public:
+template 
+const DataTagType *make(Args &&... ConstructorArgs) {
+  // We cannot use std::make_unique because we cannot access the private
+  // constructor from inside it.
+  Tags.emplace_back(
+  new DataTagType(std::forward(ConstructorArgs)...));
+  return static_cast(Tags.back().get());
+}
+  };
+
+protected:
+  DataTag(void *TagKind) : ProgramPointTag(TagKind) {}
+};
 
 /// The tag upon which the TagVisitor reacts. Add these in order to display
 /// additional PathDiagnosticEventPieces along the path.
-class NoteTag : public ProgramPointTag {
+class NoteTag : public DataTag {
 public:
-  using Callback =
-  std::function;
+  using Callback = std::function;
 
 private:
   static int Kind;
@@ -741,7 +770,7 @@ class NoteTag : public ProgramPointTag {
   const bool IsPrunable;
 
   NoteTag(Callback &, bool IsPrunable)
-  : ProgramPointTag(), Cb(std::move(Cb)), IsPrunable(IsPrunable) {}
+  : DataTag(), Cb(std::move(Cb)), IsPrunable(IsPrunable) {}
 
 public:
   static bool classof(const ProgramPointTag *T) {
@@ -766,20 +795,7 @@ class NoteTag : public ProgramPointTag {
 
   bool isPrunable() const { return IsPrunable; }
 
-  // Manage memory for NoteTag objects.
-  class Factory {
-std::vector> Tags;
-
-  public:
-const NoteTag *makeNoteTag(Callback &, bool IsPrunable = false) {
-  // We cannot use std::make_unique because we cannot access the private
-  // constructor from inside it.
-  std::unique_ptr T(new NoteTag(std::move(Cb), IsPrunable));
-  Tags.push_back(std::move(T));
-  return Tags.back().get();
-}
-  };
-
+  friend class Factory;
   friend class TagVisitor;
 };
 

diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index 54572bd81f20f..a383012dc3516 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -255,7 +255,7 @@ class CheckerContext {
   ///to omit the note from the report if it would make the displayed
   ///bug path significantly shorter.
   const NoteTag *getNoteTag(NoteTag::Callback &, bool IsPrunable = false) {
-return Eng.getNoteTags().makeNoteTag(std::move(Cb), IsPrunable);
+return Eng.getDataTags().make(std::move(Cb), IsPrunable);
   }
 
   /// A shorthand version of getNoteTag that doesn't require you to accept

diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 2aca2c99ef4fd..9898b9b42f4b2 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -96,9 +96,10 @@ class CoreEngine {
   /// (This data is owned by AnalysisConsumer.)
   FunctionSummariesTy *FunctionSummaries;
 
-  /// Add path note tags along the 

[clang] 16f7a95 - [analyzer] Simplify the process of producing notes for stores

2021-06-15 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-15T11:37:36+03:00
New Revision: 16f7a952ec3e0f362690c6449951866100c6f76c

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

LOG: [analyzer] Simplify the process of producing notes for stores

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

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h 
b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index 8e39229ab1fd6..24cae12af24a1 100644
--- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -330,6 +330,10 @@ class StoreHandler {
 TrackingOptions Opts) = 0;
 
   Tracker () { return ParentTracker; }
+
+protected:
+  PathDiagnosticPieceRef constructNote(StoreInfo SI, BugReporterContext ,
+   StringRef NodeText);
 };
 
 /// Visitor that tracks expressions and values.

diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index dab1ba0a9d50f..d06a2d4933038 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1214,136 +1214,146 @@ static bool isInitializationOfVar(const ExplodedNode 
*N, const VarRegion *VR) {
   return FrameSpace->getStackFrame() == LCtx->getStackFrame();
 }
 
+static bool isObjCPointer(const MemRegion *R) {
+  if (R->isBoundable())
+if (const auto *TR = dyn_cast(R))
+  return TR->getValueType()->isObjCObjectPointerType();
+
+  return false;
+}
+
+static bool isObjCPointer(const ValueDecl *D) {
+  return D->getType()->isObjCObjectPointerType();
+}
+
 /// Show diagnostics for initializing or declaring a region \p R with a bad 
value.
-static void showBRDiagnostics(const char *action, llvm::raw_svector_ostream 
,
-  const MemRegion *NewR, SVal V,
-  const MemRegion *OldR, const DeclStmt *DS) {
-  if (NewR->canPrintPretty()) {
-NewR->printPretty(os);
-os << " ";
-  }
-
-  if (V.getAs()) {
-bool b = false;
-if (NewR->isBoundable()) {
-  if (const auto *TR = dyn_cast(NewR)) {
-if (TR->getValueType()->isObjCObjectPointerType()) {
-  os << action << "nil";
-  b = true;
-}
-  }
-}
-if (!b)
-  os << action << "a null pointer value";
-
-  } else if (auto CVal = V.getAs()) {
-os << action << CVal->getValue();
-  } else if (OldR && OldR->canPrintPretty()) {
-os << action << "the value of ";
-OldR->printPretty(os);
-  } else if (DS) {
-if (V.isUndef()) {
-  if (isa(NewR)) {
+static void showBRDiagnostics(llvm::raw_svector_ostream , StoreInfo SI) {
+  const bool HasPrefix = SI.Dest->canPrintPretty();
+
+  if (HasPrefix) {
+SI.Dest->printPretty(OS);
+OS << " ";
+  }
+
+  const char *Action = nullptr;
+
+  switch (SI.StoreKind) {
+  case StoreInfo::Initialization:
+Action = HasPrefix ? "initialized to " : "Initializing to ";
+break;
+  case StoreInfo::BlockCapture:
+Action = HasPrefix ? "captured by block as " : "Captured by block as ";
+break;
+  default:
+llvm_unreachable("Unexpected store kind");
+  }
+
+  if (SI.Value.getAs()) {
+OS << Action << (isObjCPointer(SI.Dest) ? "nil" : "a null pointer value");
+
+  } else if (auto CVal = SI.Value.getAs()) {
+OS << Action << CVal->getValue();
+
+  } else if (SI.Origin && SI.Origin->canPrintPretty()) {
+OS << Action << "the value of ";
+SI.Origin->printPretty(OS);
+
+  } else if (SI.StoreKind == StoreInfo::Initialization) {
+// We don't need to check here, all these conditions were
+// checked by StoreSiteFinder, when it figured out that it is
+// initialization.
+const auto *DS =
+cast(SI.StoreSite->getLocationAs()->getStmt());
+
+if (SI.Value.isUndef()) {
+  if (isa(SI.Dest)) {
 const auto *VD = cast(DS->getSingleDecl());
+
 if (VD->getInit()) {
-  os << (NewR->canPrintPretty() ? "initialized" : "Initializing")
+  OS << (HasPrefix ? "initialized" : "Initializing")
  << " to a garbage value";
 } else {
-  os << (NewR->canPrintPretty() ? "declared" : "Declaring")
+  OS << (HasPrefix ? "declared" : "Declaring")
  << " without an initial value";
 }
   }
 } else {
-  os << (NewR->canPrintPretty() ? "initialized" : "Initialized") << " 
here";
+  OS << (HasPrefix ? 

[clang] 6e6a26b - [analyzer] Extract InlinedFunctionCallHandler

2021-06-15 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-15T11:37:36+03:00
New Revision: 6e6a26b8f0ea8300d5a814e4150e225c33ec25de

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

LOG: [analyzer] Extract InlinedFunctionCallHandler

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 835c54ef5f68..dab1ba0a9d50 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -937,91 +937,6 @@ class ReturnVisitor : public TrackingBugReporterVisitor {
 ID.AddBoolean(EnableNullFPSuppression);
   }
 
-  /// Adds a ReturnVisitor if the given statement represents a call that was
-  /// inlined.
-  ///
-  /// This will search back through the ExplodedGraph, starting from the given
-  /// node, looking for when the given statement was processed. If it turns out
-  /// the statement is a call that was inlined, we add the visitor to the
-  /// bug report, so it can print a note later.
-  static void addVisitorIfNecessary(TrackerRef ParentTracker,
-const ExplodedNode *Node, const Stmt *S,
-PathSensitiveBugReport ,
-bool InEnableNullFPSuppression,
-bugreporter::TrackingKind TKind) {
-if (!CallEvent::isCallStmt(S))
-  return;
-
-// First, find when we processed the statement.
-// If we work with a 'CXXNewExpr' that is going to be purged away before
-// its call take place. We would catch that purge in the last condition
-// as a 'StmtPoint' so we have to bypass it.
-const bool BypassCXXNewExprEval = isa(S);
-
-// This is moving forward when we enter into another context.
-const StackFrameContext *CurrentSFC = Node->getStackFrame();
-
-do {
-  // If that is satisfied we found our statement as an inlined call.
-  if (Optional CEE = Node->getLocationAs())
-if (CEE->getCalleeContext()->getCallSite() == S)
-  break;
-
-  // Try to move forward to the end of the call-chain.
-  Node = Node->getFirstPred();
-  if (!Node)
-break;
-
-  const StackFrameContext *PredSFC = Node->getStackFrame();
-
-  // If that is satisfied we found our statement.
-  // FIXME: This code currently bypasses the call site for the
-  //conservatively evaluated allocator.
-  if (!BypassCXXNewExprEval)
-if (Optional SP = Node->getLocationAs())
-  // See if we do not enter into another context.
-  if (SP->getStmt() == S && CurrentSFC == PredSFC)
-break;
-
-  CurrentSFC = PredSFC;
-} while (Node->getStackFrame() == CurrentSFC);
-
-// Next, step over any post-statement checks.
-while (Node && Node->getLocation().getAs())
-  Node = Node->getFirstPred();
-if (!Node)
-  return;
-
-// Finally, see if we inlined the call.
-Optional CEE = Node->getLocationAs();
-if (!CEE)
-  return;
-
-const StackFrameContext *CalleeContext = CEE->getCalleeContext();
-if (CalleeContext->getCallSite() != S)
-  return;
-
-// Check the return value.
-ProgramStateRef State = Node->getState();
-SVal RetVal = Node->getSVal(S);
-
-// Handle cases where a reference is returned and then immediately used.
-if (cast(S)->isGLValue())
-  if (Optional LValue = RetVal.getAs())
-RetVal = State->getSVal(*LValue);
-
-// See if the return value is NULL. If so, suppress the report.
-AnalyzerOptions  = State->getAnalysisManager().options;
-
-bool EnableNullFPSuppression = false;
-if (InEnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths)
-  if (Optional RetLoc = RetVal.getAs())
-EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
-
-BR.addVisitor(ParentTracker, CalleeContext,
- EnableNullFPSuppression, Options, TKind);
-  }
-
   PathDiagnosticPieceRef visitNodeInitial(const ExplodedNode *N,
   BugReporterContext ,
   PathSensitiveBugReport ) {
@@ -2228,6 +2143,96 @@ class InterestingLValueHandler final : public 
ExpressionHandler {
   }
 };
 
+/// Adds a ReturnVisitor if the given statement represents a call that was
+/// inlined.
+///
+/// This will search back through the ExplodedGraph, starting from the given
+/// node, looking for when the given statement was processed. If it turns out
+/// the statement is a call that was inlined, we add the visitor 

[clang] 2e49067 - [analyzer] Extract InterestingLValueHandler

2021-06-15 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-15T11:37:36+03:00
New Revision: 2e490676ea2eb419e7b2f54e1e2e537d5244ebbc

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

LOG: [analyzer] Extract InterestingLValueHandler

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 23f925e49b15..835c54ef5f68 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -2151,7 +2151,8 @@ class ArrayIndexHandler final : public ExpressionHandler {
   }
 };
 
-class DefaultExpressionHandler final : public ExpressionHandler {
+// TODO: extract it into more handlers
+class InterestingLValueHandler final : public ExpressionHandler {
 public:
   using ExpressionHandler::ExpressionHandler;
 
@@ -2219,13 +2220,26 @@ class DefaultExpressionHandler final : public 
ExpressionHandler {
 // previously.
 Report.addVisitor(*DV,
 InputNode);
-
 getParentTracker().track(V, R, Opts, SFC);
-
-return Result;
   }
 }
 
+return Result;
+  }
+};
+
+class DefaultExpressionHandler final : public ExpressionHandler {
+public:
+  using ExpressionHandler::ExpressionHandler;
+
+  Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
+ const ExplodedNode *LVNode,
+ TrackingOptions Opts) override {
+ProgramStateRef LVState = LVNode->getState();
+const StackFrameContext *SFC = LVNode->getStackFrame();
+PathSensitiveBugReport  = getParentTracker().getReport();
+Tracker::Result Result;
+
 // If the expression is not an "lvalue expression", we can still
 // track the constraints on its contents.
 SVal V = LVState->getSValAsScalarOrLoc(Inner, 
LVNode->getLocationContext());
@@ -2332,6 +2346,7 @@ Tracker::Tracker(PathSensitiveBugReport ) : 
Report(Report) {
   addLowPriorityHandler();
   addLowPriorityHandler();
   addLowPriorityHandler();
+  addLowPriorityHandler();
   addLowPriorityHandler();
   addLowPriorityHandler();
   // Default store handlers.



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


[clang] 40cb73b - [analyzer] Extract ArrayIndexHandler

2021-06-15 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-15T11:37:36+03:00
New Revision: 40cb73bd20735051eb8f2d43735097d2ff46f0a7

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

LOG: [analyzer] Extract ArrayIndexHandler

One interesting problem was discovered here.  When we do interrupt
Tracker's track flow, we want to interrupt only it and not all the
other flows recursively.

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 29768f79c5dd..23f925e49b15 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -2134,6 +2134,23 @@ class NilReceiverHandler final : public 
ExpressionHandler {
   }
 };
 
+class ArrayIndexHandler final : public ExpressionHandler {
+public:
+  using ExpressionHandler::ExpressionHandler;
+
+  Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
+ const ExplodedNode *LVNode,
+ TrackingOptions Opts) override {
+// Track the index if this is an array subscript.
+if (const auto *Arr = dyn_cast(Inner))
+  return getParentTracker().track(
+  Arr->getIdx(), LVNode,
+  {Opts.Kind, /*EnableNullFPSuppression*/ false});
+
+return {};
+  }
+};
+
 class DefaultExpressionHandler final : public ExpressionHandler {
 public:
   using ExpressionHandler::ExpressionHandler;
@@ -2146,12 +2163,6 @@ class DefaultExpressionHandler final : public 
ExpressionHandler {
 PathSensitiveBugReport  = getParentTracker().getReport();
 Tracker::Result Result;
 
-// Track the index if this is an array subscript.
-if (const auto *Arr = dyn_cast(Inner))
-  Result.combineWith(getParentTracker().track(
-  Arr->getIdx(), LVNode,
-  {Opts.Kind, /*EnableNullFPSuppression*/ false}));
-
 // See if the expression we're interested refers to a variable.
 // If so, we can track both its contents and constraints on its value.
 if (ExplodedGraph::isInterestingLValueExpr(Inner)) {
@@ -2320,6 +2331,7 @@ Tracker::Tracker(PathSensitiveBugReport ) : 
Report(Report) {
   // Default expression handlers.
   addLowPriorityHandler();
   addLowPriorityHandler();
+  addLowPriorityHandler();
   addLowPriorityHandler();
   addLowPriorityHandler();
   // Default store handlers.
@@ -2340,8 +2352,12 @@ Tracker::Result Tracker::track(const Expr *E, const 
ExplodedNode *N,
   // Iterate through the handlers in the order according to their priorities.
   for (ExpressionHandlerPtr  : ExpressionHandlers) {
 CombinedResult.combineWith(Handler->handle(Inner, N, LVNode, Opts));
-if (CombinedResult.WasInterrupted)
+if (CombinedResult.WasInterrupted) {
+  // There is no need to confuse our users here.
+  // We got interrupted, but our users don't need to know about it.
+  CombinedResult.WasInterrupted = false;
   break;
+}
   }
 
   return CombinedResult;



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


[clang] 1639dcb - [analyzer] Extract NilReceiverHandler

2021-06-15 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-15T11:37:36+03:00
New Revision: 1639dcb2798469c4372e50bcb6b4cf36ecffd9ce

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

LOG: [analyzer] Extract NilReceiverHandler

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 10b674be4972..29768f79c5dd 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -2116,24 +2116,35 @@ class ControlDependencyHandler final : public 
ExpressionHandler {
   }
 };
 
-class DefaultExpressionHandler final : public ExpressionHandler {
+class NilReceiverHandler final : public ExpressionHandler {
 public:
   using ExpressionHandler::ExpressionHandler;
 
   Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
  const ExplodedNode *LVNode,
  TrackingOptions Opts) override {
-ProgramStateRef LVState = LVNode->getState();
-const StackFrameContext *SFC = LVNode->getStackFrame();
-PathSensitiveBugReport  = getParentTracker().getReport();
-Tracker::Result Result;
-
 // The message send could be nil due to the receiver being nil.
 // At this point in the path, the receiver should be live since we are at
 // the message send expr. If it is nil, start tracking it.
 if (const Expr *Receiver =
 NilReceiverBRVisitor::getNilReceiver(Inner, LVNode))
-  Result.combineWith(getParentTracker().track(Receiver, LVNode, Opts));
+  return getParentTracker().track(Receiver, LVNode, Opts);
+
+return {};
+  }
+};
+
+class DefaultExpressionHandler final : public ExpressionHandler {
+public:
+  using ExpressionHandler::ExpressionHandler;
+
+  Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
+ const ExplodedNode *LVNode,
+ TrackingOptions Opts) override {
+ProgramStateRef LVState = LVNode->getState();
+const StackFrameContext *SFC = LVNode->getStackFrame();
+PathSensitiveBugReport  = getParentTracker().getReport();
+Tracker::Result Result;
 
 // Track the index if this is an array subscript.
 if (const auto *Arr = dyn_cast(Inner))
@@ -2308,6 +2319,7 @@ class PRValueHandler final : public ExpressionHandler {
 Tracker::Tracker(PathSensitiveBugReport ) : Report(Report) {
   // Default expression handlers.
   addLowPriorityHandler();
+  addLowPriorityHandler();
   addLowPriorityHandler();
   addLowPriorityHandler();
   // Default store handlers.



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


[clang] 85f475c - [analyzer] Extract ControlDependencyHandler

2021-06-15 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-15T11:37:36+03:00
New Revision: 85f475c979aa49b1b833c9e66af9cb35eafd02c7

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

LOG: [analyzer] Extract ControlDependencyHandler

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 0d0b34d7782a..10b674be4972 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -2088,17 +2088,14 @@ class DefaultStoreHandler final : public StoreHandler {
   }
 };
 
-class DefaultExpressionHandler final : public ExpressionHandler {
+class ControlDependencyHandler final : public ExpressionHandler {
 public:
   using ExpressionHandler::ExpressionHandler;
 
   Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
  const ExplodedNode *LVNode,
  TrackingOptions Opts) override {
-ProgramStateRef LVState = LVNode->getState();
-const StackFrameContext *SFC = LVNode->getStackFrame();
 PathSensitiveBugReport  = getParentTracker().getReport();
-Tracker::Result Result;
 
 // We only track expressions if we believe that they are important. Chances
 // are good that control dependencies to the tracking point are also
@@ -2106,14 +2103,31 @@ class DefaultExpressionHandler final : public 
ExpressionHandler {
 // this point.
 // TODO: Shouldn't we track control dependencies of every bug location,
 // rather than only tracked expressions?
-if (LVState->getAnalysisManager()
+if (LVNode->getState()
+->getAnalysisManager()
 .getAnalyzerOptions()
 .ShouldTrackConditions) {
   Report.addVisitor(
   (), InputNode);
-  Result.FoundSomethingToTrack = true;
+  return {/*FoundSomethingToTrack=*/true};
 }
 
+return {};
+  }
+};
+
+class DefaultExpressionHandler final : public ExpressionHandler {
+public:
+  using ExpressionHandler::ExpressionHandler;
+
+  Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
+ const ExplodedNode *LVNode,
+ TrackingOptions Opts) override {
+ProgramStateRef LVState = LVNode->getState();
+const StackFrameContext *SFC = LVNode->getStackFrame();
+PathSensitiveBugReport  = getParentTracker().getReport();
+Tracker::Result Result;
+
 // The message send could be nil due to the receiver being nil.
 // At this point in the path, the receiver should be live since we are at
 // the message send expr. If it is nil, start tracking it.
@@ -2293,7 +2307,8 @@ class PRValueHandler final : public ExpressionHandler {
 
 Tracker::Tracker(PathSensitiveBugReport ) : Report(Report) {
   // Default expression handlers.
-  addHighPriorityHandler();
+  addLowPriorityHandler();
+  addLowPriorityHandler();
   addLowPriorityHandler();
   // Default store handlers.
   addHighPriorityHandler();



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


[clang] bbebf38 - [analyzer] Refactor StoreSiteFinder and extract DefaultStoreHandler

2021-06-15 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-15T11:37:35+03:00
New Revision: bbebf38b736a12c9582f9ae59c8e245a6ed68cb8

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

LOG: [analyzer] Refactor StoreSiteFinder and extract DefaultStoreHandler

After this patch, custom StoreHandlers will also work as expected.

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

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h 
b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index 047b2072bbcd9..8e39229ab1fd6 100644
--- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -125,6 +125,9 @@ struct StoreInfo {
 ///   int x;
 ///   x = 42;
 Assignment,
+/// The value got stored into the parameter region as the result
+/// of a call.
+CallArgument,
 /// The value got stored into the region as block capture.
 /// Block data is modeled as a separate region, thus whenever
 /// the analyzer sees a captured variable, its value is copied
@@ -138,7 +141,7 @@ struct StoreInfo {
   const ExplodedNode *StoreSite;
   /// The expression where the value comes from.
   /// NOTE: might be null.
-  Expr *SourceOfTheValue;
+  const Expr *SourceOfTheValue;
   /// Symbolic value that is being stored.
   SVal Value;
   /// Memory regions involved in the store operation.
@@ -230,7 +233,8 @@ class Tracker : public llvm::RefCountedBase {
   /// \param Opts Tracking options specifying how we got to it.
   ///
   /// NOTE: this method is designed for sub-trackers and visitors.
-  virtual PathDiagnosticPieceRef handle(StoreInfo SI, TrackingOptions Opts);
+  virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext ,
+TrackingOptions Opts);
 
   /// Add custom expression handler with the highest priority.
   ///
@@ -322,7 +326,8 @@ class StoreHandler {
   ///
   /// \return the produced note, null if the handler doesn't support this kind
   /// of stores.
-  virtual PathDiagnosticPieceRef handle(StoreInfo SI, TrackingOptions Opts) = 
0;
+  virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext ,
+TrackingOptions Opts) = 0;
 
   Tracker () { return ParentTracker; }
 };

diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index c51b7db2b2f3c..0d0b34d7782a0 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1232,12 +1232,7 @@ class StoreSiteFinder final : public 
TrackingBugReporterVisitor {
   SVal V;
   bool Satisfied = false;
 
-  /// If the visitor is tracking the value directly responsible for the
-  /// bug, we are going to employ false positive suppression.
-  bool EnableNullFPSuppression;
-
-  using TrackingKind = bugreporter::TrackingKind;
-  TrackingKind TKind;
+  TrackingOptions Options;
   const StackFrameContext *OriginSFC;
 
 public:
@@ -1252,11 +1247,9 @@ class StoreSiteFinder final : public 
TrackingBugReporterVisitor {
   ///this visitor can prevent that without polluting the bugpath too
   ///much.
   StoreSiteFinder(bugreporter::TrackerRef ParentTracker, KnownSVal V,
-  const MemRegion *R, bool InEnableNullFPSuppression,
-  TrackingKind TKind,
+  const MemRegion *R, TrackingOptions Options,
   const StackFrameContext *OriginSFC = nullptr)
-  : TrackingBugReporterVisitor(ParentTracker), R(R), V(V),
-EnableNullFPSuppression(InEnableNullFPSuppression), TKind(TKind),
+  : TrackingBugReporterVisitor(ParentTracker), R(R), V(V), 
Options(Options),
 OriginSFC(OriginSFC) {
 assert(R);
   }
@@ -1273,8 +1266,8 @@ void StoreSiteFinder::Profile(llvm::FoldingSetNodeID ) 
const {
   ID.AddPointer();
   ID.AddPointer(R);
   ID.Add(V);
-  ID.AddInteger(static_cast(TKind));
-  ID.AddBoolean(EnableNullFPSuppression);
+  ID.AddInteger(static_cast(Options.Kind));
+  ID.AddBoolean(Options.EnableNullFPSuppression);
 }
 
 /// Returns true if \p N represents the DeclStmt declaring and initializing
@@ -1533,8 +1526,7 @@ PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const 
ExplodedNode *Succ,
 if (!IsParam)
   InitE = InitE->IgnoreParenCasts();
 
-getParentTracker().track(InitE, StoreSite,
- {TKind, EnableNullFPSuppression});
+

[clang] 57006d2 - [analyzer] Refactor trackExpressionValue to accept TrackingOptions

2021-06-11 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-11T12:49:04+03:00
New Revision: 57006d2f6d96d8a6836ae901218ed615071b3b8e

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

LOG: [analyzer] Refactor trackExpressionValue to accept TrackingOptions

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

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h 
b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index ba652be33fb5..17a8e7859a54 100644
--- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -353,9 +353,7 @@ class TrackingBugReporterVisitor : public 
BugReporterVisitor {
 /// statement. Note that returning \c true does not actually imply
 /// that any visitors were added.
 bool trackExpressionValue(const ExplodedNode *N, const Expr *E,
-  PathSensitiveBugReport ,
-  TrackingKind TKind = TrackingKind::Thorough,
-  bool EnableNullFPSuppression = true);
+  PathSensitiveBugReport , TrackingOptions Opts = 
{});
 
 /// Track how the value got stored into the given region and where it came
 /// from.

diff  --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
index 837213875a60..b72d72580c28 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
@@ -284,8 +284,9 @@ void MIGChecker::checkReturnAux(const ReturnStmt *RS, 
CheckerContext ) const {
   N);
 
   R->addRange(RS->getSourceRange());
-  bugreporter::trackExpressionValue(N, RS->getRetValue(), *R,
-bugreporter::TrackingKind::Thorough, 
false);
+  bugreporter::trackExpressionValue(
+  N, RS->getRetValue(), *R,
+  {bugreporter::TrackingKind::Thorough, 
/*EnableNullFPSuppression=*/false});
   C.emitReport(std::move(R));
 }
 

diff  --git a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
index 8c2008a7ceb4..13985af76b00 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
@@ -147,8 +147,9 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE,
   auto R = std::make_unique(
   *BT, "Index is out of bounds", N);
   R->addRange(IdxExpr->getSourceRange());
-  bugreporter::trackExpressionValue(
-  N, IdxExpr, *R, bugreporter::TrackingKind::Thorough, false);
+  bugreporter::trackExpressionValue(N, IdxExpr, *R,
+{bugreporter::TrackingKind::Thorough,
+ /*EnableNullFPSuppression=*/false});
   C.emitReport(std::move(R));
   return;
 }

diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index ede76154ac7a..c51b7db2b2f3 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -2314,11 +2314,11 @@ PathDiagnosticPieceRef Tracker::handle(StoreInfo SI, 
TrackingOptions Opts) {
 
 bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode,
const Expr *E,
-   PathSensitiveBugReport ,
-   bugreporter::TrackingKind TKind,
-   bool EnableNullFPSuppression) {
-  return Tracker::create(report)
-  ->track(E, InputNode, {TKind, EnableNullFPSuppression})
+
+   PathSensitiveBugReport ,
+   TrackingOptions Opts) {
+  return Tracker::create(Report)
+  ->track(E, InputNode, Opts)
   .FoundSomethingToTrack;
 }
 
@@ -2375,9 +2375,9 @@ NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, 
BugReporterContext ,
   // The receiver was nil, and hence the method was skipped.
   // Register a BugReporterVisitor to issue a message telling us how
   // the receiver was null.
-  bugreporter::trackExpressionValue(
-  N, Receiver, BR, bugreporter::TrackingKind::Thorough,
-  /*EnableNullFPSuppression*/ false);
+  bugreporter::trackExpressionValue(N, Receiver, BR,
+  

[clang] 51d4704 - [analyzer] Turn TrackControlDependencyCond into a tracking visitor

2021-06-11 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-11T12:49:04+03:00
New Revision: 51d4704d5ec9b8e4e5e445ee69c56a58250e370e

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

LOG: [analyzer] Turn TrackControlDependencyCond into a tracking visitor

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 677a1d39d8a0..ede76154ac7a 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1855,14 +1855,17 @@ namespace {
 /// An error is emitted at line 3. This visitor realizes that the branch
 /// on line 2 is a control dependency of line 3, and tracks it's condition via
 /// trackExpressionValue().
-class TrackControlDependencyCondBRVisitor final : public BugReporterVisitor {
+class TrackControlDependencyCondBRVisitor final
+: public TrackingBugReporterVisitor {
   const ExplodedNode *Origin;
   ControlDependencyCalculator ControlDeps;
   llvm::SmallSet VisitedBlocks;
 
 public:
-  TrackControlDependencyCondBRVisitor(const ExplodedNode *O)
-  : Origin(O), ControlDeps(>getCFG()) {}
+  TrackControlDependencyCondBRVisitor(TrackerRef ParentTracker,
+  const ExplodedNode *O)
+  : TrackingBugReporterVisitor(ParentTracker), Origin(O),
+ControlDeps(>getCFG()) {}
 
   void Profile(llvm::FoldingSetNodeID ) const override {
 static int x = 0;
@@ -1960,9 +1963,9 @@ TrackControlDependencyCondBRVisitor::VisitNode(const 
ExplodedNode *N,
   // isn't sufficient, because a new visitor is created for each tracked
   // expression, hence the BugReport level set.
   if (BR.addTrackedCondition(N)) {
-bugreporter::trackExpressionValue(
-N, Condition, BR, bugreporter::TrackingKind::Condition,
-/*EnableNullFPSuppression=*/false);
+getParentTracker().track(Condition, N,
+ {bugreporter::TrackingKind::Condition,
+  /*EnableNullFPSuppression=*/false});
 return constructDebugPieceForTrackedCondition(Condition, N, BRC);
   }
 }
@@ -2078,7 +2081,8 @@ class DefaultExpressionHandler final : public 
ExpressionHandler {
 if (LVState->getAnalysisManager()
 .getAnalyzerOptions()
 .ShouldTrackConditions) {
-  Report.addVisitor(InputNode);
+  Report.addVisitor(
+  (), InputNode);
   Result.FoundSomethingToTrack = true;
 }
 



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


[clang] 3fc8d94 - [analyzer] Refactor trackRValueExpression into ExpressionHandler

2021-06-11 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-11T12:49:04+03:00
New Revision: 3fc8d943c360f801a428ff24569d2dd53a2afe0f

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

LOG: [analyzer] Refactor trackRValueExpression into ExpressionHandler

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 651c80276110..677a1d39d8a0 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -2053,44 +2053,6 @@ static const ExplodedNode* findNodeForExpression(const 
ExplodedNode *N,
   return N;
 }
 
-/// Attempts to add visitors to track an RValue expression back to its point of
-/// origin. Works similarly to trackExpressionValue, but accepts only RValues.
-static void trackRValueExpression(const ExplodedNode *InputNode, const Expr *E,
-  PathSensitiveBugReport ,
-  bugreporter::TrackingKind TKind,
-  bool EnableNullFPSuppression) {
-  assert(E->isPRValue() && "The expression is not a prvalue!");
-  const ExplodedNode *RVNode = findNodeForExpression(InputNode, E);
-  if (!RVNode)
-return;
-  ProgramStateRef RVState = RVNode->getState();
-  SVal V = RVState->getSValAsScalarOrLoc(E, RVNode->getLocationContext());
-  const auto *BO = dyn_cast(E);
-  if (!BO)
-return;
-  if (!V.isZeroConstant())
-return;
-  if (!BO->isMultiplicativeOp())
-return;
-
-  SVal RHSV = RVState->getSVal(BO->getRHS(), RVNode->getLocationContext());
-  SVal LHSV = RVState->getSVal(BO->getLHS(), RVNode->getLocationContext());
-
-  // Track both LHS and RHS of a multiplication.
-  if (BO->getOpcode() == BO_Mul) {
-if (LHSV.isZeroConstant())
-  trackExpressionValue(InputNode, BO->getLHS(), report, TKind,
-   EnableNullFPSuppression);
-if (RHSV.isZeroConstant())
-  trackExpressionValue(InputNode, BO->getRHS(), report, TKind,
-   EnableNullFPSuppression);
-  } else { // Track only the LHS of a division or a modulo.
-if (LHSV.isZeroConstant())
-  trackExpressionValue(InputNode, BO->getLHS(), report, TKind,
-   EnableNullFPSuppression);
-  }
-}
-
 
//===--===//
 //Tracker implementation
 
//===--===//
@@ -2245,17 +2207,61 @@ class DefaultExpressionHandler final : public 
ExpressionHandler {
   }
 }
 
-if (Inner->isPRValue())
-  // TODO: Incorporate as Handler
-  trackRValueExpression(LVNode, Inner, Report, Opts.Kind,
-Opts.EnableNullFPSuppression);
-
 return Result;
   }
 };
 
+/// Attempts to add visitors to track an RValue expression back to its point of
+/// origin.
+class PRValueHandler final : public ExpressionHandler {
+public:
+  using ExpressionHandler::ExpressionHandler;
+
+  Tracker::Result handle(const Expr *E, const ExplodedNode *InputNode,
+ const ExplodedNode *ExprNode,
+ TrackingOptions Opts) override {
+if (!E->isPRValue())
+  return {};
+
+const ExplodedNode *RVNode = findNodeForExpression(ExprNode, E);
+if (!RVNode)
+  return {};
+
+ProgramStateRef RVState = RVNode->getState();
+SVal V = RVState->getSValAsScalarOrLoc(E, RVNode->getLocationContext());
+const auto *BO = dyn_cast(E);
+
+if (!BO || !BO->isMultiplicativeOp() || !V.isZeroConstant())
+  return {};
+
+SVal RHSV = RVState->getSVal(BO->getRHS(), RVNode->getLocationContext());
+SVal LHSV = RVState->getSVal(BO->getLHS(), RVNode->getLocationContext());
+
+// Track both LHS and RHS of a multiplication.
+Tracker::Result CombinedResult;
+Tracker  = getParentTracker();
+
+const auto track = [, , ExprNode, Opts](Expr *Inner) 
{
+  CombinedResult.combineWith(Parent.track(Inner, ExprNode, Opts));
+};
+
+if (BO->getOpcode() == BO_Mul) {
+  if (LHSV.isZeroConstant())
+track(BO->getLHS());
+  if (RHSV.isZeroConstant())
+track(BO->getRHS());
+} else { // Track only the LHS of a division or a modulo.
+  if (LHSV.isZeroConstant())
+track(BO->getLHS());
+}
+
+return CombinedResult;
+  }
+};
+
 Tracker::Tracker(PathSensitiveBugReport ) : Report(Report) {
   addHighPriorityHandler();
+  addLowPriorityHandler();
   // TODO: split trackExpressionValue and FindLastStoreBRVisitor into handlers
   //   

[clang] f853d26 - [analyzer] Turn ReturnVisitor into a tracking visitor

2021-06-11 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-11T12:49:03+03:00
New Revision: f853d2601abd4f6ab789ca1513ae8b59ba5d38b7

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

LOG: [analyzer] Turn ReturnVisitor into a tracking visitor

Whenever Tracker spawns a visitor that needs to call tracker
back, we have to use TrackingBugReporterVisitor in order to maintain
all the hooks that the checker might've used.

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index af553a2b5903..651c80276110 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -906,7 +906,7 @@ namespace {
 ///
 /// This visitor is intended to be used when another visitor discovers that an
 /// interesting value comes from an inlined function call.
-class ReturnVisitor : public BugReporterVisitor {
+class ReturnVisitor : public TrackingBugReporterVisitor {
   const StackFrameContext *CalleeSFC;
   enum {
 Initial,
@@ -920,10 +920,11 @@ class ReturnVisitor : public BugReporterVisitor {
   bugreporter::TrackingKind TKind;
 
 public:
-  ReturnVisitor(const StackFrameContext *Frame, bool Suppressed,
-AnalyzerOptions , bugreporter::TrackingKind TKind)
-  : CalleeSFC(Frame), EnableNullFPSuppression(Suppressed),
-Options(Options), TKind(TKind) {}
+  ReturnVisitor(TrackerRef ParentTracker, const StackFrameContext *Frame,
+bool Suppressed, AnalyzerOptions ,
+bugreporter::TrackingKind TKind)
+  : TrackingBugReporterVisitor(ParentTracker), CalleeSFC(Frame),
+EnableNullFPSuppression(Suppressed), Options(Options), TKind(TKind) {}
 
   static void *getTag() {
 static int Tag = 0;
@@ -943,7 +944,8 @@ class ReturnVisitor : public BugReporterVisitor {
   /// node, looking for when the given statement was processed. If it turns out
   /// the statement is a call that was inlined, we add the visitor to the
   /// bug report, so it can print a note later.
-  static void addVisitorIfNecessary(const ExplodedNode *Node, const Stmt *S,
+  static void addVisitorIfNecessary(TrackerRef ParentTracker,
+const ExplodedNode *Node, const Stmt *S,
 PathSensitiveBugReport ,
 bool InEnableNullFPSuppression,
 bugreporter::TrackingKind TKind) {
@@ -1016,8 +1018,8 @@ class ReturnVisitor : public BugReporterVisitor {
   if (Optional RetLoc = RetVal.getAs())
 EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
 
-BR.addVisitor(CalleeContext, EnableNullFPSuppression,
- Options, TKind);
+BR.addVisitor(ParentTracker, CalleeContext,
+ EnableNullFPSuppression, Options, TKind);
   }
 
   PathDiagnosticPieceRef visitNodeInitial(const ExplodedNode *N,
@@ -1066,8 +1068,7 @@ class ReturnVisitor : public BugReporterVisitor {
 RetE = RetE->IgnoreParenCasts();
 
 // Let's track the return value.
-bugreporter::trackExpressionValue(
-N, RetE, BR, TKind, EnableNullFPSuppression);
+getParentTracker().track(RetE, N, {TKind, EnableNullFPSuppression});
 
 // Build an appropriate message based on the return value.
 SmallString<64> Msg;
@@ -1183,7 +1184,9 @@ class ReturnVisitor : public BugReporterVisitor {
   if (!State->isNull(*ArgV).isConstrainedTrue())
 continue;
 
-  if (trackExpressionValue(N, ArgE, BR, TKind, EnableNullFPSuppression))
+  if (getParentTracker()
+  .track(ArgE, N, {TKind, EnableNullFPSuppression})
+  .FoundSomethingToTrack)
 ShouldInvalidate = false;
 
   // If we /can't/ track the null pointer, we should err on the side of
@@ -2197,8 +2200,9 @@ class DefaultExpressionHandler final : public 
ExpressionHandler {
 // track the constraints on its contents.
 SVal V = LVState->getSValAsScalarOrLoc(Inner, 
LVNode->getLocationContext());
 
-ReturnVisitor::addVisitorIfNecessary(
-LVNode, Inner, Report, Opts.EnableNullFPSuppression, Opts.Kind);
+ReturnVisitor::addVisitorIfNecessary((), LVNode, Inner,
+ Report, Opts.EnableNullFPSuppression,
+ Opts.Kind);
 
 // Is it a symbolic value?
 if (auto L = V.getAs()) {



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

[clang] 87a5c4d - [analyzer] Hide and rename FindLastStoreBRVisitor

2021-06-11 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-11T12:49:03+03:00
New Revision: 87a5c4d3745a06ec0594fa3f7aaf7f58a53315ec

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

LOG: [analyzer] Hide and rename FindLastStoreBRVisitor

This component should not be used directly at this point and it is
simply an implementation detail, that's why StoreSiteFinder is
out of the header file.

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

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h 
b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index 4b0d5378e0c13..ba652be33fb52 100644
--- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -378,50 +378,6 @@ const Expr *getDerefExpr(const Stmt *S);
 
 } // namespace bugreporter
 
-/// Finds last store into the given region,
-/// which is 
diff erent from a given symbolic value.
-class FindLastStoreBRVisitor final
-: public bugreporter::TrackingBugReporterVisitor {
-  const MemRegion *R;
-  SVal V;
-  bool Satisfied = false;
-
-  /// If the visitor is tracking the value directly responsible for the
-  /// bug, we are going to employ false positive suppression.
-  bool EnableNullFPSuppression;
-
-  using TrackingKind = bugreporter::TrackingKind;
-  TrackingKind TKind;
-  const StackFrameContext *OriginSFC;
-
-public:
-  /// \param V We're searching for the store where \c R received this value.
-  /// \param R The region we're tracking.
-  /// \param TKind May limit the amount of notes added to the bug report.
-  /// \param OriginSFC Only adds notes when the last store happened in a
-  ///
diff erent stackframe to this one. Disregarded if the tracking kind
-  ///is thorough.
-  ///This is useful, because for non-tracked regions, notes about
-  ///changes to its value in a nested stackframe could be pruned, and
-  ///this visitor can prevent that without polluting the bugpath too
-  ///much.
-  FindLastStoreBRVisitor(bugreporter::TrackerRef ParentTracker, KnownSVal V,
- const MemRegion *R, bool InEnableNullFPSuppression,
- TrackingKind TKind,
- const StackFrameContext *OriginSFC = nullptr)
-  : TrackingBugReporterVisitor(ParentTracker), R(R), V(V),
-EnableNullFPSuppression(InEnableNullFPSuppression), TKind(TKind),
-OriginSFC(OriginSFC) {
-assert(R);
-  }
-
-  void Profile(llvm::FoldingSetNodeID ) const override;
-
-  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
-   BugReporterContext ,
-   PathSensitiveBugReport ) override;
-};
-
 class TrackConstraintBRVisitor final : public BugReporterVisitor {
   DefinedSVal Constraint;
   bool Assumption;

diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index ec16a4deae029..af553a2b5903e 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1219,10 +1219,53 @@ class ReturnVisitor : public BugReporterVisitor {
 } // end of anonymous namespace
 
 
//===--===//
-// Implementation of FindLastStoreBRVisitor.
+//   StoreSiteFinder
 
//===--===//
 
-void FindLastStoreBRVisitor::Profile(llvm::FoldingSetNodeID ) const {
+/// Finds last store into the given region,
+/// which is 
diff erent from a given symbolic value.
+class StoreSiteFinder final : public TrackingBugReporterVisitor {
+  const MemRegion *R;
+  SVal V;
+  bool Satisfied = false;
+
+  /// If the visitor is tracking the value directly responsible for the
+  /// bug, we are going to employ false positive suppression.
+  bool EnableNullFPSuppression;
+
+  using TrackingKind = bugreporter::TrackingKind;
+  TrackingKind TKind;
+  const StackFrameContext *OriginSFC;
+
+public:
+  /// \param V We're searching for the store where \c R received this value.
+  /// \param R The region we're tracking.
+  /// \param TKind May limit the amount of notes added to the bug report.
+  /// \param OriginSFC Only adds notes when the last store happened in a
+  ///
diff erent stackframe to this one. Disregarded if the tracking kind
+  ///is thorough.
+  ///This is useful, because for 

[clang] b6bcf95 - [analyzer] Change FindLastStoreBRVisitor to use Tracker

2021-06-11 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-11T12:49:03+03:00
New Revision: b6bcf953220db7880f2bb508f6f5c02b41078b2c

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

LOG: [analyzer] Change FindLastStoreBRVisitor to use Tracker

Additionally, this commit completely removes any uses of
FindLastStoreBRVisitor from the analyzer except for the
one in Tracker.

The next step is actually removing this class altogether
from the header file.

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

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h

clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h 
b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index 5c4345a32c8d3..4b0d5378e0c13 100644
--- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -19,6 +19,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 #include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include 
@@ -147,6 +148,9 @@ struct StoreInfo {
   const MemRegion *Dest, *Origin;
 };
 
+class Tracker;
+using TrackerRef = llvm::IntrusiveRefCntPtr;
+
 class ExpressionHandler;
 class StoreHandler;
 
@@ -155,7 +159,7 @@ class StoreHandler;
 /// Tracker aimes at providing a sensible set of default behaviors that can be
 /// used by any checker, while providing mechanisms to hook into any part of 
the
 /// tracking process and insert checker-specific logic.
-class Tracker {
+class Tracker : public llvm::RefCountedBase {
 private:
   using ExpressionHandlerPtr = std::unique_ptr;
   using StoreHandlerPtr = std::unique_ptr;
@@ -164,11 +168,17 @@ class Tracker {
   std::list ExpressionHandlers;
   std::list StoreHandlers;
 
-public:
+protected:
   /// \param Report The bug report to which visitors should be attached.
   Tracker(PathSensitiveBugReport );
+
+public:
   virtual ~Tracker() = default;
 
+  static TrackerRef create(PathSensitiveBugReport ) {
+return new Tracker(Report);
+  }
+
   PathSensitiveBugReport () { return Report; }
 
   /// Describes a tracking result with the most basic information of what was
@@ -318,6 +328,18 @@ class StoreHandler {
   Tracker () { return ParentTracker; }
 };
 
+/// Visitor that tracks expressions and values.
+class TrackingBugReporterVisitor : public BugReporterVisitor {
+private:
+  TrackerRef ParentTracker;
+
+public:
+  TrackingBugReporterVisitor(TrackerRef ParentTracker)
+  : ParentTracker(ParentTracker) {}
+
+  Tracker () { return *ParentTracker; }
+};
+
 /// Attempts to add visitors to track expression value back to its point of
 /// origin.
 ///
@@ -335,13 +357,31 @@ bool trackExpressionValue(const ExplodedNode *N, const 
Expr *E,
   TrackingKind TKind = TrackingKind::Thorough,
   bool EnableNullFPSuppression = true);
 
+/// Track how the value got stored into the given region and where it came
+/// from.
+///
+/// \param V We're searching for the store where \c R received this value.
+/// \param R The region we're tracking.
+/// \param Opts Tracking options specifying how we want to track the value.
+/// \param Origin Only adds notes when the last store happened in a
+///
diff erent stackframe to this one. Disregarded if the tracking kind
+///is thorough.
+///This is useful, because for non-tracked regions, notes about
+///changes to its value in a nested stackframe could be pruned, and
+///this visitor can prevent that without polluting the bugpath too
+///much.
+void trackStoredValue(KnownSVal V, const MemRegion *R,
+  PathSensitiveBugReport , TrackingOptions Opts = 
{},
+  const StackFrameContext *Origin = nullptr);
+
 const Expr *getDerefExpr(const Stmt *S);
 
 } // namespace bugreporter
 
 /// Finds last store into the given region,
 /// which is 
diff erent from a given symbolic value.
-class FindLastStoreBRVisitor final : public BugReporterVisitor {
+class FindLastStoreBRVisitor final
+: public bugreporter::TrackingBugReporterVisitor {
   const MemRegion *R;
   SVal V;
   bool Satisfied = false;
@@ -365,11 +405,13 @@ class FindLastStoreBRVisitor final : public 
BugReporterVisitor {
   ///changes to its value in a 

[clang] 967c06b - [analyzer] Reimplement trackExpressionValue as ExpressionHandler

2021-06-11 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-11T12:49:03+03:00
New Revision: 967c06b3e95ba776fb06ad0ea5aa699cf2e1b59a

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

LOG: [analyzer] Reimplement trackExpressionValue as ExpressionHandler

This commit moves trackExpressionValue into the Tracker interface
as DefaultExpressionHandler.  It still can be split into smaller
handlers, but that can be a future change.

Additionally, this commit doesn't remove the original trackExpressionValue
interface, so it's not too big.  One of the next commits will address it.

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 9359a5fe80f1..2df3687f2bb4 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -2050,7 +2050,166 @@ static void trackRValueExpression(const ExplodedNode 
*InputNode, const Expr *E,
 //Tracker implementation
 
//===--===//
 
+class DefaultExpressionHandler final : public ExpressionHandler {
+public:
+  using ExpressionHandler::ExpressionHandler;
+
+  Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
+ const ExplodedNode *LVNode,
+ TrackingOptions Opts) override {
+ProgramStateRef LVState = LVNode->getState();
+const StackFrameContext *SFC = LVNode->getStackFrame();
+PathSensitiveBugReport  = getParentTracker().getReport();
+Tracker::Result Result;
+
+// We only track expressions if we believe that they are important. Chances
+// are good that control dependencies to the tracking point are also
+// important because of this, let's explain why we believe control reached
+// this point.
+// TODO: Shouldn't we track control dependencies of every bug location,
+// rather than only tracked expressions?
+if (LVState->getAnalysisManager()
+.getAnalyzerOptions()
+.ShouldTrackConditions) {
+  Report.addVisitor(InputNode);
+  Result.FoundSomethingToTrack = true;
+}
+
+// The message send could be nil due to the receiver being nil.
+// At this point in the path, the receiver should be live since we are at
+// the message send expr. If it is nil, start tracking it.
+if (const Expr *Receiver =
+NilReceiverBRVisitor::getNilReceiver(Inner, LVNode))
+  Result.combineWith(getParentTracker().track(Receiver, LVNode, Opts));
+
+// Track the index if this is an array subscript.
+if (const auto *Arr = dyn_cast(Inner))
+  Result.combineWith(getParentTracker().track(
+  Arr->getIdx(), LVNode,
+  {Opts.Kind, /*EnableNullFPSuppression*/ false}));
+
+// See if the expression we're interested refers to a variable.
+// If so, we can track both its contents and constraints on its value.
+if (ExplodedGraph::isInterestingLValueExpr(Inner)) {
+  SVal LVal = LVNode->getSVal(Inner);
+
+  const MemRegion *RR = getLocationRegionIfReference(Inner, LVNode);
+  bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
+
+  // If this is a C++ reference to a null pointer, we are tracking the
+  // pointer. In addition, we should find the store at which the reference
+  // got initialized.
+  if (RR && !LVIsNull)
+Result.combineWith(getParentTracker().track(LVal, RR, Opts, SFC));
+
+  // In case of C++ references, we want to 
diff erentiate between a null
+  // reference and reference to null pointer.
+  // If the LVal is null, check if we are dealing with null reference.
+  // For those, we want to track the location of the reference.
+  const MemRegion *R =
+  (RR && LVIsNull) ? RR : LVNode->getSVal(Inner).getAsRegion();
+
+  if (R) {
+
+// Mark both the variable region and its contents as interesting.
+SVal V = LVState->getRawSVal(loc::MemRegionVal(R));
+Report.addVisitor(cast(R), Opts.Kind);
+
+// When we got here, we do have something to track, and we will
+// interrupt.
+Result.FoundSomethingToTrack = true;
+Result.WasInterrupted = true;
+
+MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
+LVNode, R, Opts.EnableNullFPSuppression, Report, V);
+
+Report.markInteresting(V, Opts.Kind);
+Report.addVisitor(R);
+
+// If the contents are symbolic and null, find out when they became
+// null.
+if 

[clang] 0cc3100 - [analyzer] Introduce a new interface for tracking

2021-06-11 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-11T12:49:03+03:00
New Revision: 0cc3100bf8d126ce080c0075cf25784b45e5f990

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

LOG: [analyzer] Introduce a new interface for tracking

Tracking values through expressions and the stores is fundamental
for producing clear diagnostics.  However, the main components
participating in this process, namely `trackExpressionValue` and
`FindLastStoreBRVisitor`, became pretty bloated.  They have an
interesting dynamic between them (and some other visitors) that
one might call a "chain reaction". `trackExpressionValue` adds
`FindLastStoreBRVisitor`, and the latter calls `trackExpressionValue`.

Because of this design, individual checkers couldn't affect what's
going to happen somewhere in the middle of that chain.  Whether they
want to produce a more informative note or keep the overall tracking
going by utilizing some of the domain expertise.  This all lead to two
biggest problems that I see:

  * Some checkers don't use it
  This should probably never be the case for path-sensitive checks.

  * Some checkers incorporated their logic directly into those
components
  This doesn't make the maintenance easier, breaks multiple
  architecture principles, and makes the code harder to read adn
  understand, thus, increasing the probability of the first case.

This commit introduces a prototype for a new interface that will be
responsible for tracking.  My main idea here was to make operations
that I want have as a checker developer easy to implement and hook
directly into the tracking process.

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

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h 
b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index 2975d50de3334..5c4345a32c8d3 100644
--- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -21,7 +21,9 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
+#include 
 #include 
+#include 
 
 namespace clang {
 
@@ -99,6 +101,223 @@ enum class TrackingKind {
   Condition
 };
 
+/// Defines a set of options altering tracking behavior.
+struct TrackingOptions {
+  /// Specifies the kind of tracking.
+  TrackingKind Kind = TrackingKind::Thorough;
+  /// Specifies whether we should employ false positive suppression
+  /// (inlined defensive checks, returned null).
+  bool EnableNullFPSuppression = true;
+};
+
+/// Describes an event when the value got stored into a memory region.
+///
+/// As opposed to checker checkBind API, it reacts also to binds
+/// generated by the checker as well.  It can be useful when the binding
+/// happened as a result of evalCall, for example.
+struct StoreInfo {
+  enum Kind {
+/// The value got stored into the region during initialization:
+///   int x = 42;
+Initialization,
+/// The value got stored into the region during assignment:
+///   int x;
+///   x = 42;
+Assignment,
+/// The value got stored into the region as block capture.
+/// Block data is modeled as a separate region, thus whenever
+/// the analyzer sees a captured variable, its value is copied
+/// into a special block region.
+BlockCapture
+  };
+
+  /// The type of store operation.
+  Kind StoreKind;
+  /// The node where the store happened.
+  const ExplodedNode *StoreSite;
+  /// The expression where the value comes from.
+  /// NOTE: might be null.
+  Expr *SourceOfTheValue;
+  /// Symbolic value that is being stored.
+  SVal Value;
+  /// Memory regions involved in the store operation.
+  ///   Dest <- Origin
+  /// NOTE: Origin might be null, when the stored value doesn't come
+  ///   from another region.
+  const MemRegion *Dest, *Origin;
+};
+
+class ExpressionHandler;
+class StoreHandler;
+
+/// A generalized component for tracking expressions, values, and stores.
+///
+/// Tracker aimes at providing a sensible set of default behaviors that can be
+/// used by any checker, while providing mechanisms to hook into any part of 
the
+/// tracking process and insert checker-specific logic.
+class Tracker {
+private:
+  using ExpressionHandlerPtr = std::unique_ptr;
+  using StoreHandlerPtr = std::unique_ptr;
+
+  PathSensitiveBugReport 
+  std::list ExpressionHandlers;
+  std::list StoreHandlers;
+
+public:
+  /// \param Report The bug report to which visitors should be attached.
+  Tracker(PathSensitiveBugReport );
+  

[clang] 92d03c2 - [analyzer] Add forwarding `addVisitor` method

2021-06-03 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-06-03T17:10:16+03:00
New Revision: 92d03c20ea71479c78a29da09e377e040d37c3a5

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

LOG: [analyzer] Add forwarding `addVisitor` method

The majority of all `addVisitor` callers follow the same pattern:
  addVisitor(std::make_unique(arg1, arg2, ...));

This patches introduces additional overload for `addVisitor` to simplify
that pattern:
  addVisitor(arg1, arg2, ...);

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

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp

clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
clang/lib/StaticAnalyzer/Core/BugReporter.cpp
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Removed: 




diff  --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h 
b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 27bc0dda1f1ce..0b12ff7075780 100644
--- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -489,11 +489,16 @@ class PathSensitiveBugReport : public BugReport {
   ///
   /// The visitors should be used when the default trace is not sufficient.
   /// For example, they allow constructing a more elaborate trace.
-  /// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(),
-  /// registerFindLastStore(), registerNilReceiverVisitor(), and
-  /// registerVarDeclsLastStore().
+  /// @{
   void addVisitor(std::unique_ptr visitor);
 
+  template 
+  void addVisitor(Args &&... ConstructorArgs) {
+addVisitor(
+std::make_unique(std::forward(ConstructorArgs)...));
+  }
+  /// @}
+
   /// Remove all visitors attached to this bug report.
   void clearVisitors();
 

diff  --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 1f3a1e1ac7773..e0f0dc35e7a71 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -2123,7 +2123,7 @@ void 
MallocChecker::HandleMismatchedDealloc(CheckerContext ,
   os.str(), N);
 R->markInteresting(Sym);
 R->addRange(Range);
-R->addVisitor(std::make_unique(Sym));
+R->addVisitor(Sym);
 C.emitReport(std::move(R));
   }
 }
@@ -2216,7 +2216,7 @@ void MallocChecker::HandleUseAfterFree(CheckerContext , 
SourceRange Range,
 
 R->markInteresting(Sym);
 R->addRange(Range);
-R->addVisitor(std::make_unique(Sym));
+R->addVisitor(Sym);
 
 if (AF == AF_InnerBuffer)
   R->addVisitor(allocation_state::getInnerPointerBRVisitor(Sym));
@@ -2252,7 +2252,7 @@ void MallocChecker::HandleDoubleFree(CheckerContext , 
SourceRange Range,
 R->markInteresting(Sym);
 if (PrevSym)
   R->markInteresting(PrevSym);
-R->addVisitor(std::make_unique(Sym));
+R->addVisitor(Sym);
 C.emitReport(std::move(R));
   }
 }
@@ -2278,7 +2278,7 @@ void MallocChecker::HandleDoubleDelete(CheckerContext , 
SymbolRef Sym) const {
 *BT_DoubleDelete, "Attempt to delete released memory", N);
 
 R->markInteresting(Sym);
-R->addVisitor(std::make_unique(Sym));
+R->addVisitor(Sym);
 C.emitReport(std::move(R));
   }
 }
@@ -2308,7 +2308,7 @@ void MallocChecker::HandleUseZeroAlloc(CheckerContext , 
SourceRange Range,
 R->addRange(Range);
 if (Sym) {
   R->markInteresting(Sym);
-  R->addVisitor(std::make_unique(Sym));
+  R->addVisitor(Sym);
 }
 C.emitReport(std::move(R));
   }
@@ -2578,7 +2578,7 @@ void MallocChecker::HandleLeak(SymbolRef Sym, 
ExplodedNode *N,
   *BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
   AllocNode->getLocationContext()->getDecl());
   R->markInteresting(Sym);
-  R->addVisitor(std::make_unique(Sym, true));
+  R->addVisitor(Sym, true);
   C.emitReport(std::move(R));
 }
 

diff  --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index bc7a8a3b12a1d..fe8f7e7bf69e7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -170,7 +170,7 @@ class NullabilityChecker
 auto R = std::make_unique(*BT, Msg, N);
 if (Region) {
   R->markInteresting(Region);
-  R->addVisitor(std::make_unique(Region));
+  R->addVisitor(Region);
 }
 if (ValueExpr) {
   R->addRange(ValueExpr->getSourceRange());

diff  --git 

[clang] 45212de - [analyzer][solver] Prevent use of a null state

2021-05-13 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-05-13T20:16:29+03:00
New Revision: 45212dec01b9be90596d8d6fa7586ce8c84e2622

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

LOG: [analyzer][solver] Prevent use of a null state

rdar://77686137

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

Added: 
clang/test/Analysis/PR50268.c

Modified: 
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 974535952d0f0..e54b9c13b9355 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -1487,15 +1487,18 @@ class RangeConstraintManager : public 
RangedConstraintManager {
   // This is an infeasible assumption.
   return nullptr;
 
-ProgramStateRef NewState = setConstraint(State, Sym, NewConstraint);
-if (auto Equality = EqualityInfo::extract(Sym, Int, Adjustment)) {
-  // If the original assumption is not Sym + Adjustment !=/ Int,
-  // we should invert IsEquality flag.
-  Equality->IsEquality = Equality->IsEquality != EQ;
-  return track(NewState, *Equality);
+if (ProgramStateRef NewState = setConstraint(State, Sym, NewConstraint)) {
+  if (auto Equality = EqualityInfo::extract(Sym, Int, Adjustment)) {
+// If the original assumption is not Sym + Adjustment !=/ Int,
+// we should invert IsEquality flag.
+Equality->IsEquality = Equality->IsEquality != EQ;
+return track(NewState, *Equality);
+  }
+
+  return NewState;
 }
 
-return NewState;
+return nullptr;
   }
 
   ProgramStateRef track(ProgramStateRef State, EqualityInfo ToTrack) {

diff  --git a/clang/test/Analysis/PR50268.c b/clang/test/Analysis/PR50268.c
new file mode 100644
index 0..6e3536b7c23c5
--- /dev/null
+++ b/clang/test/Analysis/PR50268.c
@@ -0,0 +1,12 @@
+// RUN: %clang_analyze_cc1 -w -analyzer-checker=core -verify %s \
+// RUN:-analyzer-config eagerly-assume=true
+
+// expected-no-diagnostics
+
+
+int test(unsigned long a, unsigned long c, int b) {
+  c -= a;
+  if (0 >= b) {}
+  c == b;
+  return c ? 0 : 2; // no-crash
+}



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


[clang] 602c8b4 - [analyzer][NFC] Fix tests failing after a rebase

2021-04-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-04-28T18:55:20+03:00
New Revision: 602c8b4db5dbe88be7080b411455538c9b4cd117

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

LOG: [analyzer][NFC] Fix tests failing after a rebase

Added: 


Modified: 
clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist

Removed: 




diff  --git 
a/clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist 
b/clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
index fb92943d00dc..e9f4f7577649 100644
--- 
a/clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
+++ 
b/clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
@@ -6561,12 +6561,12 @@
 start
  
   
-   line381
+   line391
col3
file0
   
   
-   line381
+   line391
col4
file0
   
@@ -6574,12 +6574,12 @@
 end
  
   
-   line381
+   line391
col17
file0
   
   
-   line381
+   line391
col17
file0
   
@@ -6591,7 +6591,7 @@
  kindevent
  location
  
-  line381
+  line391
   col17
   file0
  
@@ -6599,12 +6599,12 @@
  

 
- line381
+ line391
  col17
  file0
 
 
- line381
+ line391
  col37
  file0
 
@@ -6731,7 +6731,7 @@
  kindevent
  location
  
-  line381
+  line391
   col17
   file0
  
@@ -6739,12 +6739,12 @@
  

 
- line381
+ line391
  col17
  file0
 
 
- line381
+ line391
  col37
  file0
 
@@ -6764,12 +6764,12 @@
 start
  
   
-   line381
+   line391
col17
file0
   
   
-   line381
+   line391
col17
file0
   
@@ -6777,12 +6777,12 @@
 end
  
   
-   line381
+   line391
col3
file0
   
   
-   line381
+   line391
col4
file0
   
@@ -6798,12 +6798,12 @@
 start
  
   
-   line381
+   line391
col3
file0
   
   
-   line381
+   line391
col4
file0
   
@@ -6811,12 +6811,12 @@
 end
  
   
-   line385
+   line395
col3
file0
   
   
-   line385
+   line395
col3
file0
   
@@ -6828,7 +6828,7 @@
  kindevent
  location
  
-  line385
+  line395
   col3
   file0
  
@@ -6836,12 +6836,12 @@
  

 
- line385
+ line395
  col3
  file0
 
 
- line385
+ line395
  col20
  file0
 
@@ -6865,7 +6865,7 @@
   issue_hash_function_offset1
   location
   
-   line385
+   line395
col3
file0
   
@@ -6879,10 +6879,10 @@
 219
 220
 221
-380
-381
-384
-385
+390
+391
+394
+395

   
   
@@ -6897,12 +6897,12 @@
 start
  
   
-   line390
+   line400
col3
file0
   
   
-   line390
+   line400
col4
file0
   
@@ -6910,12 +6910,12 @@
 end
  
   
-   line390
+   line400
col17
file0
   
   
-   line390
+   line400
col17
file0
   
@@ -6927,7 +6927,7 @@
  kindevent
  location
  
-  line390
+  line400
   col17
   file0
  
@@ -6935,12 +6935,12 @@
  

 
- line390
+ line400
  col17
  file0
 
 
- line390
+ line400
  col37
  file0
 
@@ -7067,7 +7067,7 @@
  kindevent
  location
  
-  line390
+  line400
   col17
   file0
  
@@ -7075,12 +7075,12 @@
  

 
- line390
+ line400
  col17
  file0
 
 
- line390
+ line400
  col37
  file0
 
@@ -7100,12 +7100,12 @@
 start
  
   
-   line390
+   line400
col17

[clang] ab58238 - [analyzer] Find better description for tracked symbolic values

2021-04-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-04-28T18:37:38+03:00
New Revision: ab5823867c4aee7f3e02ddfaa217905c87471bf9

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

LOG: [analyzer] Find better description for tracked symbolic values

When searching for stores and creating corresponding notes, the
analyzer is more specific about the target region of the store
as opposed to the stored value.  While this description was tweaked
for constant and undefined values, it lacked in the most general
case of symbolic values.

This patch tries to find a memory region, where this value is stored,
to use it as a better alias for the value.

rdar://76645710

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
clang/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
clang/test/Analysis/osobject-retain-release.cpp
clang/test/Analysis/retain-release-path-notes.m
clang/test/Analysis/uninit-const.c
clang/test/Analysis/uninit-const.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index fd334b0bc9c36..c0526469909b3 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -153,6 +153,28 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) {
   return E;
 }
 
+static const MemRegion *
+getLocationRegionIfReference(const Expr *E, const ExplodedNode *N,
+ bool LookingForReference = true) {
+  if (const auto *DR = dyn_cast(E)) {
+if (const auto *VD = dyn_cast(DR->getDecl())) {
+  if (LookingForReference && !VD->getType()->isReferenceType())
+return nullptr;
+  return N->getState()
+  ->getLValue(VD, N->getLocationContext())
+  .getAsRegion();
+}
+  }
+
+  // FIXME: This does not handle other kinds of null references,
+  // for example, references from FieldRegions:
+  //   struct Wrapper { int  };
+  //   Wrapper w = { *(int *)0 };
+  //   w.ref = 1;
+
+  return nullptr;
+}
+
 /// Comparing internal representations of symbolic values (via
 /// SVal::operator==()) is a valid way to check if the value was updated,
 /// unless it's a LazyCompoundVal that may have a 
diff erent internal
@@ -1241,16 +1263,17 @@ static bool isInitializationOfVar(const ExplodedNode 
*N, const VarRegion *VR) {
 
 /// Show diagnostics for initializing or declaring a region \p R with a bad 
value.
 static void showBRDiagnostics(const char *action, llvm::raw_svector_ostream 
,
-  const MemRegion *R, SVal V, const DeclStmt *DS) {
-  if (R->canPrintPretty()) {
-R->printPretty(os);
+  const MemRegion *NewR, SVal V,
+  const MemRegion *OldR, const DeclStmt *DS) {
+  if (NewR->canPrintPretty()) {
+NewR->printPretty(os);
 os << " ";
   }
 
   if (V.getAs()) {
 bool b = false;
-if (R->isBoundable()) {
-  if (const auto *TR = dyn_cast(R)) {
+if (NewR->isBoundable()) {
+  if (const auto *TR = dyn_cast(NewR)) {
 if (TR->getValueType()->isObjCObjectPointerType()) {
   os << action << "nil";
   b = true;
@@ -1262,29 +1285,31 @@ static void showBRDiagnostics(const char *action, 
llvm::raw_svector_ostream ,
 
   } else if (auto CVal = V.getAs()) {
 os << action << CVal->getValue();
+  } else if (OldR && OldR->canPrintPretty()) {
+os << action << "the value of ";
+OldR->printPretty(os);
   } else if (DS) {
 if (V.isUndef()) {
-  if (isa(R)) {
+  if (isa(NewR)) {
 const auto *VD = cast(DS->getSingleDecl());
 if (VD->getInit()) {
-  os << (R->canPrintPretty() ? "initialized" : "Initializing")
-<< " to a garbage value";
+  os << (NewR->canPrintPretty() ? "initialized" : "Initializing")
+ << " to a garbage value";
 } else {
-  os << (R->canPrintPretty() ? "declared" : "Declaring")
-<< " without an initial value";
+  os << (NewR->canPrintPretty() ? "declared" : "Declaring")
+ << " without an initial value";
 }
   }
 } else {
-  os << (R->canPrintPretty() ? "initialized" : "Initialized")
-<< " here";
+  os << (NewR->canPrintPretty() ? "initialized" : "Initialized") << " 
here";
 }
   }
 }
 
 /// Display diagnostics for passing bad region as a parameter.
-static void showBRParamDiagnostics(llvm::raw_svector_ostream& os,
-const VarRegion *VR,
-SVal V) {
+static void showBRParamDiagnostics(llvm::raw_svector_ostream ,
+   

[clang] e273918 - [analyzer] Track leaking object through stores

2021-04-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-04-28T18:37:38+03:00
New Revision: e273918038a7aa300cb8e6afebd9714bf647eed0

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

LOG: [analyzer] Track leaking object through stores

Since we can report memory leaks on one variable, while the originally
allocated object was stored into another one, we should explain
how did it get there.

rdar://76645710

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

Added: 


Modified: 

clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist
clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist
clang/test/Analysis/osobject-retain-release.cpp
clang/test/Analysis/retain-release-path-notes.m

Removed: 




diff  --git 
a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
 
b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 48b5f8d9ba7c9..eaa1e35f62bef 100644
--- 
a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ 
b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -616,7 +616,7 @@ static Optional describeRegion(const MemRegion 
*MR) {
   return None;
 }
 
-using Bindings = llvm::SmallVector;
+using Bindings = llvm::SmallVector, 4>;
 
 class VarBindingsCollector : public StoreManager::BindingsHandler {
   SymbolRef Sym;
@@ -633,7 +633,7 @@ class VarBindingsCollector : public 
StoreManager::BindingsHandler {
   return true;
 
 if (isa(R))
-  Result.push_back(R);
+  Result.emplace_back(R, Val);
 
 return true;
   }
@@ -968,11 +968,28 @@ void RefLeakReport::findBindingToReport(CheckerContext 
,
   // `AllocFirstBinding` to be one of them.  In situations like this,
   // it would still be the easiest case to explain to our users.
   if (!AllVarBindings.empty() &&
-  llvm::count(AllVarBindings, AllocFirstBinding) == 0)
+  llvm::count_if(AllVarBindings,
+ [this](const std::pair Binding) {
+   return Binding.first == AllocFirstBinding;
+ }) == 0) {
 // Let's pick one of them at random (if there is something to pick from).
-AllocBindingToReport = AllVarBindings[0];
-  else
+AllocBindingToReport = AllVarBindings[0].first;
+
+// Because 'AllocBindingToReport' is not the the same as
+// 'AllocFirstBinding', we need to explain how the leaking object
+// got from one to another.
+//
+// NOTE: We use the actual SVal stored in AllocBindingToReport here because
+//   FindLastStoreBRVisitor compares SVal's and it can get trickier for
+//   something like derived regions if we want to construct SVal from
+//   Sym. Instead, we take the value that is definitely stored in that
+//   region, thus guaranteeing that FindLastStoreBRVisitor will work.
+addVisitor(std::make_unique(
+AllVarBindings[0].second.castAs(), AllocBindingToReport,
+false, bugreporter::TrackingKind::Thorough));
+  } else {
 AllocBindingToReport = AllocFirstBinding;
+  }
 }
 
 RefLeakReport::RefLeakReport(const RefCountBug , const LangOptions ,

diff  --git a/clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist 
b/clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
index 0665e976efe9d..62cd52b7aa822 100644
--- a/clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
+++ b/clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
@@ -21827,6 +21827,35 @@

   
 
+
+ kindevent
+ location
+ 
+  line566
+  col3
+  file0
+ 
+ ranges
+ 
+   
+
+ line566
+ col3
+ file0
+
+
+ line566
+ col11
+ file0
+
+   
+ 
+ depth0
+ extended_message
+ garply initialized here
+ message
+ garply initialized here
+
 
  kindcontrol
  edges

diff  --git 
a/clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist 
b/clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
index 185525c3a8473..3b0ce877b76e6 100644
--- 
a/clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
+++ 
b/clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
@@ -5155,6 +5155,35 @@
  message
  Method returns an instance of MyObj with a +1 retain 
count
 
+
+ kindevent
+ location
+ 
+  line215
+  col3
+  

[clang] 61ae2db - [analyzer] Adjust the reported variable name in retain count checker

2021-04-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-04-28T18:37:37+03:00
New Revision: 61ae2db2d7a97af5206afe609a303071711f9e6e

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

LOG: [analyzer] Adjust the reported variable name in retain count checker

When reporting leaks, we try to attach the leaking object to some
variable, so it's easier to understand.  Before the patch, we always
tried to use the first variable that stored the object in question.
This can get very confusing for the user, if that variable doesn't
contain that object at the moment of the actual leak.  In many cases,
the warning is dismissed as false positive and it is effectively a
false positive when we fail to properly explain the warning to the
user.

This patch addresses the bigest issue in cases like this.  Now we
check if the variable still contains the leaking symbolic object.
If not, we look for the last variable to actually hold it and use
that variable instead.

rdar://76645710

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

Added: 


Modified: 

clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp

clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist
clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist
clang/test/Analysis/osobject-retain-release.cpp
clang/test/Analysis/retain-release-path-notes.m
clang/test/Analysis/retain-release.m

Removed: 




diff  --git 
a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
 
b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index a004d78bfe397..48b5f8d9ba7c9 100644
--- 
a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ 
b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -13,6 +13,8 @@
 
 #include "RetainCountDiagnostics.h"
 #include "RetainCountChecker.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
 
 using namespace clang;
 using namespace ento;
@@ -337,15 +339,15 @@ class RefCountReportVisitor : public BugReporterVisitor {
 
 class RefLeakReportVisitor : public RefCountReportVisitor {
 public:
-  RefLeakReportVisitor(SymbolRef Sym, const MemRegion *FirstBinding)
-  : RefCountReportVisitor(Sym), FirstBinding(FirstBinding) {}
+  RefLeakReportVisitor(SymbolRef Sym, const MemRegion *LastBinding)
+  : RefCountReportVisitor(Sym), LastBinding(LastBinding) {}
 
   PathDiagnosticPieceRef getEndPath(BugReporterContext ,
 const ExplodedNode *N,
 PathSensitiveBugReport ) override;
 
 private:
-  const MemRegion *FirstBinding;
+  const MemRegion *LastBinding;
 };
 
 } // end namespace retaincountchecker
@@ -614,6 +616,41 @@ static Optional describeRegion(const 
MemRegion *MR) {
   return None;
 }
 
+using Bindings = llvm::SmallVector;
+
+class VarBindingsCollector : public StoreManager::BindingsHandler {
+  SymbolRef Sym;
+  Bindings 
+
+public:
+  VarBindingsCollector(SymbolRef Sym, Bindings )
+  : Sym(Sym), Result(ToFill) {}
+
+  bool HandleBinding(StoreManager , Store Store, const MemRegion *R,
+ SVal Val) override {
+SymbolRef SymV = Val.getAsLocSymbol();
+if (!SymV || SymV != Sym)
+  return true;
+
+if (isa(R))
+  Result.push_back(R);
+
+return true;
+  }
+};
+
+Bindings getAllVarBindingsForSymbol(ProgramStateManager ,
+const ExplodedNode *Node, SymbolRef Sym) {
+  Bindings Result;
+  VarBindingsCollector Collector{Sym, Result};
+  while (Result.empty() && Node) {
+Manager.iterBindings(Node->getState(), Collector);
+Node = Node->getFirstPred();
+  }
+
+  return Result;
+}
+
 namespace {
 // Find the first node in the current function context that referred to the
 // tracked symbol and the memory location that value was stored to. Note, the
@@ -740,7 +777,7 @@ RefLeakReportVisitor::getEndPath(BugReporterContext ,
 
   os << "Object leaked: ";
 
-  Optional RegionDescription = describeRegion(FirstBinding);
+  Optional RegionDescription = describeRegion(LastBinding);
   if (RegionDescription) {
 os << "object allocated and stored into '" << *RegionDescription << '\'';
   } else {
@@ -749,7 +786,7 @@ RefLeakReportVisitor::getEndPath(BugReporterContext ,
   }
 
   // Get the retain count.
-  const RefVal* RV = getRefBinding(EndN->getState(), Sym);
+  const RefVal *RV = getRefBinding(EndN->getState(), Sym);
   assert(RV);
 
   if 

[clang] 1dad8c5 - [analyzer][NFC] Remove duplicated work from retain count leak report

2021-04-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-04-28T18:37:37+03:00
New Revision: 1dad8c5036bc912078f7859d89e3ea571616fc4a

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

LOG: [analyzer][NFC] Remove duplicated work from retain count leak report

Allocation site is the key location for the leak checker.  It is a
uniqueing location for the report and a source of information for
the warning's message.

Before this patch, we calculated and used it twice in bug report and
in bug report visitor.  Such duplication is not only harmful
performance-wise (not much, but still), but also design-wise.  Because
changing something about the end piece of the report should've been
repeated for description as well.

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

Added: 


Modified: 

clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp

Removed: 




diff  --git 
a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
 
b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 1fc3ee03d2e10..a004d78bfe397 100644
--- 
a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ 
b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -337,11 +337,15 @@ class RefCountReportVisitor : public BugReporterVisitor {
 
 class RefLeakReportVisitor : public RefCountReportVisitor {
 public:
-  RefLeakReportVisitor(SymbolRef sym) : RefCountReportVisitor(sym) {}
+  RefLeakReportVisitor(SymbolRef Sym, const MemRegion *FirstBinding)
+  : RefCountReportVisitor(Sym), FirstBinding(FirstBinding) {}
 
   PathDiagnosticPieceRef getEndPath(BugReporterContext ,
 const ExplodedNode *N,
 PathSensitiveBugReport ) override;
+
+private:
+  const MemRegion *FirstBinding;
 };
 
 } // end namespace retaincountchecker
@@ -729,14 +733,6 @@ RefLeakReportVisitor::getEndPath(BugReporterContext ,
   // assigned to 
diff erent variables, etc.
   BR.markInteresting(Sym);
 
-  // We are reporting a leak.  Walk up the graph to get to the first node where
-  // the symbol appeared, and also get the first VarDecl that tracked object
-  // is stored to.
-  AllocationInfo AllocI = GetAllocationSite(BRC.getStateManager(), EndN, Sym);
-
-  const MemRegion* FirstBinding = AllocI.R;
-  BR.markInteresting(AllocI.InterestingMethodContext);
-
   PathDiagnosticLocation L = cast(BR).getEndOfPath();
 
   std::string sbuf;
@@ -902,15 +898,15 @@ void RefLeakReport::createDescription(CheckerContext 
) {
 }
 
 RefLeakReport::RefLeakReport(const RefCountBug , const LangOptions ,
- ExplodedNode *n, SymbolRef sym,
+ ExplodedNode *N, SymbolRef Sym,
  CheckerContext )
-: RefCountReport(D, LOpts, n, sym, /*isLeak=*/true) {
+: RefCountReport(D, LOpts, N, Sym, /*isLeak=*/true) {
 
-  deriveAllocLocation(Ctx, sym);
+  deriveAllocLocation(Ctx, Sym);
   if (!AllocBinding)
-deriveParamLocation(Ctx, sym);
+deriveParamLocation(Ctx, Sym);
 
   createDescription(Ctx);
 
-  addVisitor(std::make_unique(sym));
+  addVisitor(std::make_unique(Sym, AllocBinding));
 }



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


[clang] 5780dbe - [-Wcalled-once] Do not run analysis on Obj-C++

2021-04-22 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-04-22T15:20:52+03:00
New Revision: 5780dbeee6480fdceae66fb57dcc7bd1cfcda5c9

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

LOG: [-Wcalled-once] Do not run analysis on Obj-C++

Objective-C++ is not yet suppoerted.

rdar://76729552

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

Added: 


Modified: 
clang/lib/Sema/AnalysisBasedWarnings.cpp
clang/test/SemaObjCXX/warn-called-once.mm

Removed: 




diff  --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp 
b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index bcd6a00d7ba5a..aa2602c8d9256 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2403,7 +2403,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
   }
 
   // Check for violations of "called once" parameter properties.
-  if (S.getLangOpts().ObjC &&
+  if (S.getLangOpts().ObjC && !S.getLangOpts().CPlusPlus &&
   shouldAnalyzeCalledOnceParameters(Diags, D->getBeginLoc())) {
 if (AC.getCFG()) {
   CalledOnceCheckReporter Reporter(S, IPData->CalledOnceData);

diff  --git a/clang/test/SemaObjCXX/warn-called-once.mm 
b/clang/test/SemaObjCXX/warn-called-once.mm
index 312da27d9ae32..3763a9b219f24 100644
--- a/clang/test/SemaObjCXX/warn-called-once.mm
+++ b/clang/test/SemaObjCXX/warn-called-once.mm
@@ -1,7 +1,13 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -Wcompletion-handler %s
+// RUN: %clang_cc1 -verify -fsyntax-only -fblocks -Wcompletion-handler %s
 
 // expected-no-diagnostics
 
 class HasCtor {
   HasCtor(void *) {}
 };
+
+void double_call_one_block(void (^completionHandler)(void)) {
+  completionHandler();
+  completionHandler();
+  // no-warning - we don't support C++/Obj-C++ yet
+}



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


[clang] 663ac91 - [analyzer] Fix false positives in inner pointer checker (PR49628)

2021-04-08 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-04-08T20:30:12+03:00
New Revision: 663ac91ed1d6156e848e5f5f00cd7e7dd6cf867f

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

LOG: [analyzer] Fix false positives in inner pointer checker (PR49628)

This patch supports std::data and std::addressof functions.

rdar://73463300

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
clang/test/Analysis/inner-pointer.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
index 65e52e139ee4..bcae73378028 100644
--- a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
@@ -34,9 +34,9 @@ namespace {
 class InnerPointerChecker
 : public Checker {
 
-  CallDescription AppendFn, AssignFn, ClearFn, CStrFn, DataFn, EraseFn,
-  InsertFn, PopBackFn, PushBackFn, ReplaceFn, ReserveFn, ResizeFn,
-  ShrinkToFitFn, SwapFn;
+  CallDescription AppendFn, AssignFn, AddressofFn, ClearFn, CStrFn, DataFn,
+  DataMemberFn, EraseFn, InsertFn, PopBackFn, PushBackFn, ReplaceFn,
+  ReserveFn, ResizeFn, ShrinkToFitFn, SwapFn;
 
 public:
   class InnerPointerBRVisitor : public BugReporterVisitor {
@@ -73,9 +73,10 @@ class InnerPointerChecker
   InnerPointerChecker()
   : AppendFn({"std", "basic_string", "append"}),
 AssignFn({"std", "basic_string", "assign"}),
+AddressofFn({"std", "addressof"}),
 ClearFn({"std", "basic_string", "clear"}),
-CStrFn({"std", "basic_string", "c_str"}),
-DataFn({"std", "basic_string", "data"}),
+CStrFn({"std", "basic_string", "c_str"}), DataFn({"std", "data"}, 1),
+DataMemberFn({"std", "basic_string", "data"}),
 EraseFn({"std", "basic_string", "erase"}),
 InsertFn({"std", "basic_string", "insert"}),
 PopBackFn({"std", "basic_string", "pop_back"}),
@@ -90,6 +91,9 @@ class InnerPointerChecker
   /// pointers referring to the container object's inner buffer.
   bool isInvalidatingMemberFunction(const CallEvent ) const;
 
+  /// Check whether the called function returns a raw inner pointer.
+  bool isInnerPointerAccessFunction(const CallEvent ) const;
+
   /// Mark pointer symbols associated with the given memory region released
   /// in the program state.
   void markPtrSymbolsReleased(const CallEvent , ProgramStateRef State,
@@ -130,6 +134,12 @@ bool InnerPointerChecker::isInvalidatingMemberFunction(
   Call.isCalled(SwapFn));
 }
 
+bool InnerPointerChecker::isInnerPointerAccessFunction(
+const CallEvent ) const {
+  return (Call.isCalled(CStrFn) || Call.isCalled(DataFn) ||
+  Call.isCalled(DataMemberFn));
+}
+
 void InnerPointerChecker::markPtrSymbolsReleased(const CallEvent ,
  ProgramStateRef State,
  const MemRegion *MR,
@@ -172,6 +182,11 @@ void InnerPointerChecker::checkFunctionArguments(const 
CallEvent ,
   if (!ArgRegion)
 continue;
 
+  // std::addressof function accepts a non-const reference as an argument,
+  // but doesn't modify it.
+  if (Call.isCalled(AddressofFn))
+continue;
+
   markPtrSymbolsReleased(Call, State, ArgRegion, C);
 }
   }
@@ -195,36 +210,49 @@ void InnerPointerChecker::checkPostCall(const CallEvent 
,
 CheckerContext ) const {
   ProgramStateRef State = C.getState();
 
+  // TODO: Do we need these to be typed?
+  const TypedValueRegion *ObjRegion = nullptr;
+
   if (const auto *ICall = dyn_cast()) {
-// TODO: Do we need these to be typed?
-const auto *ObjRegion = dyn_cast_or_null(
+ObjRegion = dyn_cast_or_null(
 ICall->getCXXThisVal().getAsRegion());
-if (!ObjRegion)
-  return;
 
-if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
-  SVal RawPtr = Call.getReturnValue();
-  if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) {
-// Start tracking this raw pointer by adding it to the set of symbols
-// associated with this container object in the program state map.
+// Check [string.require] / second point.
+if (isInvalidatingMemberFunction(Call)) {
+  markPtrSymbolsReleased(Call, State, ObjRegion, C);
+  return;
+}
+  }
 
-PtrSet::Factory  = State->getStateManager().get_context();
-const PtrSet *SetPtr = State->get(ObjRegion);
-PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
-assert(C.wasInlined || !Set.contains(Sym));
-Set = F.add(Set, Sym);
+  if (isInnerPointerAccessFunction(Call)) {
 
-   

[clang] 4b958dd - [analyzer] Fix crash on spaceship operator (PR47511)

2021-04-08 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-04-08T20:28:05+03:00
New Revision: 4b958dd6bccab386be432cac99332b867ab9ee22

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

LOG: [analyzer] Fix crash on spaceship operator (PR47511)

rdar://68954187

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

Added: 
clang/test/Analysis/PR47511.cpp

Modified: 
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp 
b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index a47a28e1e866..9942b7e1423c 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -423,6 +423,14 @@ SVal SValBuilder::evalBinOp(ProgramStateRef state, 
BinaryOperator::Opcode op,
 return UnknownVal();
   }
 
+  if (op == BinaryOperatorKind::BO_Cmp) {
+// We can't reason about C++20 spaceship operator yet.
+//
+// FIXME: Support C++20 spaceship operator.
+//The main problem here is that the result is not integer.
+return UnknownVal();
+  }
+
   if (Optional LV = lhs.getAs()) {
 if (Optional RV = rhs.getAs())
   return evalBinOpLL(state, op, *LV, *RV, type);

diff  --git a/clang/test/Analysis/PR47511.cpp b/clang/test/Analysis/PR47511.cpp
new file mode 100644
index ..d42799f4fbde
--- /dev/null
+++ b/clang/test/Analysis/PR47511.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++20 -w -analyzer-checker=core -verify %s
+
+// expected-no-diagnostics
+
+namespace std {
+struct strong_ordering {
+  int n;
+  constexpr operator int() const { return n; }
+  static const strong_ordering equal, greater, less;
+};
+constexpr strong_ordering strong_ordering::equal = {0};
+constexpr strong_ordering strong_ordering::greater = {1};
+constexpr strong_ordering strong_ordering::less = {-1};
+} // namespace std
+
+void test() {
+  // no crash
+  (void)(0 <=> 0);
+}



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


[clang] 9f0d8ba - [analyzer] Fix dead store checker false positive

2021-04-08 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-04-08T16:12:42+03:00
New Revision: 9f0d8bac144c8eb1ca4aff823b2e2d5a0f990072

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

LOG: [analyzer] Fix dead store checker false positive

It is common to zero-initialize not only scalar variables,
but also structs.  This is also defensive programming and
we shouldn't complain about that.

rdar://34122265

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
clang/test/Analysis/dead-stores.c

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 8c86e83608b1e..8070d869f6785 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -11,17 +11,18 @@
 //
 
//===--===//
 
-#include "clang/Lex/Lexer.h"
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/ParentMap.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/SaveAndRestore.h"
 
@@ -408,15 +409,17 @@ class DeadStoreObs : public LiveVariables::Observer {
   // Special case: check for initializations with constants.
   //
   //  e.g. : int x = 0;
+  // struct A = {0, 1};
+  // struct B = {{0}, {1, 2}};
   //
   // If x is EVER assigned a new value later, don't issue
   // a warning.  This is because such initialization can be
   // due to defensive programming.
-  if (E->isEvaluatable(Ctx))
+  if (isConstant(E))
 return;
 
   if (const DeclRefExpr *DRE =
-  dyn_cast(E->IgnoreParenCasts()))
+  dyn_cast(E->IgnoreParenCasts()))
 if (const VarDecl *VD = dyn_cast(DRE->getDecl())) {
   // Special case: check for initialization from constant
   //  variables.
@@ -444,6 +447,29 @@ class DeadStoreObs : public LiveVariables::Observer {
 }
   }
   }
+
+private:
+  /// Return true if the given init list can be interpreted as constant
+  bool isConstant(const InitListExpr *Candidate) const {
+// We consider init list to be constant if each member of the list can be
+// interpreted as constant.
+return llvm::all_of(Candidate->inits(),
+[this](const Expr *Init) { return isConstant(Init); });
+  }
+
+  /// Return true if the given expression can be interpreted as constant
+  bool isConstant(const Expr *E) const {
+// It looks like E itself is a constant
+if (E->isEvaluatable(Ctx))
+  return true;
+
+// We should also allow defensive initialization of structs, i.e. { 0 }
+if (const auto *ILE = dyn_cast(E->IgnoreParenCasts())) {
+  return isConstant(ILE);
+}
+
+return false;
+  }
 };
 
 } // end anonymous namespace

diff  --git a/clang/test/Analysis/dead-stores.c 
b/clang/test/Analysis/dead-stores.c
index a17e1692496da..145b81bd03327 100644
--- a/clang/test/Analysis/dead-stores.c
+++ b/clang/test/Analysis/dead-stores.c
@@ -635,3 +635,44 @@ void testVolatile() {
   volatile int v;
   v = 0; // no warning
 }
+
+struct Foo {
+  int x;
+  int y;
+};
+
+struct Foo rdar34122265_getFoo(void);
+
+int rdar34122265_test(int input) {
+  // This is allowed for defensive programming.
+  struct Foo foo = {0, 0};
+  if (input > 0) {
+foo = rdar34122265_getFoo();
+  } else {
+return 0;
+  }
+  return foo.x + foo.y;
+}
+
+void rdar34122265_test_cast() {
+  // This is allowed for defensive programming.
+  struct Foo foo = {0, 0};
+  (void)foo;
+}
+
+struct Bar {
+  struct Foo x, y;
+};
+
+struct Bar rdar34122265_getBar(void);
+
+int rdar34122265_test_nested(int input) {
+  // This is allowed for defensive programming.
+  struct Bar bar = {{0, 0}, {0, 0}};
+  if (input > 0) {
+bar = rdar34122265_getBar();
+  } else {
+return 0;
+  }
+  return bar.x.x + bar.y.y;
+}



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

[clang] 77f1e09 - [-Wcompletion-handler] Don't recognize init methods as conventional

2021-04-07 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-04-07T13:50:01+03:00
New Revision: 77f1e096e8a0a0f37a4c5f8a0bacc7c60f44f0a1

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

LOG: [-Wcompletion-handler] Don't recognize init methods as conventional

rdar://75704162

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

Added: 


Modified: 
clang/lib/Analysis/CalledOnceCheck.cpp
clang/test/SemaObjC/warn-called-once.m

Removed: 




diff  --git a/clang/lib/Analysis/CalledOnceCheck.cpp 
b/clang/lib/Analysis/CalledOnceCheck.cpp
index 9fa8ac30404c3..db094129a9608 100644
--- a/clang/lib/Analysis/CalledOnceCheck.cpp
+++ b/clang/lib/Analysis/CalledOnceCheck.cpp
@@ -1011,11 +1011,16 @@ class CalledOnceChecker : public 
ConstStmtVisitor {
 return llvm::None;
   }
 
+  /// Return true if the specified selector represents init method.
+  static bool isInitMethod(Selector MethodSelector) {
+return MethodSelector.getMethodFamily() == OMF_init;
+  }
+
   /// Return true if the specified selector piece matches conventions.
   static bool isConventionalSelectorPiece(Selector MethodSelector,
   unsigned PieceIndex,
   QualType PieceType) {
-if (!isConventional(PieceType)) {
+if (!isConventional(PieceType) || isInitMethod(MethodSelector)) {
   return false;
 }
 

diff  --git a/clang/test/SemaObjC/warn-called-once.m 
b/clang/test/SemaObjC/warn-called-once.m
index ff2778d4bd0a4..27030dd94a825 100644
--- a/clang/test/SemaObjC/warn-called-once.m
+++ b/clang/test/SemaObjC/warn-called-once.m
@@ -13,6 +13,7 @@
 @protocol NSObject
 @end
 @interface NSObject 
+- (instancetype)init;
 - (id)copy;
 - (id)class;
 - autorelease;
@@ -1235,4 +1236,13 @@ - (void)test_cleanup_2:(int)cond
   handler(); // expected-warning{{completion handler is called twice}}
 }
 
+- (void)initWithAdditions:(int)cond
+   withCompletion:(void (^)(void))handler {
+  self = [self init];
+  if (self) {
+escape(handler);
+  }
+  // no-warning
+}
+
 @end



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


[clang] 4821c15 - [analyzer] Fix body farm for Obj-C++ properties

2021-04-07 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-04-07T13:44:43+03:00
New Revision: 4821c15691bab9efaef871c957a8ba73697cdda9

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

LOG: [analyzer] Fix body farm for Obj-C++ properties

When property is declared in a superclass (or in a protocol),
it still can be of CXXRecord type and Sema could've already
generated a body for us.  This patch joins two branches and
two ways of acquiring IVar in order to reuse the existing code.
And prevent us from generating l-value to r-value casts for
C++ types.

rdar://67416721

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

Added: 


Modified: 
clang/lib/Analysis/BodyFarm.cpp
clang/test/Analysis/properties.mm

Removed: 




diff  --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp
index 603da67156254..b2110f6b5450c 100644
--- a/clang/lib/Analysis/BodyFarm.cpp
+++ b/clang/lib/Analysis/BodyFarm.cpp
@@ -742,8 +742,9 @@ static const ObjCIvarDecl *findBackingIvar(const 
ObjCPropertyDecl *Prop) {
 
 static Stmt *createObjCPropertyGetter(ASTContext ,
   const ObjCMethodDecl *MD) {
-// First, find the backing ivar.
+  // First, find the backing ivar.
   const ObjCIvarDecl *IVar = nullptr;
+  const ObjCPropertyDecl *Prop = nullptr;
 
   // Property accessor stubs sometimes do not correspond to any property decl
   // in the current interface (but in a superclass). They still have a
@@ -751,54 +752,57 @@ static Stmt *createObjCPropertyGetter(ASTContext ,
   if (MD->isSynthesizedAccessorStub()) {
 const ObjCInterfaceDecl *IntD = MD->getClassInterface();
 const ObjCImplementationDecl *ImpD = IntD->getImplementation();
-for (const auto *PI: ImpD->property_impls()) {
-  if (const ObjCPropertyDecl *P = PI->getPropertyDecl()) {
-if (P->getGetterName() == MD->getSelector())
-  IVar = P->getPropertyIvarDecl();
+for (const auto *PI : ImpD->property_impls()) {
+  if (const ObjCPropertyDecl *Candidate = PI->getPropertyDecl()) {
+if (Candidate->getGetterName() == MD->getSelector()) {
+  Prop = Candidate;
+  IVar = Prop->getPropertyIvarDecl();
+}
   }
 }
   }
 
   if (!IVar) {
-const ObjCPropertyDecl *Prop = MD->findPropertyDecl();
+Prop = MD->findPropertyDecl();
 IVar = findBackingIvar(Prop);
-if (!IVar)
-  return nullptr;
+  }
 
-// Ignore weak variables, which have special behavior.
-if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak)
-  return nullptr;
+  if (!IVar || !Prop)
+return nullptr;
+
+  // Ignore weak variables, which have special behavior.
+  if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak)
+return nullptr;
 
-// Look to see if Sema has synthesized a body for us. This happens in
-// Objective-C++ because the return value may be a C++ class type with a
-// non-trivial copy constructor. We can only do this if we can find the
-// @synthesize for this property, though (or if we know it's been auto-
-// synthesized).
-const ObjCImplementationDecl *ImplDecl =
+  // Look to see if Sema has synthesized a body for us. This happens in
+  // Objective-C++ because the return value may be a C++ class type with a
+  // non-trivial copy constructor. We can only do this if we can find the
+  // @synthesize for this property, though (or if we know it's been auto-
+  // synthesized).
+  const ObjCImplementationDecl *ImplDecl =
   IVar->getContainingInterface()->getImplementation();
-if (ImplDecl) {
-  for (const auto *I : ImplDecl->property_impls()) {
-if (I->getPropertyDecl() != Prop)
-  continue;
-
-if (I->getGetterCXXConstructor()) {
-  ASTMaker M(Ctx);
-  return M.makeReturn(I->getGetterCXXConstructor());
-}
+  if (ImplDecl) {
+for (const auto *I : ImplDecl->property_impls()) {
+  if (I->getPropertyDecl() != Prop)
+continue;
+
+  if (I->getGetterCXXConstructor()) {
+ASTMaker M(Ctx);
+return M.makeReturn(I->getGetterCXXConstructor());
   }
 }
-
-// Sanity check that the property is the same type as the ivar, or a
-// reference to it, and that it is either an object pointer or trivially
-// copyable.
-if (!Ctx.hasSameUnqualifiedType(IVar->getType(),
-Prop->getType().getNonReferenceType()))
-  return nullptr;
-if (!IVar->getType()->isObjCLifetimeType() &&
-!IVar->getType().isTriviallyCopyableType(Ctx))
-  return nullptr;
   }
 
+  // Sanity check that the property is the same type as the ivar, or a
+  // reference to it, and that it is either an object pointer or trivially
+  // copyable.
+  if 

[clang] af7e1f0 - [analyzer] Fix crash when reasoning about C11 atomics (PR49422)

2021-03-30 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-03-30T16:04:19+03:00
New Revision: af7e1f07ac03074647897498358aaec165c1aaea

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

LOG: [analyzer] Fix crash when reasoning about C11 atomics (PR49422)

rdar://75020762

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

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
clang/test/Analysis/atomics.c

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index 9f464e82304f4..f59b254094db8 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -139,6 +139,12 @@ class BasicValueFactory {
 
   /// Returns the type of the APSInt used to store values of the given 
QualType.
   APSIntType getAPSIntType(QualType T) const {
+// For the purposes of the analysis and constraints, we treat atomics
+// as their underlying types.
+if (const AtomicType *AT = T->getAs()) {
+  T = AT->getValueType();
+}
+
 assert(T->isIntegralOrEnumerationType() || Loc::isLocType(T));
 return APSIntType(Ctx.getIntWidth(T),
   !T->isSignedIntegerOrEnumerationType());

diff  --git a/clang/test/Analysis/atomics.c b/clang/test/Analysis/atomics.c
index b3d2d352a2283..ef1a216c7d577 100644
--- a/clang/test/Analysis/atomics.c
+++ b/clang/test/Analysis/atomics.c
@@ -93,3 +93,11 @@ void test_atomic_compare_exchange_weak(struct 
RefCountedStruct *s) {
   clang_analyzer_eval(s->refCount == 3); // expected-warning {{UNKNOWN}}
   clang_analyzer_eval(expected == 2); // expected-warning {{UNKNOWN}}
 }
+
+// PR49422
+void test_atomic_compare(int input) {
+  _Atomic(int) x = input;
+  if (x > 0) {
+// no crash
+  }
+}



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


[clang] 9037730 - [analyzer] Support allocClassWithName in OSObjectCStyleCast checker

2021-03-30 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-03-30T15:58:06+03:00
New Revision: 90377308de6cac8239bc1a1dcd32b57b9ec91444

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

LOG: [analyzer] Support allocClassWithName in OSObjectCStyleCast checker

`allocClassWithName` allocates an object with the given type.
The type is actually provided as a string argument (type's name).
This creates a possibility for not particularly useful warnings
from the analyzer.

In order to combat with those, this patch checks for casts of the
`allocClassWithName` results to types mentioned directly as its
argument.  All other uses of this method should be reasoned about
as before.

rdar://72165694

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp
clang/test/Analysis/os_object_base.h
clang/test/Analysis/osobjectcstylecastchecker_test.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp 
b/clang/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp
index 270b66dab020..0a8379d9ab99 100644
--- a/clang/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp
@@ -32,7 +32,21 @@ class OSObjectCStyleCastChecker : public 
Checker {
   void checkASTCodeBody(const Decl *D, AnalysisManager ,
 BugReporter ) const;
 };
+} // namespace
+
+namespace clang {
+namespace ast_matchers {
+AST_MATCHER_P(StringLiteral, mentionsBoundType, std::string, BindingID) {
+  return Builder->removeBindings([this, ](const BoundNodesMap ) {
+const auto  = Nodes.getNode(this->BindingID);
+if (const auto *ND = BN.get()) {
+  return ND->getName() != Node.getString();
+}
+return true;
+  });
 }
+} // end namespace ast_matchers
+} // end namespace clang
 
 static void emitDiagnostics(const BoundNodes ,
 BugReporter ,
@@ -63,22 +77,41 @@ static decltype(auto) hasTypePointingTo(DeclarationMatcher 
DeclM) {
   return hasType(pointerType(pointee(hasDeclaration(DeclM;
 }
 
-void OSObjectCStyleCastChecker::checkASTCodeBody(const Decl *D, 
AnalysisManager ,
+void OSObjectCStyleCastChecker::checkASTCodeBody(const Decl *D,
+ AnalysisManager ,
  BugReporter ) const {
 
   AnalysisDeclContext *ADC = AM.getAnalysisDeclContext(D);
 
   auto DynamicCastM = callExpr(callee(functionDecl(hasName("safeMetaCast";
-
-  auto OSObjTypeM = 
hasTypePointingTo(cxxRecordDecl(isDerivedFrom("OSMetaClassBase")));
+  // 'allocClassWithName' allocates an object with the given type.
+  // The type is actually provided as a string argument (type's name).
+  // This makes the following pattern possible:
+  //
+  // Foo *object = (Foo *)allocClassWithName("Foo");
+  //
+  // While OSRequiredCast can be used here, it is still not a useful warning.
+  auto AllocClassWithNameM = callExpr(
+  callee(functionDecl(hasName("allocClassWithName"))),
+  // Here we want to make sure that the string argument matches the
+  // type in the cast expression.
+  hasArgument(0, stringLiteral(mentionsBoundType(WarnRecordDecl;
+
+  auto OSObjTypeM =
+  hasTypePointingTo(cxxRecordDecl(isDerivedFrom("OSMetaClassBase")));
   auto OSObjSubclassM = hasTypePointingTo(
-cxxRecordDecl(isDerivedFrom("OSObject")).bind(WarnRecordDecl));
-
-  auto CastM = cStyleCastExpr(
-  allOf(hasSourceExpression(allOf(OSObjTypeM, unless(DynamicCastM))),
-  OSObjSubclassM)).bind(WarnAtNode);
-
-  auto Matches = match(stmt(forEachDescendant(CastM)), *D->getBody(), 
AM.getASTContext());
+  cxxRecordDecl(isDerivedFrom("OSObject")).bind(WarnRecordDecl));
+
+  auto CastM =
+  cStyleCastExpr(
+  allOf(OSObjSubclassM,
+hasSourceExpression(
+allOf(OSObjTypeM,
+  unless(anyOf(DynamicCastM, AllocClassWithNameM))
+  .bind(WarnAtNode);
+
+  auto Matches =
+  match(stmt(forEachDescendant(CastM)), *D->getBody(), AM.getASTContext());
   for (BoundNodes Match : Matches)
 emitDiagnostics(Match, BR, ADC, this);
 }

diff  --git a/clang/test/Analysis/os_object_base.h 
b/clang/test/Analysis/os_object_base.h
index 4698185f2b3c..c3d5d6271d48 100644
--- a/clang/test/Analysis/os_object_base.h
+++ b/clang/test/Analysis/os_object_base.h
@@ -66,6 +66,7 @@ struct OSObject : public OSMetaClassBase {
 
 struct OSMetaClass : public OSMetaClassBase {
   virtual OSObject * alloc() const;
+  static OSObject * allocClassWithName(const char * name);
   virtual ~OSMetaClass(){}
 };
 

diff  --git a/clang/test/Analysis/osobjectcstylecastchecker_test.cpp 

[clang] 02b51e5 - [analyzer][solver] Redesign constraint ranges data structure

2021-03-22 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-03-22T13:52:35+03:00
New Revision: 02b51e5316cd501ede547d0223e0f5416ebd9845

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

LOG: [analyzer][solver] Redesign constraint ranges data structure

ImmutableSet doesn't seem like the perfect fit for the RangeSet
data structure.  It is good for saving memory in a persistent
setting, but not for the case when the population of the container
is tiny.  This commit replaces RangeSet implementation and
redesigns the most common operations to be more efficient.

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

Added: 


Modified: 

clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
clang/unittests/StaticAnalyzer/RangeSetTest.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
index bc5d5f57cd68..4a118074463d 100644
--- 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
+++ 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -16,6 +16,8 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/Allocator.h"
 
 namespace clang {
 
@@ -24,21 +26,19 @@ namespace ento {
 /// A Range represents the closed range [from, to].  The caller must
 /// guarantee that from <= to.  Note that Range is immutable, so as not
 /// to subvert RangeSet's immutability.
-class Range : public std::pair {
+class Range {
 public:
-  Range(const llvm::APSInt , const llvm::APSInt )
-  : std::pair(, ) {
-assert(from <= to);
+  Range(const llvm::APSInt , const llvm::APSInt ) : Impl(, ) {
+assert(From <= To);
   }
 
-  Range(const llvm::APSInt )
-  : std::pair(, ) 
{}
+  Range(const llvm::APSInt ) : Range(Point, Point) {}
 
-  bool Includes(const llvm::APSInt ) const {
-return *first <= v && v <= *second;
+  bool Includes(const llvm::APSInt ) const {
+return From() <= Point && Point <= To();
   }
-  const llvm::APSInt () const { return *first; }
-  const llvm::APSInt () const { return *second; }
+  const llvm::APSInt () const { return *Impl.first; }
+  const llvm::APSInt () const { return *Impl.second; }
   const llvm::APSInt *getConcreteValue() const {
 return () == () ? () : nullptr;
   }
@@ -47,93 +47,264 @@ class Range : public std::pair {
 ID.AddPointer(());
 ID.AddPointer(());
   }
-};
+  void dump(raw_ostream ) const;
 
-class RangeTrait : public llvm::ImutContainerInfo {
-public:
-  // When comparing if one Range is less than another, we should compare
-  // the actual APSInt values instead of their pointers.  This keeps the order
-  // consistent (instead of comparing by pointer values) and can potentially
-  // be used to speed up some of the operations in RangeSet.
-  static inline bool isLess(key_type_ref lhs, key_type_ref rhs) {
-return *lhs.first < *rhs.first ||
-   (!(*rhs.first < *lhs.first) && *lhs.second < *rhs.second);
-  }
+  // In order to keep non-overlapping ranges sorted, we can compare only From
+  // points.
+  bool operator<(const Range ) const { return From() < RHS.From(); }
+
+  bool operator==(const Range ) const { return Impl == RHS.Impl; }
+  bool operator!=(const Range ) const { return !operator==(RHS); }
+
+private:
+  std::pair Impl;
 };
 
-/// RangeSet contains a set of ranges. If the set is empty, then
-///  there the value of a symbol is overly constrained and there are no
-///  possible values for that symbol.
+/// @class RangeSet is a persistent set of non-overlapping ranges.
+///
+/// New RangeSet objects can be ONLY produced by RangeSet::Factory object, 
which
+/// also supports the most common operations performed on range sets.
+///
+/// Empty set corresponds to an overly constrained symbol meaning that there
+/// are no possible values for that symbol.
 class RangeSet {
-  typedef llvm::ImmutableSet PrimRangeSet;
-  PrimRangeSet ranges; // no need to make const, since it is an
-   // ImmutableSet - this allows default operator=
-   // to work.
 public:
-  typedef PrimRangeSet::Factory Factory;
-  typedef PrimRangeSet::iterator iterator;
-
-  RangeSet(PrimRangeSet RS) : ranges(RS) {}
-
-  /// Create a new set with all ranges of this set and RS.
-  /// Possible intersections are not checked here.
-  RangeSet addRange(Factory , 

[clang] 3085bda - [analyzer][solver] Fix infeasible constraints (PR49642)

2021-03-22 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-03-22T11:02:02+03:00
New Revision: 3085bda2b348f6a8b4e0bd1d230af4e9c900c9c4

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

LOG: [analyzer][solver] Fix infeasible constraints (PR49642)

Additionally, this patch puts an assertion checking for feasible
constraints in every place where constraints are assigned to states.

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

Added: 
clang/test/Analysis/PR49642.c

Modified: 
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 95e61f9c8c61..6ae80b3ae773 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -448,12 +448,12 @@ class EquivalenceClass : public llvm::FoldingSetNode {
   EquivalenceClass Other);
 
   /// Return a set of class members for the given state.
-  LLVM_NODISCARD inline SymbolSet getClassMembers(ProgramStateRef State);
+  LLVM_NODISCARD inline SymbolSet getClassMembers(ProgramStateRef State) const;
   /// Return true if the current class is trivial in the given state.
-  LLVM_NODISCARD inline bool isTrivial(ProgramStateRef State);
+  LLVM_NODISCARD inline bool isTrivial(ProgramStateRef State) const;
   /// Return true if the current class is trivial and its only member is dead.
   LLVM_NODISCARD inline bool isTriviallyDead(ProgramStateRef State,
- SymbolReaper );
+ SymbolReaper ) const;
 
   LLVM_NODISCARD static inline ProgramStateRef
   markDisequal(BasicValueFactory , RangeSet::Factory ,
@@ -521,7 +521,7 @@ class EquivalenceClass : public llvm::FoldingSetNode {
ProgramStateRef State, SymbolSet Members,
EquivalenceClass Other,
SymbolSet OtherMembers);
-  static inline void
+  static inline bool
   addToDisequalityInfo(DisequalityMapTy , ConstraintRangeTy ,
BasicValueFactory , RangeSet::Factory ,
ProgramStateRef State, EquivalenceClass First,
@@ -535,6 +535,15 @@ class EquivalenceClass : public llvm::FoldingSetNode {
 // Constraint functions
 
//===--===//
 
+LLVM_NODISCARD LLVM_ATTRIBUTE_UNUSED bool
+areFeasible(ConstraintRangeTy Constraints) {
+  return llvm::none_of(
+  Constraints,
+  [](const std::pair ) {
+return ClassConstraint.second.isEmpty();
+  });
+}
+
 LLVM_NODISCARD inline const RangeSet *getConstraint(ProgramStateRef State,
 EquivalenceClass Class) {
   return State->get(Class);
@@ -1397,15 +1406,6 @@ class RangeConstraintManager : public 
RangedConstraintManager {
 return EquivalenceClass::merge(getBasicVals(), F, State, LHS, RHS);
   }
 
-  LLVM_NODISCARD LLVM_ATTRIBUTE_UNUSED static bool
-  areFeasible(ConstraintRangeTy Constraints) {
-return llvm::none_of(
-Constraints,
-[](const std::pair ) {
-  return ClassConstraint.second.isEmpty();
-});
-  }
-
   LLVM_NODISCARD ProgramStateRef setConstraint(ProgramStateRef State,
EquivalenceClass Class,
RangeSet Constraint) {
@@ -1428,7 +1428,7 @@ class RangeConstraintManager : public 
RangedConstraintManager {
 getRange(State, DisequalClass).Delete(getBasicVals(), F, *Point);
 
 // If we end up with at least one of the disequal classes to be
-// constrainted with an empty range-set, the state is infeasible.
+// constrained with an empty range-set, the state is infeasible.
 if (UpdatedConstraint.isEmpty())
   return nullptr;
 
@@ -1574,6 +1574,9 @@ EquivalenceClass::mergeImpl(BasicValueFactory 
,
 // Assign new constraints for this class.
 Constraints = CRF.add(Constraints, *this, *NewClassConstraint);
 
+assert(areFeasible(Constraints) && "Constraint manager shouldn't produce "
+   "a state with infeasible constraints");
+
 State = State->set(Constraints);
   }
 
@@ -1644,7 +1647,7 @@ EquivalenceClass::getMembersFactory(ProgramStateRef 
State) {
   return State->get_context();
 }
 
-SymbolSet EquivalenceClass::getClassMembers(ProgramStateRef State) {
+SymbolSet EquivalenceClass::getClassMembers(ProgramStateRef State) const {
   if (const SymbolSet *Members = State->get(*this))
 return 

[clang] 8b8b9af - [-Wcalled-once-parameter][NFC] Fix GCC compilation error

2021-03-18 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-03-18T14:49:24+03:00
New Revision: 8b8b9af8c9132acb446fc42569de8a0f57c6b556

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

LOG: [-Wcalled-once-parameter][NFC] Fix GCC compilation error

Added: 


Modified: 
clang/lib/Analysis/CalledOnceCheck.cpp

Removed: 




diff  --git a/clang/lib/Analysis/CalledOnceCheck.cpp 
b/clang/lib/Analysis/CalledOnceCheck.cpp
index ab56d3e3c988..00bb51a1c0d3 100644
--- a/clang/lib/Analysis/CalledOnceCheck.cpp
+++ b/clang/lib/Analysis/CalledOnceCheck.cpp
@@ -63,14 +63,14 @@ struct KnownCalledOnceParameter {
   unsigned ParamIndex;
 };
 constexpr KnownCalledOnceParameter KNOWN_CALLED_ONCE_PARAMETERS[] = {
-{"dispatch_async", 1},
-{"dispatch_async_and_wait", 1},
-{"dispatch_after", 2},
-{"dispatch_sync", 1},
-{"dispatch_once", 1},
-{"dispatch_barrier_async", 1},
-{"dispatch_barrier_async_and_wait", 1},
-{"dispatch_barrier_sync", 1}};
+{llvm::StringLiteral{"dispatch_async"}, 1},
+{llvm::StringLiteral{"dispatch_async_and_wait"}, 1},
+{llvm::StringLiteral{"dispatch_after"}, 2},
+{llvm::StringLiteral{"dispatch_sync"}, 1},
+{llvm::StringLiteral{"dispatch_once"}, 1},
+{llvm::StringLiteral{"dispatch_barrier_async"}, 1},
+{llvm::StringLiteral{"dispatch_barrier_async_and_wait"}, 1},
+{llvm::StringLiteral{"dispatch_barrier_sync"}, 1}};
 
 class ParameterStatus {
 public:



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


[clang] 4a7afc9 - [-Wcalled-once-parameter] Fix false positives for cleanup attr

2021-03-18 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-03-18T12:32:16+03:00
New Revision: 4a7afc9a8843f4793296a260f7153fd2ef4ec497

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

LOG: [-Wcalled-once-parameter] Fix false positives for cleanup attr

Cleanup attribute allows users to attach a destructor-like functions
to variable declarations to be called whenever they leave the scope.
The logic of such functions is not supported by the Clang's CFG and
is too hard to be reasoned about.  In order to avoid false positives
in this situation, we assume that we didn't see ALL of the executtion
paths of the function and, thus, can warn only about multiple call
violation.

rdar://74441906

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

Added: 


Modified: 
clang/lib/Analysis/CalledOnceCheck.cpp
clang/test/SemaObjC/warn-called-once.m

Removed: 




diff  --git a/clang/lib/Analysis/CalledOnceCheck.cpp 
b/clang/lib/Analysis/CalledOnceCheck.cpp
index 29021b0a9016..ab56d3e3c988 100644
--- a/clang/lib/Analysis/CalledOnceCheck.cpp
+++ b/clang/lib/Analysis/CalledOnceCheck.cpp
@@ -812,8 +812,12 @@ class CalledOnceChecker : public 
ConstStmtVisitor {
   }
 }
 
-// Early exit if we don't have parameters for extra analysis.
-if (NotCalledOnEveryPath.none() && NotUsedOnEveryPath.none())
+// Early exit if we don't have parameters for extra analysis...
+if (NotCalledOnEveryPath.none() && NotUsedOnEveryPath.none() &&
+// ... or if we've seen variables with cleanup functions.
+// We can't reason that we've seen every path in this case,
+// and thus abandon reporting any warnings that imply that.
+!FunctionHasCleanupVars)
   return;
 
 // We are looking for a pair of blocks A, B so that the following is true:
@@ -1601,6 +1605,10 @@ class CalledOnceChecker : public 
ConstStmtVisitor {
 if (Var->getInit()) {
   checkEscapee(Var->getInit());
 }
+
+if (Var->hasAttr()) {
+  FunctionHasCleanupVars = true;
+}
   }
 }
   }
@@ -1669,6 +1677,13 @@ class CalledOnceChecker : public 
ConstStmtVisitor {
   // around.
   bool SuppressOnConventionalErrorPaths = false;
 
+  // The user can annotate variable declarations with cleanup functions, which
+  // essentially imposes a custom destructor logic on that variable.
+  // It is possible to use it, however, to call tracked parameters on all exits
+  // from the function.  For this reason, we track the fact that the function
+  // actually has these.
+  bool FunctionHasCleanupVars = false;
+
   State CurrentState;
   ParamSizedVector TrackedParams;
   CFGSizedVector States;

diff  --git a/clang/test/SemaObjC/warn-called-once.m 
b/clang/test/SemaObjC/warn-called-once.m
index 825d491f53bb..ff2778d4bd0a 100644
--- a/clang/test/SemaObjC/warn-called-once.m
+++ b/clang/test/SemaObjC/warn-called-once.m
@@ -1193,4 +1193,46 @@ - (void)test_escape_after_branch:(int)cond
   escape(handler);
 }
 
+// rdar://74441906
+typedef void (^DeferredBlock)(void);
+static inline void DefferedCallback(DeferredBlock *inBlock) { (*inBlock)(); }
+#define _DEFERCONCAT(a, b) a##b
+#define _DEFERNAME(a) _DEFERCONCAT(__DeferredVar_, a)
+#define DEFER __extension__ __attribute__((cleanup(DefferedCallback), unused)) 
\
+  DeferredBlock _DEFERNAME(__COUNTER__) = ^
+
+- (void)test_cleanup_1:(int)cond
+withCompletion:(void (^)(void))handler {
+  int error = 0;
+  DEFER {
+if (error)
+  handler();
+  };
+
+  if (cond) {
+error = 1;
+  } else {
+// no-warning
+handler();
+  }
+}
+
+- (void)test_cleanup_2:(int)cond
+withCompletion:(void (^)(void))handler {
+  int error = 0;
+  DEFER {
+if (error)
+  handler();
+  };
+
+  if (cond) {
+error = 1;
+  } else {
+handler(); // expected-note{{previous call is here}}
+  }
+
+  // We still can warn about double call even in this case.
+  handler(); // expected-warning{{completion handler is called twice}}
+}
+
 @end



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


[clang] f1a7d5a - [-Wcalled-once-parameter] Harden analysis in terms of block use

2021-03-18 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-03-18T12:12:18+03:00
New Revision: f1a7d5a7b0ec810057ff6e88371ab86d1fce812c

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

LOG: [-Wcalled-once-parameter] Harden analysis in terms of block use

This patch introduces a very simple inter-procedural analysis
between blocks and enclosing functions.

We always analyze blocks first (analysis is done as part of semantic
analysis that goes side-by-side with the parsing process), and at the
moment of reporting we don't know how that block will be actually
used.

This patch introduces new logic delaying reports of the "never called"
warnings on blocks.  If we are not sure that the block will be called
exactly once, we shouldn't warn our users about that.  Double calls,
however, don't require such delays.  While analyzing the enclosing
function, we can actually decide what we should do with those
warnings.

Additionally, as a side effect, we can be more confident about blocks
in such context and can treat them not as escapes, but as direct
calls.

rdar://74090107

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

Added: 


Modified: 
clang/include/clang/Analysis/Analyses/CalledOnceCheck.h
clang/include/clang/Sema/AnalysisBasedWarnings.h
clang/lib/Analysis/CalledOnceCheck.cpp
clang/lib/Sema/AnalysisBasedWarnings.cpp
clang/test/SemaObjC/warn-called-once.m

Removed: 




diff  --git a/clang/include/clang/Analysis/Analyses/CalledOnceCheck.h 
b/clang/include/clang/Analysis/Analyses/CalledOnceCheck.h
index fc574c680a44..a0c767bf92d2 100644
--- a/clang/include/clang/Analysis/Analyses/CalledOnceCheck.h
+++ b/clang/include/clang/Analysis/Analyses/CalledOnceCheck.h
@@ -17,6 +17,7 @@
 namespace clang {
 
 class AnalysisDeclContext;
+class BlockDecl;
 class CFG;
 class Decl;
 class DeclContext;
@@ -79,6 +80,7 @@ class CalledOnceCheckHandler {
   /// the path containing the call and not containing the call.  This helps us
   /// to pinpoint a bad path for the user.
   /// \param Parameter -- parameter that should be called once.
+  /// \param Function -- function declaration where the problem occured.
   /// \param Where -- the least common ancestor statement.
   /// \param Reason -- a reason describing the path without a call.
   /// \param IsCalledDirectly -- true, if parameter actually gets called on
@@ -86,9 +88,22 @@ class CalledOnceCheckHandler {
   /// collection, passed as a parameter, etc.).
   /// \param IsCompletionHandler -- true, if parameter is a completion handler.
   virtual void handleNeverCalled(const ParmVarDecl *Parameter,
- const Stmt *Where, NeverCalledReason Reason,
+ const Decl *Function, const Stmt *Where,
+ NeverCalledReason Reason,
  bool IsCalledDirectly,
  bool IsCompletionHandler) {}
+
+  /// Called when the block is guaranteed to be called exactly once.
+  /// It means that we can be stricter with what we report on that block.
+  /// \param Block -- block declaration that is known to be called exactly 
once.
+  virtual void
+  handleBlockThatIsGuaranteedToBeCalledOnce(const BlockDecl *Block) {}
+
+  /// Called when the block has no guarantees about how many times it can get
+  /// called.
+  /// It means that we should be more lenient with reporting warnings in it.
+  /// \param Block -- block declaration in question.
+  virtual void handleBlockWithNoGuarantees(const BlockDecl *Block) {}
 };
 
 /// Check given CFG for 'called once' parameter violations.

diff  --git a/clang/include/clang/Sema/AnalysisBasedWarnings.h 
b/clang/include/clang/Sema/AnalysisBasedWarnings.h
index e13fe955eaf4..49b69c585ff7 100644
--- a/clang/include/clang/Sema/AnalysisBasedWarnings.h
+++ b/clang/include/clang/Sema/AnalysisBasedWarnings.h
@@ -14,6 +14,7 @@
 #define LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H
 
 #include "llvm/ADT/DenseMap.h"
+#include 
 
 namespace clang {
 
@@ -47,6 +48,9 @@ class AnalysisBasedWarnings {
   Sema 
   Policy DefaultPolicy;
 
+  class InterProceduralData;
+  std::unique_ptr IPData;
+
   enum VisitFlag { NotVisited = 0, Visited = 1, Pending = 2 };
   llvm::DenseMap VisitedFD;
 
@@ -88,6 +92,7 @@ class AnalysisBasedWarnings {
 
 public:
   AnalysisBasedWarnings(Sema );
+  ~AnalysisBasedWarnings();
 
   void IssueWarnings(Policy P, FunctionScopeInfo *fscope,
  const Decl *D, QualType BlockType);
@@ -97,6 +102,7 @@ class AnalysisBasedWarnings {
   void PrintStats() const;
 };
 
-}} // end namespace clang::sema
+} // namespace sema
+} // namespace clang
 
 #endif

diff  --git a/clang/lib/Analysis/CalledOnceCheck.cpp 
b/clang/lib/Analysis/CalledOnceCheck.cpp
index 

[clang] c86dacd - [-Wcalled-once-parameter] Let escapes overwrite MaybeCalled states

2021-03-17 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-03-17T11:12:55+03:00
New Revision: c86dacd1a4489572721dec3135506d31da96c679

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

LOG: [-Wcalled-once-parameter] Let escapes overwrite MaybeCalled states

This commit makes escapes symmetrical, meaning that having escape
before and after the branching, where parameter is not called on
one of the paths, will have the same effect.

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

Added: 


Modified: 
clang/lib/Analysis/CalledOnceCheck.cpp
clang/test/SemaObjC/warn-called-once.m

Removed: 




diff  --git a/clang/lib/Analysis/CalledOnceCheck.cpp 
b/clang/lib/Analysis/CalledOnceCheck.cpp
index 2438c50d7e4e..d24e0b500564 100644
--- a/clang/lib/Analysis/CalledOnceCheck.cpp
+++ b/clang/lib/Analysis/CalledOnceCheck.cpp
@@ -867,16 +867,14 @@ class CalledOnceChecker : public 
ConstStmtVisitor {
 // Let's check if any of the call arguments is a point of interest.
 for (const auto  : llvm::enumerate(Arguments)) {
   if (auto Index = getIndexOfExpression(Argument.value())) {
-ParameterStatus  = 
CurrentState.getStatusFor(*Index);
-
 if (shouldBeCalledOnce(CallOrMessage, Argument.index())) {
   // If the corresponding parameter is marked as 'called_once' we 
should
   // consider it as a call.
   processCallFor(*Index, CallOrMessage);
-} else if (CurrentParamStatus.getKind() == ParameterStatus::NotCalled) 
{
+} else {
   // Otherwise, we mark this parameter as escaped, which can be
   // interpreted both as called or not called depending on the context.
-  CurrentParamStatus = ParameterStatus::Escaped;
+  processEscapeFor(*Index);
 }
 // Otherwise, let's keep the state as it is.
   }
@@ -910,6 +908,16 @@ class CalledOnceChecker : public 
ConstStmtVisitor {
 }
   }
 
+  /// Process escape of the parameter with the given index
+  void processEscapeFor(unsigned Index) {
+ParameterStatus  = CurrentState.getStatusFor(Index);
+
+// Escape overrides whatever error we think happened.
+if (CurrentParamStatus.isErrorStatus()) {
+  CurrentParamStatus = ParameterStatus::Escaped;
+}
+  }
+
   void findAndReportNotCalledBranches(const CFGBlock *Parent, unsigned Index,
   bool IsEscape = false) {
 for (const CFGBlock *Succ : Parent->succs()) {
@@ -1365,11 +1373,7 @@ class CalledOnceChecker : public 
ConstStmtVisitor {
   /// Check given parameter that was discovered to escape.
   void checkEscapee(const ParmVarDecl ) {
 if (auto Index = getIndex(Parameter)) {
-  ParameterStatus  = CurrentState.getStatusFor(*Index);
-
-  if (CurrentParamStatus.getKind() == ParameterStatus::NotCalled) {
-CurrentParamStatus = ParameterStatus::Escaped;
-  }
+  processEscapeFor(*Index);
 }
   }
 

diff  --git a/clang/test/SemaObjC/warn-called-once.m 
b/clang/test/SemaObjC/warn-called-once.m
index 3d846deca921..7d0679035238 100644
--- a/clang/test/SemaObjC/warn-called-once.m
+++ b/clang/test/SemaObjC/warn-called-once.m
@@ -1130,4 +1130,32 @@ - (void)test_nil_suppression_3:(int)cond1
   }
 }
 
+- (void)test_escape_before_branch:(int)cond
+   withCompletion:(void (^)(void))handler {
+  if (cond) {
+filler();
+  }
+
+  void (^copiedHandler)(void) = ^{
+handler();
+  };
+
+  if (cond) {
+// no-warning
+handler();
+  } else {
+copiedHandler();
+  }
+}
+
+- (void)test_escape_after_branch:(int)cond
+  withCompletion:(void (^)(void))handler {
+  if (cond) {
+// no-warning
+handler();
+  }
+
+  escape(handler);
+}
+
 @end



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


[clang] 6dc1523 - [analyzer][solver] Prevent infeasible states (PR49490)

2021-03-12 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-03-12T15:56:48+03:00
New Revision: 6dc152350824d0abcf4e1836c2846f8f9256779c

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

LOG: [analyzer][solver] Prevent infeasible states (PR49490)

This patch fixes the situation when our knowledge of disequalities
can help us figuring out that some assumption is infeasible, but
the solver still produces a state with inconsistent constraints.

Additionally, this patch adds a couple of assertions to catch this
type of problems easier.

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

Added: 
clang/test/Analysis/PR49490.cpp

Modified: 
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index a481bde1651b..95e61f9c8c61 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -19,6 +19,8 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace clang;
@@ -1395,12 +1397,23 @@ class RangeConstraintManager : public 
RangedConstraintManager {
 return EquivalenceClass::merge(getBasicVals(), F, State, LHS, RHS);
   }
 
-  LLVM_NODISCARD inline ProgramStateRef setConstraint(ProgramStateRef State,
-  EquivalenceClass Class,
-  RangeSet Constraint) {
+  LLVM_NODISCARD LLVM_ATTRIBUTE_UNUSED static bool
+  areFeasible(ConstraintRangeTy Constraints) {
+return llvm::none_of(
+Constraints,
+[](const std::pair ) {
+  return ClassConstraint.second.isEmpty();
+});
+  }
+
+  LLVM_NODISCARD ProgramStateRef setConstraint(ProgramStateRef State,
+   EquivalenceClass Class,
+   RangeSet Constraint) {
 ConstraintRangeTy Constraints = State->get();
 ConstraintRangeTy::Factory  = State->get_context();
 
+assert(!Constraint.isEmpty() && "New constraint should not be empty");
+
 // Add new constraint.
 Constraints = CF.add(Constraints, Class, Constraint);
 
@@ -1413,9 +1426,18 @@ class RangeConstraintManager : public 
RangedConstraintManager {
   for (EquivalenceClass DisequalClass : Class.getDisequalClasses(State)) {
 RangeSet UpdatedConstraint =
 getRange(State, DisequalClass).Delete(getBasicVals(), F, *Point);
+
+// If we end up with at least one of the disequal classes to be
+// constrainted with an empty range-set, the state is infeasible.
+if (UpdatedConstraint.isEmpty())
+  return nullptr;
+
 Constraints = CF.add(Constraints, DisequalClass, UpdatedConstraint);
   }
 
+assert(areFeasible(Constraints) && "Constraint manager shouldn't produce "
+   "a state with infeasible constraints");
+
 return State->set(Constraints);
   }
 

diff  --git a/clang/test/Analysis/PR49490.cpp b/clang/test/Analysis/PR49490.cpp
new file mode 100644
index ..3254355013a6
--- /dev/null
+++ b/clang/test/Analysis/PR49490.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_analyze_cc1 -w -analyzer-checker=core -verify %s
+
+// expected-no-diagnostics
+
+struct toggle {
+  bool value;
+};
+
+toggle global_toggle;
+toggle get_global_toggle() { return global_toggle; }
+
+int oob_access();
+
+bool compare(toggle one, bool other) {
+  if (one.value != other)
+return true;
+
+  if (one.value)
+oob_access();
+  return true;
+}
+
+bool coin();
+
+void bar() {
+  bool left = coin();
+  bool right = coin();
+  for (;;)
+compare(get_global_toggle(), left) && compare(get_global_toggle(), right);
+}



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


[clang] c763504 - [analyzer] Fix StdLibraryFunctionsChecker performance issue

2021-03-09 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-03-10T10:44:04+03:00
New Revision: c7635040ce0a546020cbcd9f2030817725bd7494

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

LOG: [analyzer] Fix StdLibraryFunctionsChecker performance issue

`initFunctionSummaries` lazily initializes a data structure with
function summaries for standard library functions.  It is called for
every pre-, post-, and eval-call events, i.e. 3 times for each call on
the path.  If the initialization doesn't find any standard library
functions in the translation unit, it will get re-tried (with the same
effect) many times even for small translation units.

For projects not using standard libraries, the speed-up can reach 50%
after this patch.

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index d1c366a94fac..38a9d4ba65b6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -508,6 +508,7 @@ class StdLibraryFunctionsChecker
   mutable FunctionSummaryMapType FunctionSummaryMap;
 
   mutable std::unique_ptr BT_InvalidArg;
+  mutable bool SummariesInitialized = false;
 
   static SVal getArgSVal(const CallEvent , ArgNo ArgN) {
 return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
@@ -823,7 +824,7 @@ StdLibraryFunctionsChecker::findFunctionSummary(const 
CallEvent ,
 
 void StdLibraryFunctionsChecker::initFunctionSummaries(
 CheckerContext ) const {
-  if (!FunctionSummaryMap.empty())
+  if (SummariesInitialized)
 return;
 
   SValBuilder  = C.getSValBuilder();
@@ -2485,6 +2486,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
 Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
 Summary(EvalCallAsPure));
   }
+
+  SummariesInitialized = true;
 }
 
 void ento::registerStdCLibraryFunctionsChecker(CheckerManager ) {



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


[clang] 59112ea - [-Wcompletion-handler] Extend list of detected conventions

2021-03-09 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-03-10T10:43:19+03:00
New Revision: 59112eacb97910601504d4ce5115b2d535bcbeb6

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

LOG: [-Wcompletion-handler] Extend list of detected conventions

Update convention detection to accomodate changes from:
https://github.com/DougGregor/swift-evolution/blob/concurrency-objc/proposals/-concurrency-objc.md#asynchronous-completion-handler-methods

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

Added: 


Modified: 
clang/lib/Analysis/CalledOnceCheck.cpp
clang/test/SemaObjC/warn-called-once.m

Removed: 




diff  --git a/clang/lib/Analysis/CalledOnceCheck.cpp 
b/clang/lib/Analysis/CalledOnceCheck.cpp
index 92d68d85fbc2..2438c50d7e4e 100644
--- a/clang/lib/Analysis/CalledOnceCheck.cpp
+++ b/clang/lib/Analysis/CalledOnceCheck.cpp
@@ -48,9 +48,12 @@ static constexpr unsigned EXPECTED_NUMBER_OF_BASIC_BLOCKS = 
8;
 template 
 using CFGSizedVector = llvm::SmallVector;
 constexpr llvm::StringLiteral CONVENTIONAL_NAMES[] = {
-"completionHandler", "completion", "withCompletionHandler"};
+"completionHandler", "completion",  "withCompletionHandler",
+"withCompletion","completionBlock", "withCompletionBlock",
+"replyTo",   "reply",   "withReplyTo"};
 constexpr llvm::StringLiteral CONVENTIONAL_SUFFIXES[] = {
-"WithCompletionHandler", "WithCompletion"};
+"WithCompletionHandler", "WithCompletion", "WithCompletionBlock",
+"WithReplyTo", "WithReply"};
 constexpr llvm::StringLiteral CONVENTIONAL_CONDITIONS[] = {
 "error", "cancel", "shouldCall", "done", "OK", "success"};
 
@@ -994,13 +997,15 @@ class CalledOnceChecker : public 
ConstStmtVisitor {
   return hasConventionalSuffix(MethodSelector.getNameForSlot(0));
 }
 
-return isConventional(MethodSelector.getNameForSlot(PieceIndex));
+llvm::StringRef PieceName = MethodSelector.getNameForSlot(PieceIndex);
+return isConventional(PieceName) || hasConventionalSuffix(PieceName);
   }
 
   bool shouldBeCalledOnce(const ParmVarDecl *Parameter) const {
 return isExplicitlyMarked(Parameter) ||
(CheckConventionalParameters &&
-isConventional(Parameter->getName()) &&
+(isConventional(Parameter->getName()) ||
+ hasConventionalSuffix(Parameter->getName())) &&
 isConventional(Parameter->getType()));
   }
 

diff  --git a/clang/test/SemaObjC/warn-called-once.m 
b/clang/test/SemaObjC/warn-called-once.m
index 1014e1730163..3d846deca921 100644
--- a/clang/test/SemaObjC/warn-called-once.m
+++ b/clang/test/SemaObjC/warn-called-once.m
@@ -1036,6 +1036,20 @@ - (void)testWithCompletion:(void (^)(void))callback {
   }
 }
 
+- (void)test:(int)cond fooWithReplyTo:(void (^)(void))handler {
+  if (cond) {
+// expected-warning@-1{{completion handler is never called when taking 
false branch}}
+handler();
+  }
+}
+
+- (void)test:(int)cond with:(void (^)(void))fooWithCompletionBlock {
+  if (cond) {
+// expected-warning@-1{{completion handler is never called when taking 
false branch}}
+fooWithCompletionBlock();
+  }
+}
+
 - (void)completion_handler_wrong_type:(int (^)(void))completionHandler {
   // We don't want to consider completion handlers with non-void return types.
   if ([self condition]) {



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


[clang] 6f21ada - [analyzer][NFC] Fix test failures for builds w/o assertions

2021-02-15 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-02-15T16:38:15+03:00
New Revision: 6f21adac6dd7082f7231ae342d40ed04f4885e79

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

LOG: [analyzer][NFC] Fix test failures for builds w/o assertions

Added: 


Modified: 
clang/test/Analysis/reinterpret-cast-pointer-to-member.cpp

Removed: 




diff  --git a/clang/test/Analysis/reinterpret-cast-pointer-to-member.cpp 
b/clang/test/Analysis/reinterpret-cast-pointer-to-member.cpp
index 1631be70da3e..c457d2230ddd 100644
--- a/clang/test/Analysis/reinterpret-cast-pointer-to-member.cpp
+++ b/clang/test/Analysis/reinterpret-cast-pointer-to-member.cpp
@@ -1,5 +1,5 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify 
%s
-// XFAIL: *
+// XFAIL: asserts
 
 void clang_analyzer_eval(bool);
 



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


[clang] f8d3f47 - [analyzer] Updated comments to reflect D85817

2021-02-15 Thread Valeriy Savchenko via cfe-commits

Author: Deep Majumder
Date: 2021-02-15T11:47:21+03:00
New Revision: f8d3f47e1fd09392aa30df83849b25acd8c59a25

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

LOG: [analyzer] Updated comments to reflect D85817

Changed DeclaratorDecl in comment to NamedDecl

Reviewed By: vsavchenko

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

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h

Removed: 




diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index a2354ba62cdb..b1c33713febd 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -511,11 +511,11 @@ class LazyCompoundVal : public NonLoc {
 /// This value is qualified as NonLoc because neither loading nor storing
 /// operations are applied to it. Instead, the analyzer uses the L-value coming
 /// from pointer-to-member applied to an object.
-/// This SVal is represented by a DeclaratorDecl which can be a member function
-/// pointer or a member data pointer and a list of CXXBaseSpecifiers. This list
-/// is required to accumulate the pointer-to-member cast history to figure out
-/// the correct subobject field. In particular, implicit casts grow this list
-/// and explicit casts like static_cast shrink this list.
+/// This SVal is represented by a NamedDecl which can be a member function
+/// pointer or a member data pointer and an optional list of CXXBaseSpecifiers.
+/// This list is required to accumulate the pointer-to-member cast history to
+/// figure out the correct subobject field. In particular, implicit casts grow
+/// this list and explicit casts like static_cast shrink this list.
 class PointerToMember : public NonLoc {
   friend class ento::SValBuilder;
 



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


[clang] 21daada - [analyzer] Fix static_cast on pointer-to-member handling

2021-02-15 Thread Valeriy Savchenko via cfe-commits

Author: Deep Majumder
Date: 2021-02-15T11:44:37+03:00
New Revision: 21daada95079a37c7ca259fabfc735b6d1b362ad

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

LOG: [analyzer] Fix static_cast on pointer-to-member handling

This commit fixes bug #48739. The bug was caused by the way static_casts
on pointer-to-member caused the CXXBaseSpecifier list of a
MemberToPointer to grow instead of shrink.
The list is now grown by implicit casts and corresponding entries are
removed by static_casts. No-op static_casts cause no effect.

Reviewed By: vsavchenko

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

Added: 
clang/test/Analysis/reinterpret-cast-pointer-to-member.cpp

Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
clang/test/Analysis/pointer-to-member.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index 142b1ab11750..9f464e82304f 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -258,9 +258,9 @@ class BasicValueFactory {
 return CXXBaseListFactory.add(CBS, L);
   }
 
-  const PointerToMemberData *accumCXXBase(
-  llvm::iterator_range PathRange,
-  const nonloc::PointerToMember );
+  const PointerToMemberData *
+  accumCXXBase(llvm::iterator_range PathRange,
+   const nonloc::PointerToMember , const clang::CastKind 
);
 
   const llvm::APSInt* evalAPSInt(BinaryOperator::Opcode Op,
  const llvm::APSInt& V1,

diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index bb295ab591d4..a2354ba62cdb 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -514,7 +514,8 @@ class LazyCompoundVal : public NonLoc {
 /// This SVal is represented by a DeclaratorDecl which can be a member function
 /// pointer or a member data pointer and a list of CXXBaseSpecifiers. This list
 /// is required to accumulate the pointer-to-member cast history to figure out
-/// the correct subobject field.
+/// the correct subobject field. In particular, implicit casts grow this list
+/// and explicit casts like static_cast shrink this list.
 class PointerToMember : public NonLoc {
   friend class ento::SValBuilder;
 

diff  --git a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp 
b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
index d1f5ac02278f..40cdaef1bfa7 100644
--- a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -21,6 +21,7 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableList.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include 
 #include 
 #include 
@@ -176,28 +177,73 @@ const PointerToMemberData 
*BasicValueFactory::getPointerToMemberData(
   return D;
 }
 
+LLVM_ATTRIBUTE_UNUSED bool hasNoRepeatedElements(
+llvm::ImmutableList BaseSpecList) {
+  llvm::SmallPtrSet BaseSpecSeen;
+  for (const CXXBaseSpecifier *BaseSpec : BaseSpecList) {
+QualType BaseType = BaseSpec->getType();
+// Check whether inserted
+if (!BaseSpecSeen.insert(BaseType).second)
+  return false;
+  }
+  return true;
+}
+
 const PointerToMemberData *BasicValueFactory::accumCXXBase(
 llvm::iterator_range PathRange,
-const nonloc::PointerToMember ) {
+const nonloc::PointerToMember , const CastKind ) {
+  assert((kind == CK_DerivedToBaseMemberPointer ||
+  kind == CK_BaseToDerivedMemberPointer ||
+  kind == CK_ReinterpretMemberPointer) &&
+ "accumCXXBase called with wrong CastKind");
   nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
   const NamedDecl *ND = nullptr;
-  llvm::ImmutableList PathList;
+  llvm::ImmutableList BaseSpecList;
 
   if (PTMDT.isNull() || PTMDT.is()) {
 if (PTMDT.is())
   ND = PTMDT.get();
 
-PathList = CXXBaseListFactory.getEmptyList();
-  } else { // const PointerToMemberData *
+BaseSpecList = CXXBaseListFactory.getEmptyList();
+  } else {
 const PointerToMemberData *PTMD = PTMDT.get();
 ND = PTMD->getDeclaratorDecl();
 
-PathList = PTMD->getCXXBaseList();
+BaseSpecList = PTMD->getCXXBaseList();
   }
 
-  for (const auto  : llvm::reverse(PathRange))
-PathList = prependCXXBase(I, PathList);
- 

[clang] 94a1a5d - [analyzer][tests] Fix issue comparison script

2021-02-13 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-02-13T13:58:47+03:00
New Revision: 94a1a5d25f5546019fc5feeb24d924b09b9d27e4

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

LOG: [analyzer][tests] Fix issue comparison script

When newer build has duplicate issues the script tried to
remove it from the list more than once.  The new approach
changes the way we filter out matching issues.

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

Added: 


Modified: 
clang/utils/analyzer/CmpRuns.py

Removed: 




diff  --git a/clang/utils/analyzer/CmpRuns.py b/clang/utils/analyzer/CmpRuns.py
index 9d5e00767067..7afe865d77f2 100644
--- a/clang/utils/analyzer/CmpRuns.py
+++ b/clang/utils/analyzer/CmpRuns.py
@@ -36,7 +36,7 @@
 from copy import copy
 from enum import Enum
 from typing import (Any, DefaultDict, Dict, List, NamedTuple, Optional,
-Sequence, TextIO, TypeVar, Tuple, Union)
+Sequence, Set, TextIO, TypeVar, Tuple, Union)
 
 
 Number = Union[int, float]
@@ -374,8 +374,9 @@ def compare_results(results_old: AnalysisRun, results_new: 
AnalysisRun,
 
 # Quadratic algorithms in this part are fine because 'old' and 'new'
 # are most commonly of size 1.
-for a in copy(old):
-for b in copy(new):
+common: Set[AnalysisDiagnostic] = set()
+for a in old:
+for b in new:
 if a.get_issue_identifier() == b.get_issue_identifier():
 a_path_len = a.get_path_length()
 b_path_len = b.get_path_length()
@@ -394,16 +395,22 @@ def compare_results(results_old: AnalysisRun, 
results_new: AnalysisRun,
 path_
diff erence_data.append(
 a_path_len - b_path_len)
 
-res.add_common(a)
-old.remove(a)
-new.remove(b)
+res.add_common(b)
+common.add(a)
+
+old = filter_issues(old, common)
+new = filter_issues(new, common)
+common = set()
 
-for a in copy(old):
-for b in copy(new):
+for a in old:
+for b in new:
 if a.is_similar_to(b):
 res.add_changed(a, b)
-old.remove(a)
-new.remove(b)
+common.add(a)
+common.add(b)
+
+old = filter_issues(old, common)
+new = filter_issues(new, common)
 
 # Whatever is left in 'old' doesn't have a corresponding diagnostic
 # in 'new', so we need to mark it as 'removed'.
@@ -443,6 +450,12 @@ def compare_results(results_old: AnalysisRun, results_new: 
AnalysisRun,
 return res
 
 
+def filter_issues(origin: List[AnalysisDiagnostic],
+  to_remove: Set[AnalysisDiagnostic]) \
+  -> List[AnalysisDiagnostic]:
+return [diag for diag in origin if diag not in to_remove]
+
+
 def compute_percentile(values: Sequence[T], percentile: float) -> T:
 """
 Return computed percentile.



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


[clang] 81a9707 - [Attr] Apply GNU-style attributes to expression statements

2021-02-11 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-02-11T16:44:41+03:00
New Revision: 81a9707723845a5b880245da24633c519493205c

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

LOG: [Attr] Apply GNU-style attributes to expression statements

Before this commit, expression statements could not be annotated
with statement attributes.  Whenever parser found attribute, it
unconditionally assumed that it was followed by a declaration.
This not only doesn't allow expression attributes to have attributes,
but also produces spurious error diagnostics.

In order to maintain all previously compiled code, we still assume
that GNU attributes are followed by declarations unless ALL of those
are statement attributes.  And even in this case we are not forcing
the parser to think that it should parse a statement, but rather
let it proceed as if no attributes were found.

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

Added: 
clang/test/Parser/stmt-attributes.c
clang/test/Parser/stmt-attributes.cpp
clang/test/Parser/stmt-attributes.m

Modified: 
clang/include/clang/Basic/Features.def
clang/lib/Parse/ParseStmt.cpp

Removed: 




diff  --git a/clang/include/clang/Basic/Features.def 
b/clang/include/clang/Basic/Features.def
index 5424da67b62da..32830a3a532cc 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -253,6 +253,7 @@ EXTENSION(cxx_variable_templates, LangOpts.CPlusPlus)
 EXTENSION(overloadable_unmarked, true)
 EXTENSION(pragma_clang_attribute_namespaces, true)
 EXTENSION(pragma_clang_attribute_external_declaration, true)
+EXTENSION(statement_attributes_with_gnu_syntax, true)
 EXTENSION(gnu_asm, LangOpts.GNUAsm)
 EXTENSION(gnu_asm_goto_with_outputs, LangOpts.GNUAsm)
 EXTENSION(matrix_types, LangOpts.MatrixTypes)

diff  --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 71344ff101552..f59271c458488 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -20,6 +20,8 @@
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/TypoCorrection.h"
+#include "llvm/ADT/STLExtras.h"
+
 using namespace clang;
 
 
//===--===//
@@ -215,7 +217,11 @@ StmtResult 
Parser::ParseStatementOrDeclarationAfterAttributes(
 if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt ||
  (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) !=
  ParsedStmtContext()) &&
-(GNUAttributeLoc.isValid() || isDeclarationStatement())) {
+((GNUAttributeLoc.isValid() &&
+  !(!Attrs.empty() &&
+llvm::all_of(
+Attrs, [](ParsedAttr ) { return Attr.isStmtAttr(); }))) ||
+ isDeclarationStatement())) {
   SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
   DeclGroupPtrTy Decl;
   if (GNUAttributeLoc.isValid()) {

diff  --git a/clang/test/Parser/stmt-attributes.c 
b/clang/test/Parser/stmt-attributes.c
new file mode 100644
index 0..d142ce1b5b954
--- /dev/null
+++ b/clang/test/Parser/stmt-attributes.c
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#if !__has_extension(statement_attributes_with_gnu_syntax)
+#error "We should have statement attributes with GNU syntax support"
+#endif
+
+void foo(int i) {
+
+  __attribute__((unknown_attribute)); // expected-warning {{unknown attribute 
'unknown_attribute' ignored}}
+  __attribute__(()) {}
+  __attribute__(()) if (0) {}
+  __attribute__(()) for (;;);
+  __attribute__(()) do {
+__attribute__(()) continue;
+  }
+  while (0)
+;
+  __attribute__(()) while (0);
+
+  __attribute__(()) switch (i) {
+__attribute__(()) case 0 :
+__attribute__(()) default :
+__attribute__(()) break;
+  }
+
+  __attribute__(()) goto here;
+  __attribute__(()) here :
+
+  __attribute__(()) return;
+
+  __attribute__((noreturn)) {} // expected-error {{'noreturn' 
attribute cannot be applied to a statement}}
+  __attribute__((noreturn)) if (0) {}  // expected-error {{'noreturn' 
attribute cannot be applied to a statement}}
+  __attribute__((noreturn)) for (;;);  // expected-error {{'noreturn' 
attribute cannot be applied to a statement}}
+  __attribute__((noreturn)) do {   // expected-error {{'noreturn' 
attribute cannot be applied to a statement}}
+__attribute__((unavailable)) continue; // expected-error {{'unavailable' 
attribute cannot be applied to a statement}}
+  }
+  while (0)
+;
+  __attribute__((unknown_attribute)) while (0); // expected-warning {{unknown 
attribute 'unknown_attribute' ignored}}
+
+  __attribute__((unused)) switch (i) { // expected-error {{'unused' 
attribute cannot be applied to a statement}}
+  

[clang] 2f994d4 - [-Wcompletion-handler][NFC] Remove unexpected warnings on Windows

2021-02-09 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-02-09T13:50:11+03:00
New Revision: 2f994d4ee920983cf7624ce2208756e0c7d19007

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

LOG: [-Wcompletion-handler][NFC] Remove unexpected warnings on Windows

Added: 


Modified: 
clang/test/SemaObjC/warn-called-once.m

Removed: 




diff  --git a/clang/test/SemaObjC/warn-called-once.m 
b/clang/test/SemaObjC/warn-called-once.m
index 0c11d0e0a15b..1014e1730163 100644
--- a/clang/test/SemaObjC/warn-called-once.m
+++ b/clang/test/SemaObjC/warn-called-once.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -fblocks -fobjc-exceptions 
-Wcompletion-handler %s
+// RUN: %clang_cc1 -verify -fsyntax-only -fblocks -fobjc-exceptions 
-Wcompletion-handler -Wno-pointer-to-int-cast %s
 
 #define NULL (void *)0
 #define nil (id)0



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


[clang] d1522d3 - [-Wcompletion-handler] Support checks with builtins

2021-02-09 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2021-02-09T11:32:24+03:00
New Revision: d1522d349f4d4b960ff7a37303103e95aa535af3

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

LOG: [-Wcompletion-handler] Support checks with builtins

It is very common to check callbacks and completion handlers for null.
This patch supports such checks using built-in functions:
  * __builtin_expect
  * __builtin_expect_with_probablity
  * __builtin_unpredictable

rdar://73455388

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

Added: 


Modified: 
clang/lib/Analysis/CalledOnceCheck.cpp
clang/test/SemaObjC/warn-called-once.m

Removed: 




diff  --git a/clang/lib/Analysis/CalledOnceCheck.cpp 
b/clang/lib/Analysis/CalledOnceCheck.cpp
index 883629a300dc..92d68d85fbc2 100644
--- a/clang/lib/Analysis/CalledOnceCheck.cpp
+++ b/clang/lib/Analysis/CalledOnceCheck.cpp
@@ -22,6 +22,7 @@
 #include "clang/Analysis/AnalysisDeclContext.h"
 #include "clang/Analysis/CFG.h"
 #include "clang/Analysis/FlowSensitive/DataflowWorklist.h"
+#include "clang/Basic/Builtins.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/BitVector.h"
@@ -330,6 +331,29 @@ class DeclRefFinder
 return Visit(OVE->getSourceExpr());
   }
 
+  const DeclRefExpr *VisitCallExpr(const CallExpr *CE) {
+if (!ShouldRetrieveFromComparisons)
+  return nullptr;
+
+// We want to see through some of the boolean builtin functions
+// that we are likely to see in conditions.
+switch (CE->getBuiltinCallee()) {
+case Builtin::BI__builtin_expect:
+case Builtin::BI__builtin_expect_with_probability: {
+  assert(CE->getNumArgs() >= 2);
+
+  const DeclRefExpr *Candidate = Visit(CE->getArg(0));
+  return Candidate != nullptr ? Candidate : Visit(CE->getArg(1));
+}
+
+case Builtin::BI__builtin_unpredictable:
+  return Visit(CE->getArg(0));
+
+default:
+  return nullptr;
+}
+  }
+
   const DeclRefExpr *VisitExpr(const Expr *E) {
 // It is a fallback method that gets called whenever the actual type
 // of the given expression is not covered.

diff  --git a/clang/test/SemaObjC/warn-called-once.m 
b/clang/test/SemaObjC/warn-called-once.m
index 094f92a49935..0c11d0e0a15b 100644
--- a/clang/test/SemaObjC/warn-called-once.m
+++ b/clang/test/SemaObjC/warn-called-once.m
@@ -4,6 +4,11 @@
 #define nil (id)0
 #define CALLED_ONCE __attribute__((called_once))
 #define NORETURN __attribute__((noreturn))
+#define LIKELY(X) __builtin_expect(!!(X), 1)
+#define UNLIKELY(X) __builtin_expect(!!(X), 0)
+#define LIKELY_WITH_PROBA(X, P) __builtin_expect_with_probability(!!(X), 1, P)
+#define UNLIKELY_WITH_PROBA(X, P) __builtin_expect_with_probability(!!(X), 0, 
P)
+#define UNPRED(X) __builtin_unpredictable((long)(X))
 
 @protocol NSObject
 @end
@@ -547,6 +552,70 @@ int call_with_check_7(int (^callback)(void) CALLED_ONCE) {
   // no-warning
 }
 
+void call_with_builtin_check_1(int (^callback)(void) CALLED_ONCE) {
+  if (LIKELY(callback))
+callback();
+  // no-warning
+}
+
+void call_with_builtin_check_2(int (^callback)(void) CALLED_ONCE) {
+  if (!UNLIKELY(callback)) {
+  } else {
+callback();
+  }
+  // no-warning
+}
+
+void call_with_builtin_check_3(int (^callback)(void) CALLED_ONCE) {
+  if (__builtin_expect((long)callback, 0L)) {
+  } else {
+callback();
+  }
+  // no-warning
+}
+
+void call_with_builtin_check_4(int (^callback)(void) CALLED_ONCE) {
+  if (__builtin_expect(0L, (long)callback)) {
+  } else {
+callback();
+  }
+  // no-warning
+}
+
+void call_with_builtin_check_5(int (^callback)(void) CALLED_ONCE) {
+  if (LIKELY_WITH_PROBA(callback, 0.9))
+callback();
+  // no-warning
+}
+
+void call_with_builtin_check_6(int (^callback)(void) CALLED_ONCE) {
+  if (!UNLIKELY_WITH_PROBA(callback, 0.9)) {
+  } else {
+callback();
+  }
+  // no-warning
+}
+
+void call_with_builtin_check_7(int (^callback)(void) CALLED_ONCE) {
+  if (UNPRED(callback)) {
+  } else {
+callback();
+  }
+  // no-warning
+}
+
+void call_with_builtin_check_8(int (^callback)(void) CALLED_ONCE) {
+  if (LIKELY(callback != nil))
+callback();
+  // no-warning
+}
+
+void call_with_builtin_check_9(int (^callback)(void) CALLED_ONCE) {
+  if (!UNLIKELY(callback == NULL))
+callback();
+  // no-warning
+}
+
 void unreachable_true_branch(void (^callback)(void) CALLED_ONCE) {
   if (0) {
 



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


[clang] 9300ca5 - [doxygen] Fix bad doxygen results for BugReporterVisitors.h

2020-08-28 Thread Valeriy Savchenko via cfe-commits

Author: Ella Ma
Date: 2020-08-28T12:41:16+03:00
New Revision: 9300ca541164b80efb7d42dc45219b5d8e05de68

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

LOG: [doxygen] Fix bad doxygen results for BugReporterVisitors.h

`{@code x}` triggers a Doxygen bug. The bug may be matching the
close brace with the open brace of the namespace
declaration (`namespace clang {` or `namespace ento {`).

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

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h 
b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index 1aff2ca34a70..58a88f452ed9 100644
--- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -53,7 +53,7 @@ class BugReporterVisitor : public llvm::FoldingSetNode {
   /// Note that this function does *not* get run on the very last node
   /// of the report, as the PathDiagnosticPiece associated with the
   /// last node should be unique.
-  /// Use {@code getEndPath} to customize the note associated with the report
+  /// Use \ref getEndPath to customize the note associated with the report
   /// end instead.
   ///
   /// The last parameter can be used to register a new visitor with the given



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


[clang] aec12c1 - [analyzer][tests] Add a notion of project sizes

2020-08-24 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-08-24T16:13:00+03:00
New Revision: aec12c1264ac17877d5cb19750eaa322fe57342d

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

LOG: [analyzer][tests] Add a notion of project sizes

Summary:
Whith the number of projects growing, it is important to be able to
filter them in a more convenient way than by names.  It is especially
important for benchmarks, when it is not viable to analyze big
projects 20 or 50 times in a row.

Because of this reason, this commit adds a notion of sizes and a
filtering interface that puts a limit on a maximum size of the project
to analyze or benchmark.

Sizes assigned to the projects in this commit, do not directly
correspond to the number of lines or files in the project.  The key
factor that is important for the developers of the analyzer is the
time it takes to analyze the project.  And for this very reason,
"size" basically helps to cluster projects based on their analysis
time.

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

Added: 


Modified: 
clang/utils/analyzer/ProjectMap.py
clang/utils/analyzer/SATest.py
clang/utils/analyzer/projects/projects.json

Removed: 




diff  --git a/clang/utils/analyzer/ProjectMap.py 
b/clang/utils/analyzer/ProjectMap.py
index 3daa70140562..1e89ce634e57 100644
--- a/clang/utils/analyzer/ProjectMap.py
+++ b/clang/utils/analyzer/ProjectMap.py
@@ -1,7 +1,7 @@
 import json
 import os
 
-from enum import Enum
+from enum import auto, Enum
 from typing import Any, Dict, List, NamedTuple, Optional, Tuple
 
 
@@ -17,6 +17,64 @@ class DownloadType(str, Enum):
 SCRIPT = "script"
 
 
+class Size(int, Enum):
+"""
+Size of the project.
+
+Sizes do not directly correspond to the number of lines or files in the
+project.  The key factor that is important for the developers of the
+analyzer is the time it takes to analyze the project.  Here is how
+the following sizes map to times:
+
+TINY:  <1min
+SMALL: 1min-10min
+BIG:   10min-1h
+HUGE:  >1h
+
+The borders are a bit of a blur, especially because analysis time varies
+from one machine to another.  However, the relative times will stay pretty
+similar, and these groupings will still be helpful.
+
+UNSPECIFIED is a very special case, which is intentionally last in the list
+of possible sizes.  If the user wants to filter projects by one of the
+possible sizes, we want projects with UNSPECIFIED size to be filtered out
+for any given size.
+"""
+TINY = auto()
+SMALL = auto()
+BIG = auto()
+HUGE = auto()
+UNSPECIFIED = auto()
+
+@staticmethod
+def from_str(raw_size: Optional[str]) -> "Size":
+"""
+Construct a Size object from an optional string.
+
+:param raw_size: optional string representation of the desired Size
+ object.  None will produce UNSPECIFIED size.
+
+This method is case-insensitive, so raw sizes 'tiny', 'TINY', and
+'TiNy' will produce the same result.
+"""
+if raw_size is None:
+return Size.UNSPECIFIED
+
+raw_size_upper = raw_size.upper()
+# The implementation is decoupled from the actual values of the enum,
+# so we can easily add or modify it without bothering about this
+# function.
+for possible_size in Size:
+if possible_size.name == raw_size_upper:
+return possible_size
+
+possible_sizes = [size.name.lower() for size in Size
+  # no need in showing our users this size
+  if size != Size.UNSPECIFIED]
+raise ValueError(f"Incorrect project size '{raw_size}'. "
+ f"Available sizes are {possible_sizes}")
+
+
 class ProjectInfo(NamedTuple):
 """
 Information about a project to analyze.
@@ -27,6 +85,7 @@ class ProjectInfo(NamedTuple):
 origin: str = ""
 commit: str = ""
 enabled: bool = True
+size: Size = Size.UNSPECIFIED
 
 def with_fields(self, **kwargs) -> "ProjectInfo":
 """
@@ -98,6 +157,7 @@ def _parse_project(raw_project: JSON) -> ProjectInfo:
 build_mode: int = raw_project["mode"]
 enabled: bool = raw_project.get("enabled", True)
 source: DownloadType = raw_project.get("source", "zip")
+size = Size.from_str(raw_project.get("size", None))
 
 if source == DownloadType.GIT:
 origin, commit = ProjectMap._get_git_params(raw_project)
@@ -105,7 +165,7 @@ def _parse_project(raw_project: JSON) -> ProjectInfo:
 origin, commit = "", ""
 
 return ProjectInfo(name, build_mode, source, origin, commit,
-   

[clang] 9cbfdde - [analyzer] Fix crash with pointer to members values

2020-08-13 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-08-13T18:03:59+03:00
New Revision: 9cbfdde2ea060d7e51fd2637f63eaa74b8d92848

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

LOG: [analyzer] Fix crash with pointer to members values

This fix unifies all of the different ways we handled pointer to
members into one.  The crash was caused by the fact that the type
of pointer-to-member values was `void *`, and while this works
for the vast majority of cases it breaks when we actually need
to explain the path for the report.

rdar://problem/64202361

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

Added: 
clang/test/Analysis/PR46264.cpp

Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
clang/lib/StaticAnalyzer/Core/SVals.cpp
clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
clang/test/Analysis/pointer-to-member.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index a001c0dc7030..142b1ab11750 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -79,11 +79,11 @@ class LazyCompoundValData : public llvm::FoldingSetNode {
 };
 
 class PointerToMemberData : public llvm::FoldingSetNode {
-  const DeclaratorDecl *D;
+  const NamedDecl *D;
   llvm::ImmutableList L;
 
 public:
-  PointerToMemberData(const DeclaratorDecl *D,
+  PointerToMemberData(const NamedDecl *D,
   llvm::ImmutableList L)
   : D(D), L(L) {}
 
@@ -92,11 +92,11 @@ class PointerToMemberData : public llvm::FoldingSetNode {
   iterator begin() const { return L.begin(); }
   iterator end() const { return L.end(); }
 
-  static void Profile(llvm::FoldingSetNodeID& ID, const DeclaratorDecl *D,
+  static void Profile(llvm::FoldingSetNodeID , const NamedDecl *D,
   llvm::ImmutableList L);
 
-  void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, D, L); }
-  const DeclaratorDecl *getDeclaratorDecl() const {return D;}
+  void Profile(llvm::FoldingSetNodeID ) { Profile(ID, D, L); }
+  const NamedDecl *getDeclaratorDecl() const { return D; }
 
   llvm::ImmutableList getCXXBaseList() const {
 return L;
@@ -236,9 +236,9 @@ class BasicValueFactory {
   const LazyCompoundValData *getLazyCompoundValData(const StoreRef ,
 const TypedValueRegion *region);
 
-  const PointerToMemberData *getPointerToMemberData(
-  const DeclaratorDecl *DD,
-  llvm::ImmutableList L);
+  const PointerToMemberData *
+  getPointerToMemberData(const NamedDecl *ND,
+ llvm::ImmutableList L);
 
   llvm::ImmutableList getEmptySValList() {
 return SValListFactory.getEmptyList();

diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 35ebefdc00d6..4ea85f9730bb 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -233,7 +233,7 @@ class SValBuilder {
const LocationContext *LCtx,
unsigned count);
 
-  DefinedSVal getMemberPointer(const DeclaratorDecl *DD);
+  DefinedSVal getMemberPointer(const NamedDecl *ND);
 
   DefinedSVal getFunctionPointer(const FunctionDecl *func);
 

diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index a561ac67bf78..bb295ab591d4 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -520,7 +520,7 @@ class PointerToMember : public NonLoc {
 
 public:
   using PTMDataType =
-  llvm::PointerUnion;
+  llvm::PointerUnion;
 
   const PTMDataType getPTMData() const {
 return PTMDataType::getFromOpaqueValue(const_cast(Data));
@@ -528,7 +528,7 @@ class PointerToMember : public NonLoc {
 
   bool isNullMemberPointer() const;
 
-  const DeclaratorDecl *getDecl() const;
+  const NamedDecl *getDecl() const;
 
   template
   const AdjustedDecl *getDeclAs() const {

diff  --git a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp 

[clang] 6ddef92 - [analyzer][tests] Understand when diagnostics change between builds

2020-08-06 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-08-06T12:53:20+03:00
New Revision: 6ddef92474583ef3c183da9bdc8c8e81ec578fd8

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

LOG: [analyzer][tests] Understand when diagnostics change between builds

Before the patch `SATest compare`, produced quite obscure results
when something about the diagnostic have changed (i.e. its description
or the name of the corresponding checker) because it was simply two
lists of warnings, ADDED and REMOVED.  It was up to the developer
to match those warnings, understand that they are essentially the
same, and figure out what caused the difference.

This patch introduces another category of results: MODIFIED.
It tries to match new warnings against the old ones and prints out
clues on what is different between two builds.

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

Added: 


Modified: 
clang/utils/analyzer/CmpRuns.py

Removed: 




diff  --git a/clang/utils/analyzer/CmpRuns.py b/clang/utils/analyzer/CmpRuns.py
index f7f28d9dc72e..9d5e00767067 100644
--- a/clang/utils/analyzer/CmpRuns.py
+++ b/clang/utils/analyzer/CmpRuns.py
@@ -35,14 +35,16 @@
 from collections import defaultdict
 from copy import copy
 from enum import Enum
-from typing import (Any, cast, Dict, List, NamedTuple, Optional, Sequence,
-TextIO, TypeVar, Tuple, Union)
+from typing import (Any, DefaultDict, Dict, List, NamedTuple, Optional,
+Sequence, TextIO, TypeVar, Tuple, Union)
 
 
 Number = Union[int, float]
 Stats = Dict[str, Dict[str, Number]]
 Plist = Dict[str, Any]
 JSON = Dict[str, Any]
+# Diff in a form: field -> (before, after)
+JSONDiff = Dict[str, Tuple[str, str]]
 # Type for generics
 T = TypeVar('T')
 
@@ -136,6 +138,9 @@ def get_category(self) -> str:
 def get_description(self) -> str:
 return self._data['description']
 
+def get_location(self) -> str:
+return f"{self.get_file_name()}:{self.get_line()}:{self.get_column()}"
+
 def get_issue_identifier(self) -> str:
 id = self.get_file_name() + "+"
 
@@ -172,11 +177,32 @@ def get_readable_name(self) -> str:
 return f"{file_prefix}{funcname_postfix}:{line}:{col}" \
 f", {self.get_category()}: {self.get_description()}"
 
+KEY_FIELDS = ["check_name", "category", "description"]
+
+def is_similar_to(self, other: "AnalysisDiagnostic") -> bool:
+# We consider two diagnostics similar only if at least one
+# of the key fields is the same in both diagnostics.
+return len(self.get_
diff s(other)) != len(self.KEY_FIELDS)
+
+def get_
diff s(self, other: "AnalysisDiagnostic") -> JSONDiff:
+return {field: (self._data[field], other._data[field])
+for field in self.KEY_FIELDS
+if self._data[field] != other._data[field]}
+
 # Note, the data format is not an API and may change from one analyzer
 # version to another.
 def get_raw_data(self) -> Plist:
 return self._data
 
+def __eq__(self, other: object) -> bool:
+return hash(self) == hash(other)
+
+def __ne__(self, other: object) -> bool:
+return hash(self) != hash(other)
+
+def __hash__(self) -> int:
+return hash(self.get_issue_identifier())
+
 
 class AnalysisRun:
 def __init__(self, info: SingleRunInfo):
@@ -283,12 +309,39 @@ def cmp_analysis_diagnostic(d):
 return d.get_issue_identifier()
 
 
-PresentInBoth = Tuple[AnalysisDiagnostic, AnalysisDiagnostic]
-PresentOnlyInOld = Tuple[AnalysisDiagnostic, None]
-PresentOnlyInNew = Tuple[None, AnalysisDiagnostic]
-ComparisonResult = List[Union[PresentInBoth,
-  PresentOnlyInOld,
-  PresentOnlyInNew]]
+AnalysisDiagnosticPair = Tuple[AnalysisDiagnostic, AnalysisDiagnostic]
+
+
+class ComparisonResult:
+def __init__(self):
+self.present_in_both: List[AnalysisDiagnostic] = []
+self.present_only_in_old: List[AnalysisDiagnostic] = []
+self.present_only_in_new: List[AnalysisDiagnostic] = []
+self.changed_between_new_and_old: List[AnalysisDiagnosticPair] = []
+
+def add_common(self, issue: AnalysisDiagnostic):
+self.present_in_both.append(issue)
+
+def add_removed(self, issue: AnalysisDiagnostic):
+self.present_only_in_old.append(issue)
+
+def add_added(self, issue: AnalysisDiagnostic):
+self.present_only_in_new.append(issue)
+
+def add_changed(self, old_issue: AnalysisDiagnostic,
+new_issue: AnalysisDiagnostic):
+self.changed_between_new_and_old.append((old_issue, new_issue))
+
+
+GroupedDiagnostics = DefaultDict[str, List[AnalysisDiagnostic]]
+
+
+def get_grouped_diagnostics(diagnostics: 

[clang] 10851f9 - [analyzer][tests] Fix SATest update functionality

2020-08-03 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-08-03T18:21:15+03:00
New Revision: 10851f9db5f7d163135374b8dfc945e1b4a9c7d6

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

LOG: [analyzer][tests] Fix SATest update functionality

Summary:
Not all projects in the project map file might have newer results
for updating, we should handle this situation gracefully.

Additionally, not every user of the test system would want storing
reference results in git.  For this reason, git functionality is now
optional.

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

Added: 


Modified: 
clang/utils/analyzer/SATest.py
clang/utils/analyzer/SATestUpdateDiffs.py

Removed: 




diff  --git a/clang/utils/analyzer/SATest.py b/clang/utils/analyzer/SATest.py
index 46e636ad2895..86571902502f 100755
--- a/clang/utils/analyzer/SATest.py
+++ b/clang/utils/analyzer/SATest.py
@@ -78,7 +78,7 @@ def update(parser, args):
 
 project_map = ProjectMap()
 for project in project_map.projects:
-SATestUpdateDiffs.update_reference_results(project)
+SATestUpdateDiffs.update_reference_results(project, args.git)
 
 
 def benchmark(parser, args):
@@ -277,7 +277,8 @@ def main():
 "update",
 help="Update static analyzer reference results based on the previous "
 "run of SATest build. Assumes that SATest build was just run.")
-# TODO: add option to decide whether we should use git
+upd_parser.add_argument("--git", action="store_true",
+help="Stage updated results using git.")
 upd_parser.set_defaults(func=update)
 
 # docker subcommand

diff  --git a/clang/utils/analyzer/SATestUpdateDiffs.py 
b/clang/utils/analyzer/SATestUpdateDiffs.py
index 920fa15e4c6f..69b3383beaf1 100644
--- a/clang/utils/analyzer/SATestUpdateDiffs.py
+++ b/clang/utils/analyzer/SATestUpdateDiffs.py
@@ -15,7 +15,7 @@
 Verbose = 0
 
 
-def update_reference_results(project: ProjectInfo):
+def update_reference_results(project: ProjectInfo, git: bool = False):
 test_info = SATestBuild.TestInfo(project)
 tester = SATestBuild.ProjectTester(test_info)
 project_dir = tester.get_project_dir()
@@ -27,9 +27,10 @@ def update_reference_results(project: ProjectInfo):
 created_results_path = tester.get_output_dir()
 
 if not os.path.exists(created_results_path):
-print("New results not found, was SATestBuild.py previously run?",
+print(f"Skipping project '{project.name}', "
+  f"it doesn't have newer results.",
   file=sys.stderr)
-sys.exit(1)
+return
 
 build_log_path = SATestBuild.get_build_log_path(ref_results_path)
 build_log_dir = os.path.dirname(os.path.abspath(build_log_path))
@@ -45,7 +46,8 @@ def run_cmd(command: str):
 # Remove reference results: in git, and then again for a good measure
 # with rm, as git might not remove things fully if there are empty
 # directories involved.
-run_cmd(f"git rm -r -q '{ref_results_path}'")
+if git:
+run_cmd(f"git rm -r -q '{ref_results_path}'")
 shutil.rmtree(ref_results_path)
 
 # Replace reference results with a freshly computed once.
@@ -60,22 +62,11 @@ def run_cmd(command: str):
 # Clean up the generated 
diff erence results.
 SATestBuild.cleanup_reference_results(ref_results_path)
 
-run_cmd(f"git add '{ref_results_path}'")
+if git:
+run_cmd(f"git add '{ref_results_path}'")
 
 
-# TODO: use argparse
-def main(argv):
-if len(argv) == 2 and argv[1] in ("-h", "--help"):
-print("Update static analyzer reference results based "
-  "\non the previous run of SATestBuild.py.\n"
-  "\nN.B.: Assumes that SATestBuild.py was just run",
-  file=sys.stderr)
-sys.exit(1)
-
-project_map = ProjectMap()
-for project in project_map.projects:
-update_reference_results(project)
-
-
-if __name__ == '__main__':
-main(sys.argv)
+if __name__ == "__main__":
+print("SATestUpdateDiffs.py should not be used on its own.")
+print("Please use 'SATest.py update' instead")
+sys.exit(1)



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


[clang] b13d987 - [analyzer][solver] Track symbol equivalence

2020-07-22 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-07-22T13:02:39+03:00
New Revision: b13d9878b8dcef4354ddfc86f382ca9b537e65aa

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

LOG: [analyzer][solver] Track symbol equivalence

Summary:
For the most cases, we try to reason about symbol either based on the
information we know about that symbol in particular or about its
composite parts.  This is faster and eliminates costly brute force
searches through existing constraints.

However, we do want to support some cases that are widespread enough
and involve reasoning about different existing constraints at once.
These include:
  * resoning about 'a - b' based on what we know about 'b - a'
  * reasoning about 'a <= b' based on what we know about 'a > b' or 'a < b'

This commit expands on that part by tracking symbols known to be equal
while still avoiding brute force searches.  It changes the way we track
constraints for individual symbols.  If we know for a fact that 'a == b'
then there is no need in tracking constraints for both 'a' and 'b' especially
if these constraints are different.  This additional relationship makes
dead/live logic for constraints harder as we want to maintain as much
information on the equivalence class as possible, but we still won't
carry the information that we don't need anymore.

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

Added: 
clang/test/Analysis/equality_tracking.c

Modified: 
clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h

clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h 
b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index 365b1ff1bfe3..1aff2ca34a70 100644
--- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -373,7 +373,7 @@ class SuppressInlineDefensiveChecksVisitor final : public 
BugReporterVisitor {
 class FalsePositiveRefutationBRVisitor final : public BugReporterVisitor {
 private:
   /// Holds the constraints in a given path
-  ConstraintRangeTy Constraints;
+  ConstraintMap Constraints;
 
 public:
   FalsePositiveRefutationBRVisitor();
@@ -390,7 +390,6 @@ class FalsePositiveRefutationBRVisitor final : public 
BugReporterVisitor {
   bool OverwriteConstraintsOnExistingSyms);
 };
 
-
 /// The visitor detects NoteTags and displays the event notes they contain.
 class TagVisitor : public BugReporterVisitor {
 public:

diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
index 2f71f6fa..bc5d5f57cd68 100644
--- 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
+++ 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -136,14 +136,8 @@ class RangeSet {
   }
 };
 
-class ConstraintRange {};
-using ConstraintRangeTy = llvm::ImmutableMap;
-
-template <>
-struct ProgramStateTrait
-: public ProgramStatePartialTrait {
-  static void *GDMIndex();
-};
+using ConstraintMap = llvm::ImmutableMap;
+ConstraintMap getConstraintMap(ProgramStateRef State);
 
 class RangedConstraintManager : public SimpleConstraintManager {
 public:
@@ -222,4 +216,6 @@ class RangedConstraintManager : public 
SimpleConstraintManager {
 } // namespace ento
 } // namespace clang
 
+REGISTER_FACTORY_WITH_PROGRAMSTATE(ConstraintMap)
+
 #endif

diff  --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index ef4d38ff498f..bc72f4f8c1e3 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -2813,7 +2813,7 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, 
BugReporterContext ,
 
//===--===//
 
 FalsePositiveRefutationBRVisitor::FalsePositiveRefutationBRVisitor()
-: Constraints(ConstraintRangeTy::Factory().getEmptyMap()) {}
+: Constraints(ConstraintMap::Factory().getEmptyMap()) {}
 
 void FalsePositiveRefutationBRVisitor::finalizeVisitor(
 BugReporterContext , const ExplodedNode *EndPathNode,
@@ -2855,9 +2855,8 @@ void FalsePositiveRefutationBRVisitor::finalizeVisitor(
 void FalsePositiveRefutationBRVisitor::addConstraints(
 const ExplodedNode *N, bool 

[clang] f531c1c - [analyzer] Introduce small improvements to the solver infra

2020-07-22 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-07-22T13:02:39+03:00
New Revision: f531c1c7c0d5850c824333518ff32708730d775b

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

LOG: [analyzer] Introduce small improvements to the solver infra

Summary:
* Add a new function to delete points from range sets.
* Introduce an internal generic interface for range set intersections.
* Remove unnecessary bits from a couple of solver functions.
* Add in-code sections.

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

Added: 


Modified: 

clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
index a42eebd7d4e8..2f71f6fa 100644
--- 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
+++ 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -126,6 +126,8 @@ class RangeSet {
   RangeSet Intersect(BasicValueFactory , Factory ,
  const RangeSet ) const;
   RangeSet Negate(BasicValueFactory , Factory ) const;
+  RangeSet Delete(BasicValueFactory , Factory ,
+  const llvm::APSInt ) const;
 
   void print(raw_ostream ) const;
 
@@ -139,11 +141,10 @@ using ConstraintRangeTy = llvm::ImmutableMap;
 
 template <>
 struct ProgramStateTrait
-  : public ProgramStatePartialTrait {
+: public ProgramStatePartialTrait {
   static void *GDMIndex();
 };
 
-
 class RangedConstraintManager : public SimpleConstraintManager {
 public:
   RangedConstraintManager(ExprEngine *EE, SValBuilder )
@@ -169,8 +170,8 @@ class RangedConstraintManager : public 
SimpleConstraintManager {
 protected:
   /// Assume a constraint between a symbolic expression and a concrete integer.
   virtual ProgramStateRef assumeSymRel(ProgramStateRef State, SymbolRef Sym,
-   BinaryOperator::Opcode op,
-   const llvm::APSInt );
+   BinaryOperator::Opcode op,
+   const llvm::APSInt );
 
   //===--===//
   // Interface that subclasses must implement.
@@ -218,8 +219,7 @@ class RangedConstraintManager : public 
SimpleConstraintManager {
   static void computeAdjustment(SymbolRef , llvm::APSInt );
 };
 
-} // end GR namespace
-
-} // end clang namespace
+} // namespace ento
+} // namespace clang
 
 #endif

diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index cb6f61e86ae3..a5bb36e2026e 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -89,7 +89,7 @@ class OperatorRelationsTable {
   }
 
   TriStateKind getCmpOpState(BinaryOperatorKind CurrentOP,
- BinaryOperatorKind QueriedOP) const {
+ BinaryOperatorKind QueriedOP) const {
 return CmpOpTable[getIndexFromOp(CurrentOP)][getIndexFromOp(QueriedOP)];
   }
 
@@ -364,6 +364,18 @@ RangeSet RangeSet::Negate(BasicValueFactory , Factory 
) const {
   return newRanges;
 }
 
+RangeSet RangeSet::Delete(BasicValueFactory , Factory ,
+  const llvm::APSInt ) const {
+  llvm::APSInt Upper = Point;
+  llvm::APSInt Lower = Point;
+
+  ++Upper;
+  --Lower;
+
+  // Notice that the lower bound is greater than the upper bound.
+  return Intersect(BV, F, Upper, Lower);
+}
+
 void RangeSet::print(raw_ostream ) const {
   bool isFirst = true;
   os << "{ ";
@@ -381,6 +393,107 @@ void RangeSet::print(raw_ostream ) const {
 
 namespace {
 
+//===--===//
+//Intersection functions
+//===--===//
+
+template 
+LLVM_NODISCARD inline RangeSet intersect(BasicValueFactory ,
+ RangeSet::Factory , RangeSet Head,
+ SecondTy Second, RestTy... Tail);
+
+template  struct IntersectionTraits;
+
+template  struct IntersectionTraits {
+  // Found RangeSet, no need to check any further
+  using Type = RangeSet;
+};
+
+template <> struct IntersectionTraits<> {
+  // We ran out of types, and we didn't find any RangeSet, so the result should
+  // be optional.
+  using Type = Optional;
+};
+
+template 
+struct IntersectionTraits {
+  // If current type is Optional or a raw pointer, we should keep 

[clang] e63b488 - [analyzer][solver] Track symbol disequalities

2020-07-22 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-07-22T13:02:39+03:00
New Revision: e63b488f2755f91e8147fd678ed525cf6ba007cc

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

LOG: [analyzer][solver] Track symbol disequalities

Summary:
This commmit adds another relation that we can track separately from
range constraints.  Symbol disequality can help us understand that
two equivalence classes are not equal to each other.  We can generalize
this knowledge to classes because for every a,b,c, and d that
a == b, c == d, and b != c it is true that a != d.

As a result, we can reason about other equalities/disequalities of symbols
that we know nothing else about, i.e. no constraint ranges associated
with them.  However, we also benefit from the knowledge of disequal
symbols by following the rule:
  if a != b and b == C where C is a constant, a != C
This information can refine associated ranges for different classes
and reduce the number of false positives and paths to explore.

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

Added: 
clang/test/Analysis/mutually_exclusive_null_fp.cpp

Modified: 
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/test/Analysis/equality_tracking.c

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 4c134b63efb0..32766d796add 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -401,6 +401,9 @@ REGISTER_MAP_WITH_PROGRAMSTATE(ClassMap, SymbolRef, 
EquivalenceClass)
 REGISTER_MAP_WITH_PROGRAMSTATE(ClassMembers, EquivalenceClass, SymbolSet)
 REGISTER_MAP_WITH_PROGRAMSTATE(ConstraintRange, EquivalenceClass, RangeSet)
 
+REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(ClassSet, EquivalenceClass)
+REGISTER_MAP_WITH_PROGRAMSTATE(DisequalityMap, EquivalenceClass, ClassSet)
+
 namespace {
 /// This class encapsulates a set of symbols equal to each other.
 ///
@@ -450,6 +453,26 @@ class EquivalenceClass : public llvm::FoldingSetNode {
   LLVM_NODISCARD inline bool isTriviallyDead(ProgramStateRef State,
  SymbolReaper );
 
+  LLVM_NODISCARD static inline ProgramStateRef
+  markDisequal(BasicValueFactory , RangeSet::Factory ,
+   ProgramStateRef State, SymbolRef First, SymbolRef Second);
+  LLVM_NODISCARD static inline ProgramStateRef
+  markDisequal(BasicValueFactory , RangeSet::Factory ,
+   ProgramStateRef State, EquivalenceClass First,
+   EquivalenceClass Second);
+  LLVM_NODISCARD inline ProgramStateRef
+  markDisequal(BasicValueFactory , RangeSet::Factory ,
+   ProgramStateRef State, EquivalenceClass Other) const;
+  LLVM_NODISCARD static inline ClassSet
+  getDisequalClasses(ProgramStateRef State, SymbolRef Sym);
+  LLVM_NODISCARD inline ClassSet
+  getDisequalClasses(ProgramStateRef State) const;
+  LLVM_NODISCARD inline ClassSet
+  getDisequalClasses(DisequalityMapTy Map, ClassSet::Factory ) const;
+
+  LLVM_NODISCARD static inline Optional
+  areEqual(ProgramStateRef State, SymbolRef First, SymbolRef Second);
+
   /// Check equivalence data for consistency.
   LLVM_NODISCARD LLVM_ATTRIBUTE_UNUSED static bool
   isClassDataConsistent(ProgramStateRef State);
@@ -496,6 +519,11 @@ class EquivalenceClass : public llvm::FoldingSetNode {
ProgramStateRef State, SymbolSet Members,
EquivalenceClass Other,
SymbolSet OtherMembers);
+  static inline void
+  addToDisequalityInfo(DisequalityMapTy , ConstraintRangeTy ,
+   BasicValueFactory , RangeSet::Factory ,
+   ProgramStateRef State, EquivalenceClass First,
+   EquivalenceClass Second);
 
   /// This is a unique identifier of the class.
   uintptr_t ID;
@@ -505,17 +533,6 @@ class EquivalenceClass : public llvm::FoldingSetNode {
 // Constraint functions
 
//===--===//
 
-LLVM_NODISCARD inline ProgramStateRef setConstraint(ProgramStateRef State,
-EquivalenceClass Class,
-RangeSet Constraint) {
-  return State->set(Class, Constraint);
-}
-
-LLVM_NODISCARD inline ProgramStateRef
-setConstraint(ProgramStateRef State, SymbolRef Sym, RangeSet Constraint) {
-  return setConstraint(State, EquivalenceClass::find(State, Sym), Constraint);
-}
-
 LLVM_NODISCARD inline const RangeSet *getConstraint(ProgramStateRef State,
 EquivalenceClass 

[clang] 5b4f143 - [analyzer][tests] Introduce analyzer benchmarking framework

2020-07-14 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-07-14T11:42:46+03:00
New Revision: 5b4f143564502664a9d1197d6909047eab49530e

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

LOG: [analyzer][tests] Introduce analyzer benchmarking framework

Summary:
This commit includes a couple of changes:
  * Benchmark selected projects by analyzing them multiple times
  * Compare two benchmarking results and visualizing them on one chart
  * Organize project build logging, so we can use the same code
in benchmarks

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

Added: 
clang/utils/analyzer/SATestBenchmark.py

Modified: 
clang/utils/analyzer/SATest.py
clang/utils/analyzer/SATestBuild.py
clang/utils/analyzer/SATestUpdateDiffs.py
clang/utils/analyzer/requirements.txt

Removed: 




diff  --git a/clang/utils/analyzer/SATest.py b/clang/utils/analyzer/SATest.py
index 16f1dce0c584..46e636ad2895 100755
--- a/clang/utils/analyzer/SATest.py
+++ b/clang/utils/analyzer/SATest.py
@@ -34,29 +34,10 @@ def add(parser, args):
 
 def build(parser, args):
 import SATestBuild
-from ProjectMap import ProjectMap
 
 SATestBuild.VERBOSE = args.verbose
 
-project_map = ProjectMap()
-projects = project_map.projects
-
-if args.projects:
-projects_arg = args.projects.split(",")
-available_projects = [project.name
-  for project in projects]
-
-# validate that given projects are present in the project map file
-for manual_project in projects_arg:
-if manual_project not in available_projects:
-parser.error("Project '{project}' is not found in "
- "the project map file. Available projects are "
- "{all}.".format(project=manual_project,
- all=available_projects))
-
-projects = [project.with_fields(enabled=project.name in projects_arg)
-for project in projects]
-
+projects = get_projects(parser, args.projects)
 tester = SATestBuild.RegressionTester(args.jobs,
   projects,
   args.override_compiler,
@@ -100,6 +81,44 @@ def update(parser, args):
 SATestUpdateDiffs.update_reference_results(project)
 
 
+def benchmark(parser, args):
+from SATestBenchmark import Benchmark
+
+projects = get_projects(parser, args.projects)
+benchmark = Benchmark(projects, args.iterations, args.output)
+benchmark.run()
+
+
+def benchmark_compare(parser, args):
+import SATestBenchmark
+SATestBenchmark.compare(args.old, args.new, args.output)
+
+
+def get_projects(parser, projects_str):
+from ProjectMap import ProjectMap
+
+project_map = ProjectMap()
+projects = project_map.projects
+
+if projects_str:
+projects_arg = projects_str.split(",")
+available_projects = [project.name
+  for project in projects]
+
+# validate that given projects are present in the project map file
+for manual_project in projects_arg:
+if manual_project not in available_projects:
+parser.error("Project '{project}' is not found in "
+ "the project map file. Available projects are "
+ "{all}.".format(project=manual_project,
+ all=available_projects))
+
+projects = [project.with_fields(enabled=project.name in projects_arg)
+for project in projects]
+
+return projects
+
+
 def docker(parser, args):
 if len(args.rest) > 0:
 if args.rest[0] != "--":
@@ -284,6 +303,36 @@ def main():
  "to the docker's entrypoint.")
 dock_parser.set_defaults(func=docker)
 
+# benchmark subcommand
+bench_parser = subparsers.add_parser(
+"benchmark",
+help="Run benchmarks by building a set of projects multiple times.")
+
+bench_parser.add_argument("-i", "--iterations", action="store",
+  type=int, default=20,
+  help="Number of iterations for building each "
+  "project.")
+bench_parser.add_argument("-o", "--output", action="store",
+  default="benchmark.csv",
+  help="Output csv file for the benchmark results")
+bench_parser.add_argument("--projects", action="store", default="",
+  help="Comma-separated list of projects to test")
+bench_parser.set_defaults(func=benchmark)
+
+bench_subparsers = bench_parser.add_subparsers()
+bench_compare_parser = 

[clang] 089a0ad - [analyzer][tests] Add 5 more projects for testing

2020-07-14 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-07-14T11:42:46+03:00
New Revision: 089a0ad8bc993923817d7957f08bd67dbecd56af

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

LOG: [analyzer][tests] Add 5 more projects for testing

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

Added: 
clang/utils/analyzer/projects/capnproto/cleanup_run_static_analyzer.sh
clang/utils/analyzer/projects/capnproto/run_static_analyzer.cmd
clang/utils/analyzer/projects/cppcheck/cleanup_run_static_analyzer.sh
clang/utils/analyzer/projects/cppcheck/run_static_analyzer.cmd
clang/utils/analyzer/projects/faiss/cleanup_run_static_analyzer.sh
clang/utils/analyzer/projects/faiss/run_static_analyzer.cmd
clang/utils/analyzer/projects/harfbuzz/cleanup_run_static_analyzer.sh
clang/utils/analyzer/projects/harfbuzz/run_static_analyzer.cmd
clang/utils/analyzer/projects/tmux/cleanup_run_static_analyzer.sh
clang/utils/analyzer/projects/tmux/run_static_analyzer.cmd

Modified: 
clang/utils/analyzer/Dockerfile
clang/utils/analyzer/entrypoint.py
clang/utils/analyzer/projects/projects.json

Removed: 




diff  --git a/clang/utils/analyzer/Dockerfile b/clang/utils/analyzer/Dockerfile
index 21906011c7dc..f74ff8aa95c2 100644
--- a/clang/utils/analyzer/Dockerfile
+++ b/clang/utils/analyzer/Dockerfile
@@ -42,6 +42,16 @@ RUN apt-get install -y \
 libjsonrpccpp-dev=0.7.0-1build2 \
 uuid-dev=2.31.1-0.4ubuntu3.6
 
+# tmux dependencies
+RUN apt-get install -y \
+autotools-dev=20180224.1 \
+automake=1:1.15.1-3ubuntu2 \
+libncurses5-dev=6.1-1ubuntu1.18.04 \
+libevent-dev=2.1.8-stable-4build1 \
+pkg-config=0.29.1-0ubuntu2 \
+flex=2.6.4-6 \
+bison=2:3.0.4.dfsg-1build1
+
 RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 1
 
 VOLUME /analyzer

diff  --git a/clang/utils/analyzer/entrypoint.py 
b/clang/utils/analyzer/entrypoint.py
index b440e776b57c..9c84431da548 100644
--- a/clang/utils/analyzer/entrypoint.py
+++ b/clang/utils/analyzer/entrypoint.py
@@ -50,7 +50,7 @@ def is_cmake_needed():
 
 CMAKE_COMMAND = "cmake -G Ninja -DCMAKE_BUILD_TYPE=Release " \
 "-DCMAKE_INSTALL_PREFIX=/analyzer -DLLVM_TARGETS_TO_BUILD=X86 " \
-"-DLLVM_ENABLE_PROJECTS=clang -DLLVM_BUILD_RUNTIME=OFF " \
+"-DLLVM_ENABLE_PROJECTS=\"clang;openmp\" -DLLVM_BUILD_RUNTIME=OFF " \
 "-DLLVM_ENABLE_TERMINFO=OFF -DCLANG_ENABLE_ARCMT=OFF " \
 "-DCLANG_ENABLE_STATIC_ANALYZER=ON"
 

diff  --git 
a/clang/utils/analyzer/projects/capnproto/cleanup_run_static_analyzer.sh 
b/clang/utils/analyzer/projects/capnproto/cleanup_run_static_analyzer.sh
new file mode 100755
index ..e14c423280ec
--- /dev/null
+++ b/clang/utils/analyzer/projects/capnproto/cleanup_run_static_analyzer.sh
@@ -0,0 +1 @@
+rm -rf ./build

diff  --git a/clang/utils/analyzer/projects/capnproto/run_static_analyzer.cmd 
b/clang/utils/analyzer/projects/capnproto/run_static_analyzer.cmd
new file mode 100644
index ..6678fe635db3
--- /dev/null
+++ b/clang/utils/analyzer/projects/capnproto/run_static_analyzer.cmd
@@ -0,0 +1,2 @@
+cmake . -DCMAKE_BUILD_TYPE=Debug -Bbuild -GNinja
+cmake --build build

diff  --git 
a/clang/utils/analyzer/projects/cppcheck/cleanup_run_static_analyzer.sh 
b/clang/utils/analyzer/projects/cppcheck/cleanup_run_static_analyzer.sh
new file mode 100755
index ..e14c423280ec
--- /dev/null
+++ b/clang/utils/analyzer/projects/cppcheck/cleanup_run_static_analyzer.sh
@@ -0,0 +1 @@
+rm -rf ./build

diff  --git a/clang/utils/analyzer/projects/cppcheck/run_static_analyzer.cmd 
b/clang/utils/analyzer/projects/cppcheck/run_static_analyzer.cmd
new file mode 100644
index ..72cb7f7677e6
--- /dev/null
+++ b/clang/utils/analyzer/projects/cppcheck/run_static_analyzer.cmd
@@ -0,0 +1,2 @@
+cmake . -DCMAKE_BUILD_TYPE=Debug -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -Bbuild 
-GNinja
+cmake --build build

diff  --git 
a/clang/utils/analyzer/projects/faiss/cleanup_run_static_analyzer.sh 
b/clang/utils/analyzer/projects/faiss/cleanup_run_static_analyzer.sh
new file mode 100755
index ..efcd16e590a1
--- /dev/null
+++ b/clang/utils/analyzer/projects/faiss/cleanup_run_static_analyzer.sh
@@ -0,0 +1 @@
+make clean

diff  --git a/clang/utils/analyzer/projects/faiss/run_static_analyzer.cmd 
b/clang/utils/analyzer/projects/faiss/run_static_analyzer.cmd
new file mode 100644
index ..877fa2aa389b
--- /dev/null
+++ b/clang/utils/analyzer/projects/faiss/run_static_analyzer.cmd
@@ -0,0 +1,2 @@
+./configure --without-cuda
+make

diff  --git 
a/clang/utils/analyzer/projects/harfbuzz/cleanup_run_static_analyzer.sh 
b/clang/utils/analyzer/projects/harfbuzz/cleanup_run_static_analyzer.sh
new file mode 100755
index ..e14c423280ec
--- /dev/null
+++ 

[clang] e124062 - Fix bad doxygen result for class clang::ento::CallEvent and its derived classes

2020-07-13 Thread Valeriy Savchenko via cfe-commits

Author: Ella Ma
Date: 2020-07-13T12:25:26+03:00
New Revision: e124062bf3874e1ce7ddad407b35e95ec3d3ac13

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

LOG: Fix bad doxygen result for class clang::ento::CallEvent and its derived 
classes

Summary: Fix bug https://bugs.llvm.org/show_bug.cgi?id=44753. This
patch is a workaround of a Doxygen bug, so that it can correctly
generate documents for class clang::ento::CallEvent and its derived
classes.

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

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h

Removed: 




diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index d75f9f63286d..a2a98c558a4b 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -554,7 +554,7 @@ class SimpleFunctionCall : public AnyFunctionCall {
 
 /// Represents a call to a block.
 ///
-/// Example: ^{ /* ... */ }()
+/// Example: ^{ statement-body }()
 class BlockCall : public CallEvent {
   friend class CallEventManager;
 



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


[clang] 9c7ff0a - [analyzer][tests] Make test interruption safe

2020-07-10 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-07-10T11:31:59+03:00
New Revision: 9c7ff0a4aaef0a1efa33e9ff8a12a064087bded9

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

LOG: [analyzer][tests] Make test interruption safe

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

Added: 


Modified: 
clang/utils/analyzer/SATest.py

Removed: 




diff  --git a/clang/utils/analyzer/SATest.py b/clang/utils/analyzer/SATest.py
index fb2e031c6ab6..16f1dce0c584 100755
--- a/clang/utils/analyzer/SATest.py
+++ b/clang/utils/analyzer/SATest.py
@@ -132,27 +132,35 @@ def docker_shell(args):
 pass
 
 finally:
-print("Please wait for docker to clean up")
-call("docker stop satest", shell=True)
+docker_cleanup()
 
 
 def docker_run(args, command, docker_args=""):
-return call("docker run --rm --name satest "
-"-v {llvm}:/llvm-project "
-"-v {build}:/build "
-"-v {clang}:/analyzer "
-"-v {scripts}:/scripts "
-"-v {projects}:/projects "
-"{docker_args} "
-"satest-image:latest {command}"
-.format(llvm=args.llvm_project_dir,
-build=args.build_dir,
-clang=args.clang_dir,
-scripts=SCRIPTS_DIR,
-projects=PROJECTS_DIR,
-docker_args=docker_args,
-command=command),
-shell=True)
+try:
+return call("docker run --rm --name satest "
+"-v {llvm}:/llvm-project "
+"-v {build}:/build "
+"-v {clang}:/analyzer "
+"-v {scripts}:/scripts "
+"-v {projects}:/projects "
+"{docker_args} "
+"satest-image:latest {command}"
+.format(llvm=args.llvm_project_dir,
+build=args.build_dir,
+clang=args.clang_dir,
+scripts=SCRIPTS_DIR,
+projects=PROJECTS_DIR,
+docker_args=docker_args,
+command=command),
+shell=True)
+
+except KeyboardInterrupt:
+docker_cleanup()
+
+
+def docker_cleanup():
+print("Please wait for docker to clean up")
+call("docker stop satest", shell=True)
 
 
 def main():



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


[clang] 00997d1 - [analyzer][tests] Fix zip unpacking

2020-07-10 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-07-10T11:32:13+03:00
New Revision: 00997d1cad9ecd40c92aeae40269f6bfb9e58d11

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

LOG: [analyzer][tests] Fix zip unpacking

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

Added: 


Modified: 
clang/utils/analyzer/SATestBuild.py

Removed: 




diff  --git a/clang/utils/analyzer/SATestBuild.py 
b/clang/utils/analyzer/SATestBuild.py
index ee510e03cc5a..eefab869f6ef 100644
--- a/clang/utils/analyzer/SATestBuild.py
+++ b/clang/utils/analyzer/SATestBuild.py
@@ -601,7 +601,7 @@ def _download_from_git(self, directory: str, 
build_log_file: IO):
stdout=build_log_file, shell=True)
 
 def _unpack_zip(self, directory: str, build_log_file: IO):
-zip_files = list(glob.glob(os.path.join(directory, "/*.zip")))
+zip_files = list(glob.glob(directory + "/*.zip"))
 
 if len(zip_files) == 0:
 raise ValueError(



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


[clang] 21bacc2 - [analyzer][tests] Measure peak memory consumption for every project

2020-07-10 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-07-10T11:31:41+03:00
New Revision: 21bacc215413d10df53a4690e9561e9b96698742

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

LOG: [analyzer][tests] Measure peak memory consumption for every project

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

Added: 
clang/utils/analyzer/requirements.txt

Modified: 
clang/utils/analyzer/Dockerfile
clang/utils/analyzer/SATestBuild.py
clang/utils/analyzer/SATestUtils.py

Removed: 




diff  --git a/clang/utils/analyzer/Dockerfile b/clang/utils/analyzer/Dockerfile
index 30fb67cf93c8..21906011c7dc 100644
--- a/clang/utils/analyzer/Dockerfile
+++ b/clang/utils/analyzer/Dockerfile
@@ -54,8 +54,7 @@ ENV PATH="/analyzer/bin:${PATH}"
 
 ADD entrypoint.py /entrypoint.py
 
-# Uncomment in case of requirements
-# ADD requirements.txt /requirements.txt
-# RUN pip3 install -r /requirements.txt
+ADD requirements.txt /requirements.txt
+RUN pip3 install -r /requirements.txt
 
 ENTRYPOINT ["python", "/entrypoint.py"]

diff  --git a/clang/utils/analyzer/SATestBuild.py 
b/clang/utils/analyzer/SATestBuild.py
index 7d337632744f..ee510e03cc5a 100644
--- a/clang/utils/analyzer/SATestBuild.py
+++ b/clang/utils/analyzer/SATestBuild.py
@@ -43,7 +43,7 @@
 variable. It should contain a comma separated list.
 """
 import CmpRuns
-import SATestUtils
+import SATestUtils as utils
 from ProjectMap import DownloadType, ProjectInfo
 
 import glob
@@ -63,7 +63,7 @@
 # and this is we can shush that false positive
 from plistlib import InvalidFileException  # type:ignore
 from subprocess import CalledProcessError, check_call
-from typing import Dict, IO, List, NamedTuple, Optional, TYPE_CHECKING
+from typing import Dict, IO, List, NamedTuple, Optional, TYPE_CHECKING, Tuple
 
 
 ###
@@ -115,7 +115,7 @@ def stdout(message: str):
 if 'CC' in os.environ:
 cc_candidate: Optional[str] = os.environ['CC']
 else:
-cc_candidate = SATestUtils.which("clang", os.environ['PATH'])
+cc_candidate = utils.which("clang", os.environ['PATH'])
 if not cc_candidate:
 stderr("Error: cannot find 'clang' in PATH")
 sys.exit(1)
@@ -194,9 +194,9 @@ def run_cleanup_script(directory: str, build_log_file: IO):
 cwd = os.path.join(directory, PATCHED_SOURCE_DIR_NAME)
 script_path = os.path.join(directory, CLEANUP_SCRIPT)
 
-SATestUtils.run_script(script_path, build_log_file, cwd,
-   out=LOCAL.stdout, err=LOCAL.stderr,
-   verbose=VERBOSE)
+utils.run_script(script_path, build_log_file, cwd,
+ out=LOCAL.stdout, err=LOCAL.stderr,
+ verbose=VERBOSE)
 
 
 class TestInfo(NamedTuple):
@@ -351,8 +351,6 @@ def get_output_dir(self) -> str:
 return OUTPUT_DIR_NAME
 
 def build(self, directory: str, output_dir: str):
-time_start = time.time()
-
 build_log_path = get_build_log_path(output_dir)
 
 stdout(f"Log file: {build_log_path}\n")
@@ -375,19 +373,23 @@ def build(self, directory: str, output_dir: str):
 if self.project.mode == 1:
 self._download_and_patch(directory, build_log_file)
 run_cleanup_script(directory, build_log_file)
-self.scan_build(directory, output_dir, build_log_file)
+build_time, memory = self.scan_build(directory, output_dir,
+   build_log_file)
 else:
-self.analyze_preprocessed(directory, output_dir)
+build_time, memory = self.analyze_preprocessed(directory,
+   output_dir)
 
 if self.is_reference_build:
 run_cleanup_script(directory, build_log_file)
 normalize_reference_results(directory, output_dir,
 self.project.mode)
 
-stdout(f"Build complete (time: {time.time() - time_start:.2f}). "
+stdout(f"Build complete (time: {utils.time_to_str(build_time)}, "
+   f"peak memory: {utils.memory_to_str(memory)}). "
f"See the log for more details: {build_log_path}\n")
 
-def scan_build(self, directory: str, output_dir: str, build_log_file: IO):
+def scan_build(self, directory: str, output_dir: str,
+   build_log_file: IO) -> Tuple[float, int]:
 """
 Build the project with scan-build by reading in the commands and
 prefixing them with the scan-build options.
@@ -416,6 +418,10 @@ def scan_build(self, directory: str, output_dir: str, 
build_log_file: IO):
 options += "--override-compiler "
 
 extra_env: 

[clang] 3770f5c - [analyzer] SATest: Add convenience 'docker' command

2020-06-25 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-06-25T12:28:22+03:00
New Revision: 3770f5c9b98c5bae2f099f5c24e05eb4a0cca1d0

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

LOG: [analyzer] SATest: Add convenience 'docker' command

Summary:
It provides a simpler interface for testing within docker.
This way the user is not required to no how to use `docker run` and
its options.

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

Added: 


Modified: 
clang/utils/analyzer/SATest.py

Removed: 




diff  --git a/clang/utils/analyzer/SATest.py b/clang/utils/analyzer/SATest.py
index f45f593d08ec..f7cf5146566d 100755
--- a/clang/utils/analyzer/SATest.py
+++ b/clang/utils/analyzer/SATest.py
@@ -9,6 +9,16 @@
 
 import argparse
 import sys
+import os
+
+from subprocess import check_call
+
+SCRIPTS_DIR = os.path.dirname(os.path.realpath(__file__))
+PROJECTS_DIR = os.path.join(SCRIPTS_DIR, "projects")
+DEFAULT_LLVM_DIR = os.path.realpath(os.path.join(SCRIPTS_DIR,
+ os.path.pardir,
+ os.path.pardir,
+ os.path.pardir))
 
 
 def add(parser, args):
@@ -78,6 +88,37 @@ def update(parser, args):
 SATestUpdateDiffs.update_reference_results(project)
 
 
+def docker(parser, args):
+if len(args.rest) > 0:
+if args.rest[0] != "--":
+parser.error("REST arguments should start with '--'")
+args.rest = args.rest[1:]
+
+if args.build_image:
+docker_build_image()
+else:
+docker_run(args)
+
+
+def docker_build_image():
+check_call("docker build --tag satest-image {}".format(SCRIPTS_DIR),
+   shell=True)
+
+
+def docker_run(args):
+check_call("docker run --rm --name satest "
+   "-v {llvm}:/llvm-project "
+   "-v {build}:/build "
+   "-v {clang}:/analyzer "
+   "-v {scripts}:/scripts "
+   "-v {projects}:/projects "
+   "satest-image:latest {args}"
+   .format(llvm=args.llvm_project_dir, build=args.build_dir,
+   clang=args.clang_dir, scripts=SCRIPTS_DIR,
+   projects=PROJECTS_DIR, args=' '.join(args.rest)),
+   shell=True)
+
+
 def main():
 parser = argparse.ArgumentParser()
 subparsers = parser.add_subparsers()
@@ -180,6 +221,27 @@ def main():
 # TODO: add option to decide whether we should use git
 upd_parser.set_defaults(func=update)
 
+# docker subcommand
+dock_parser = subparsers.add_parser(
+"docker",
+help="Run regression system in the docker.")
+
+dock_parser.add_argument("--build-image", action="store_true",
+ help="Build docker image for running tests.")
+dock_parser.add_argument("--llvm-project-dir", action="store",
+ default=DEFAULT_LLVM_DIR,
+ help="Path to LLVM source code. Defaults "
+ "to the repo where this script is located. ")
+dock_parser.add_argument("--build-dir", action="store", default="",
+ help="Path to a directory where docker should "
+ "build LLVM code.")
+dock_parser.add_argument("--clang-dir", action="store", default="",
+ help="Path to find/install LLVM installation.")
+dock_parser.add_argument("rest", nargs=argparse.REMAINDER, default=[],
+ help="Additionall args that will be forwarded "
+ "to the docker's entrypoint.")
+dock_parser.set_defaults(func=docker)
+
 args = parser.parse_args()
 args.func(parser, args)
 



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


[clang] e010d14 - [analyzer] SATest: Add initial docker infrastructure

2020-06-25 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-06-25T12:28:21+03:00
New Revision: e010d1432fa15cff7a6d369f5e372d995e2eba5d

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

LOG: [analyzer] SATest: Add initial docker infrastructure

Summary:
Static analysis is very sensitive to environment.
OS and libraries installed can affect the results.  This fact makes
it extremely hard to have a regression testing system that will
produce stable results.

For this very reason, this commit introduces a new dockerized testing
environment, so that every analyzer developer can check their changes
against previous analysis results.

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

Added: 
clang/utils/analyzer/Dockerfile
clang/utils/analyzer/entrypoint.py

Modified: 


Removed: 




diff  --git a/clang/utils/analyzer/Dockerfile b/clang/utils/analyzer/Dockerfile
new file mode 100644
index ..e87377c9eec1
--- /dev/null
+++ b/clang/utils/analyzer/Dockerfile
@@ -0,0 +1,52 @@
+FROM ubuntu:bionic
+
+RUN apt-get update && apt-get install -y \
+apt-transport-https \
+ca-certificates \
+gnupg \
+software-properties-common \
+wget
+
+# newer CMake is required by LLVM
+RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 
2>/dev/null | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg 
>/dev/null
+RUN apt-add-repository -y 'deb https://apt.kitware.com/ubuntu/ bionic main'
+
+# test system dependencies
+RUN apt-get update && apt-get install -y \
+git \
+gettext \
+python3 \
+python3-pip \
+cmake \
+ninja-build
+
+# box2d dependencies
+RUN apt-get install -y \
+libx11-dev \
+libxrandr-dev \
+libxinerama-dev \
+libxcursor-dev \
+libxi-dev
+
+# symengine dependencies
+RUN apt-get install -y \
+libgmp10 \
+libgmp-dev
+
+RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 1
+
+VOLUME /analyzer
+VOLUME /projects
+VOLUME /llvm-project
+VOLUME /build
+VOLUME /scripts
+
+ENV PATH="/analyzer/bin:${PATH}"
+
+ADD entrypoint.py /entrypoint.py
+
+# Uncomment in case of requirements
+# ADD requirements.txt /requirements.txt
+# RUN pip3 install -r /requirements.txt
+
+ENTRYPOINT ["python", "/entrypoint.py"]

diff  --git a/clang/utils/analyzer/entrypoint.py 
b/clang/utils/analyzer/entrypoint.py
new file mode 100644
index ..3b85628a9a85
--- /dev/null
+++ b/clang/utils/analyzer/entrypoint.py
@@ -0,0 +1,52 @@
+import argparse
+import os
+
+from typing import List, Tuple
+
+from subprocess import check_call
+
+
+def main():
+settings, rest = parse_arguments()
+if settings.build_llvm or settings.build_llvm_only:
+build_llvm()
+if settings.build_llvm_only:
+return
+test(rest)
+
+
+def parse_arguments() -> Tuple[argparse.Namespace, List[str]]:
+parser = argparse.ArgumentParser()
+parser.add_argument('--build-llvm', action='store_true')
+parser.add_argument('--build-llvm-only', action='store_true')
+return parser.parse_known_args()
+
+
+def build_llvm() -> None:
+os.chdir('/build')
+cmake()
+ninja()
+
+
+CMAKE_COMMAND = "cmake -G Ninja -DCMAKE_BUILD_TYPE=Release " \
+"-DCMAKE_INSTALL_PREFIX=/analyzer -DLLVM_TARGETS_TO_BUILD=X86 " \
+"-DLLVM_ENABLE_PROJECTS=clang -DLLVM_BUILD_RUNTIME=OFF " \
+"-DLLVM_ENABLE_TERMINFO=OFF -DCLANG_ENABLE_ARCMT=OFF " \
+"-DCLANG_ENABLE_STATIC_ANALYZER=ON"
+
+
+def cmake():
+check_call(CMAKE_COMMAND + ' /llvm-project/llvm', shell=True)
+
+
+def ninja():
+check_call("ninja install", shell=True)
+
+
+def test(args: List[str]):
+os.chdir("/projects")
+check_call("/scripts/SATest.py " + " ".join(args), shell=True)
+
+
+if __name__ == '__main__':
+main()



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


[clang] 14b947f - [analyzer] Fix StdLibraryFunctionsChecker crash on macOS

2020-06-16 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-06-16T16:10:07+03:00
New Revision: 14b947f306ac7bc2e4eb55ac1e4255fd762b217b

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

LOG: [analyzer] Fix StdLibraryFunctionsChecker crash on macOS

Summary:
EOF macro token coming from a PCH file on macOS while marked as literal,
doesn't contain any literal data.  This causes crash on every project
using PCHs.

This commit doesn't resolve the problem with PCH (maybe it was
designed like this for a purpose) or with `tryExpandAsInteger`, but
rather simply shoots off a crash itself.

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

Added: 
clang/test/Analysis/pch_crash.cpp

Modified: 
clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp 
b/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp
index 4b63ebc40ede..cae728815b41 100644
--- a/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp
@@ -128,7 +128,9 @@ llvm::Optional tryExpandAsInteger(StringRef Macro,
 
   // Parse an integer at the end of the macro definition.
   const Token  = FilteredTokens.back();
-  if (!T.isLiteral())
+  // FIXME: EOF macro token coming from a PCH file on macOS while marked as
+  //literal, doesn't contain any literal data
+  if (!T.isLiteral() || !T.getLiteralData())
 return llvm::None;
   StringRef ValueStr = StringRef(T.getLiteralData(), T.getLength());
   llvm::APInt IntValue;

diff  --git a/clang/test/Analysis/pch_crash.cpp 
b/clang/test/Analysis/pch_crash.cpp
new file mode 100644
index ..7ad2cb2d2ab5
--- /dev/null
+++ b/clang/test/Analysis/pch_crash.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.15.0 -emit-pch -o %t %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-macosx10.15.0 -include-pch %t \
+// RUN:   -analyzer-checker=core,apiModeling -verify %s
+//
+// RUN: %clang_cc1 -emit-pch -o %t %s
+// RUN: %clang_analyze_cc1 -include-pch %t \
+// RUN:   -analyzer-checker=core,apiModeling -verify %s
+
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+// Pre-compiled header
+
+int foo();
+
+// Literal data for this macro value will be null
+#define EOF -1
+
+#else
+// Source file
+
+int test() {
+  // we need a function call here to initiate erroneous routine
+  return foo(); // no-crash
+}
+
+#endif



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


[clang] 4a606e0 - [analyzer] CmpRuns.py: Fix error due to statistics differences

2020-06-16 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-06-16T13:30:00+03:00
New Revision: 4a606e0a8c8f196832049c9a6c297589dacedb04

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

LOG: [analyzer] CmpRuns.py: Fix error due to statistics differences

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

Added: 


Modified: 
clang/utils/analyzer/CmpRuns.py

Removed: 




diff  --git a/clang/utils/analyzer/CmpRuns.py b/clang/utils/analyzer/CmpRuns.py
index d94d0bfc83b5..5199a87a8205 100755
--- a/clang/utils/analyzer/CmpRuns.py
+++ b/clang/utils/analyzer/CmpRuns.py
@@ -398,16 +398,18 @@ def compare_stats(results_old: AnalysisRun, results_new: 
AnalysisRun):
 stats_old = derive_stats(results_old)
 stats_new = derive_stats(results_new)
 
-keys = sorted(stats_old.keys())
+old_keys = set(stats_old.keys())
+new_keys = set(stats_new.keys())
+keys = sorted(old_keys & new_keys)
 
-# FIXME: stats_old and stats_new are not necessarily sharing all of their
-#stats and can crash when stats_new doesn't have/removed some
 for key in keys:
 print(key)
 
-for kkey in stats_old[key]:
-val_old = float(stats_old[key][kkey])
-val_new = float(stats_new[key][kkey])
+nested_keys = sorted(set(stats_old[key]) & set(stats_new[key]))
+
+for nested_key in nested_keys:
+val_old = float(stats_old[key][nested_key])
+val_new = float(stats_new[key][nested_key])
 
 report = f"{val_old:.3f} -> {val_new:.3f}"
 
@@ -420,7 +422,17 @@ def compare_stats(results_old: AnalysisRun, results_new: 
AnalysisRun):
 elif ratio > 0.2:
 report = Colors.RED + report + Colors.CLEAR
 
-print(f"\t {kkey} {report}")
+print(f"\t {nested_key} {report}")
+
+removed_keys = old_keys - new_keys
+if removed_keys:
+print(f"REMOVED statistics: {removed_keys}")
+
+added_keys = new_keys - old_keys
+if added_keys:
+print(f"ADDED statistics: {added_keys}")
+
+print()
 
 
 def dump_scan_build_results_
diff (dir_old: str, dir_new: str,



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


[clang] 38b455e - [analyzer] SATest: Add option to specify projects to test

2020-06-16 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-06-16T13:30:01+03:00
New Revision: 38b455e91a63cc20c24b19ab4f469f7c6c60db44

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

LOG: [analyzer] SATest: Add option to specify projects to test

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

Added: 


Modified: 
clang/utils/analyzer/ProjectMap.py
clang/utils/analyzer/SATest.py
clang/utils/analyzer/SATestBuild.py

Removed: 




diff  --git a/clang/utils/analyzer/ProjectMap.py 
b/clang/utils/analyzer/ProjectMap.py
index 62b7e48fde9b..3daa70140562 100644
--- a/clang/utils/analyzer/ProjectMap.py
+++ b/clang/utils/analyzer/ProjectMap.py
@@ -28,6 +28,20 @@ class ProjectInfo(NamedTuple):
 commit: str = ""
 enabled: bool = True
 
+def with_fields(self, **kwargs) -> "ProjectInfo":
+"""
+Create a copy of this project info with customized fields.
+NamedTuple is immutable and this is a way to create modified copies.
+
+  info.enabled = True
+  info.mode = 1
+
+can be done as follows:
+
+  modified = info.with_fields(enbled=True, mode=1)
+"""
+return ProjectInfo(**{**self._asdict(), **kwargs})
+
 
 class ProjectMap:
 """

diff  --git a/clang/utils/analyzer/SATest.py b/clang/utils/analyzer/SATest.py
index 4fb7bf749947..f45f593d08ec 100755
--- a/clang/utils/analyzer/SATest.py
+++ b/clang/utils/analyzer/SATest.py
@@ -28,7 +28,29 @@ def add(parser, args):
 
 def build(parser, args):
 SATestBuild.VERBOSE = args.verbose
-tester = SATestBuild.RegressionTester(args.jobs, args.override_compiler,
+
+project_map = ProjectMap()
+projects = project_map.projects
+
+if args.projects:
+projects_arg = args.projects.split(",")
+available_projects = [project.name
+  for project in projects]
+
+# validate that given projects are present in the project map file
+for manual_project in projects_arg:
+if manual_project not in available_projects:
+parser.error("Project '{project}' is not found in "
+ "the project map file. Available projects are "
+ "{all}.".format(project=manual_project,
+ all=available_projects))
+
+projects = [project.with_fields(enabled=project.name in projects_arg)
+for project in projects]
+
+tester = SATestBuild.RegressionTester(args.jobs,
+  projects,
+  args.override_compiler,
   args.extra_analyzer_config,
   args.regenerate,
   args.strictness)
@@ -111,6 +133,8 @@ def main():
   dest="extra_analyzer_config", type=str,
   default="",
   help="Arguments passed to to -analyzer-config")
+build_parser.add_argument("--projects", action="store", default="",
+  help="Comma-separated list of projects to test")
 build_parser.add_argument("-v", "--verbose", action="count", default=0)
 build_parser.set_defaults(func=build)
 

diff  --git a/clang/utils/analyzer/SATestBuild.py 
b/clang/utils/analyzer/SATestBuild.py
index d5b0710c8d61..d83ff1e7d009 100644
--- a/clang/utils/analyzer/SATestBuild.py
+++ b/clang/utils/analyzer/SATestBuild.py
@@ -44,7 +44,7 @@
 """
 import CmpRuns
 import SATestUtils
-from ProjectMap import DownloadType, ProjectInfo, ProjectMap
+from ProjectMap import DownloadType, ProjectInfo
 
 import glob
 import logging
@@ -225,10 +225,11 @@ class RegressionTester:
 """
 A component aggregating all of the project testing.
 """
-def __init__(self, jobs: int, override_compiler: bool,
- extra_analyzer_config: str, regenerate: bool,
- strictness: bool):
+def __init__(self, jobs: int, projects: List[ProjectInfo],
+ override_compiler: bool, extra_analyzer_config: str,
+ regenerate: bool, strictness: bool):
 self.jobs = jobs
+self.projects = projects
 self.override_compiler = override_compiler
 self.extra_analyzer_config = extra_analyzer_config
 self.regenerate = regenerate
@@ -237,10 +238,8 @@ def __init__(self, jobs: int, override_compiler: bool,
 def test_all(self) -> bool:
 projects_to_test: List[TestInfo] = []
 
-project_map = ProjectMap()
-
 # Test the projects.
-for project in project_map.projects:
+for project in self.projects:
 projects_to_test.append(
 

[clang] 98f737f - [analyzer] CmpRuns.py: Refactor and add type annotations. NFC.

2020-06-16 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-06-16T13:29:46+03:00
New Revision: 98f737f4bfc79acac31d899886ad6b5d44396bde

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

LOG: [analyzer] CmpRuns.py: Refactor and add type annotations. NFC.

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

Added: 


Modified: 
clang/utils/analyzer/CmpRuns.py
clang/utils/analyzer/SATestBuild.py

Removed: 




diff  --git a/clang/utils/analyzer/CmpRuns.py b/clang/utils/analyzer/CmpRuns.py
index 28e9258f593a..d94d0bfc83b5 100755
--- a/clang/utils/analyzer/CmpRuns.py
+++ b/clang/utils/analyzer/CmpRuns.py
@@ -17,26 +17,35 @@
 # Load the results of both runs, to obtain lists of the corresponding
 # AnalysisDiagnostic objects.
 #
-resultsA = loadResultsFromSingleRun(singleRunInfoA, deleteEmpty)
-resultsB = loadResultsFromSingleRun(singleRunInfoB, deleteEmpty)
+resultsA = load_results_from_single_run(singleRunInfoA, delete_empty)
+resultsB = load_results_from_single_run(singleRunInfoB, delete_empty)
 
 # Generate a relation from diagnostics in run A to diagnostics in run B
 # to obtain a list of triples (a, b, confidence).
-
diff  = compareResults(resultsA, resultsB)
+
diff  = compare_results(resultsA, resultsB)
 
 """
-from __future__ import division, print_function
-
-from collections import defaultdict
-
-from math import log
-from optparse import OptionParser
+import argparse
 import json
 import os
 import plistlib
 import re
 import sys
 
+from math import log
+from collections import defaultdict
+from copy import copy
+from typing import (Any, cast, Dict, List, Optional, Sequence, TextIO, TypeVar,
+Tuple, Union)
+
+
+Number = Union[int, float]
+Stats = Dict[str, Dict[str, Number]]
+Plist = Dict[str, Any]
+JSON = Dict[str, Any]
+# Type for generics
+T = TypeVar('T')
+
 STATS_REGEXP = re.compile(r"Statistics: (\{.+\})", re.MULTILINE | re.DOTALL)
 
 
@@ -56,118 +65,127 @@ class SingleRunInfo:
 root - the name of the root directory, which will be disregarded when
 determining the source file name
 """
-def __init__(self, path, root="", verboseLog=None):
+def __init__(self, path: str, root: str = "", verbose_log=None):
 self.path = path
 self.root = root.rstrip("/\\")
-self.verboseLog = verboseLog
+self.verbose_log = verbose_log
 
 
 class AnalysisDiagnostic:
-def __init__(self, data, report, htmlReport):
+def __init__(self, data: Plist, report: "AnalysisReport",
+ html_report: Optional[str]):
 self._data = data
 self._loc = self._data['location']
 self._report = report
-self._htmlReport = htmlReport
-self._reportSize = len(self._data['path'])
+self._html_report = html_report
+self._report_size = len(self._data['path'])
 
-def getFileName(self):
+def get_file_name(self) -> str:
 root = self._report.run.root
-fileName = self._report.files[self._loc['file']]
-if fileName.startswith(root) and len(root) > 0:
-return fileName[len(root) + 1:]
-return fileName
+file_name = self._report.files[self._loc['file']]
+
+if file_name.startswith(root) and len(root) > 0:
+return file_name[len(root) + 1:]
 
-def getRootFileName(self):
+return file_name
+
+def get_root_file_name(self) -> str:
 path = self._data['path']
+
 if not path:
-return self.getFileName()
+return self.get_file_name()
+
 p = path[0]
 if 'location' in p:
-fIdx = p['location']['file']
+file_index = p['location']['file']
 else:  # control edge
-fIdx = path[0]['edges'][0]['start'][0]['file']
-out = self._report.files[fIdx]
+file_index = path[0]['edges'][0]['start'][0]['file']
+
+out = self._report.files[file_index]
 root = self._report.run.root
+
 if out.startswith(root):
 return out[len(root):]
+
 return out
 
-def getLine(self):
+def get_line(self) -> int:
 return self._loc['line']
 
-def getColumn(self):
+def get_column(self) -> int:
 return self._loc['col']
 
-def getPathLength(self):
-return self._reportSize
+def get_path_length(self) -> int:
+return self._report_size
 
-def getCategory(self):
+def get_category(self) -> str:
 return self._data['category']
 
-def getDescription(self):
+def get_description(self) -> str:
 return self._data['description']
 
-def getIssueIdentifier(self):
-id = self.getFileName() + "+"
-if 'issue_context' in self._data:
-id += 

[clang] 35dd014 - [analyzer] CmpRuns.py: Decouple main functionality from argparse

2020-06-16 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-06-16T13:30:01+03:00
New Revision: 35dd0147cdd0b8a145592d895d0a64eedb397917

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

LOG: [analyzer] CmpRuns.py: Decouple main functionality from argparse

Summary:
It makes it much harder to use from other modules when one of the
parameters is an argparse Namespace.  This commit makes it easier
to use CmpRuns programmatically.

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

Added: 


Modified: 
clang/utils/analyzer/CmpRuns.py
clang/utils/analyzer/SATestBuild.py

Removed: 




diff  --git a/clang/utils/analyzer/CmpRuns.py b/clang/utils/analyzer/CmpRuns.py
index 5199a87a8205..d80481da03f1 100755
--- a/clang/utils/analyzer/CmpRuns.py
+++ b/clang/utils/analyzer/CmpRuns.py
@@ -35,8 +35,9 @@
 from math import log
 from collections import defaultdict
 from copy import copy
-from typing import (Any, cast, Dict, List, Optional, Sequence, TextIO, TypeVar,
-Tuple, Union)
+from enum import Enum
+from typing import (Any, cast, Dict, List, NamedTuple, Optional, Sequence,
+TextIO, TypeVar, Tuple, Union)
 
 
 Number = Union[int, float]
@@ -58,6 +59,17 @@ class Colors:
 CLEAR = '\x1b[0m'
 
 
+class HistogramType(str, Enum):
+RELATIVE = "relative"
+LOG_RELATIVE = "log-relative"
+ABSOLUTE = "absolute"
+
+
+class ResultsDirectory(NamedTuple):
+path: str
+root: str = ""
+
+
 class SingleRunInfo:
 """
 Information about analysis run:
@@ -65,9 +77,10 @@ class SingleRunInfo:
 root - the name of the root directory, which will be disregarded when
 determining the source file name
 """
-def __init__(self, path: str, root: str = "", verbose_log=None):
-self.path = path
-self.root = root.rstrip("/\\")
+def __init__(self, results: ResultsDirectory,
+ verbose_log: Optional[str] = None):
+self.path = results.path
+self.root = results.root.rstrip("/\\")
 self.verbose_log = verbose_log
 
 
@@ -232,13 +245,13 @@ def __init__(self, run: AnalysisRun, files: List[str]):
 self.diagnostics: List[AnalysisDiagnostic] = []
 
 
-def load_results(path: str, args: argparse.Namespace, root: str = "",
- delete_empty: bool = True) -> AnalysisRun:
+def load_results(results: ResultsDirectory, delete_empty: bool = True,
+ verbose_log: Optional[str] = None) -> AnalysisRun:
 """
 Backwards compatibility API.
 """
-return load_results_from_single_run(SingleRunInfo(path, root,
-  args.verbose_log),
+return load_results_from_single_run(SingleRunInfo(results,
+  verbose_log),
 delete_empty)
 
 
@@ -280,7 +293,8 @@ def cmp_analysis_diagnostic(d):
 
 
 def compare_results(results_old: AnalysisRun, results_new: AnalysisRun,
-args: argparse.Namespace) -> ComparisonResult:
+histogram: Optional[HistogramType] = None
+) -> ComparisonResult:
 """
 compare_results - Generate a relation from diagnostics in run A to
 diagnostics in run B.
@@ -311,15 +325,15 @@ def compare_results(results_old: AnalysisRun, 
results_new: AnalysisRun,
 if a.get_issue_identifier() == b.get_issue_identifier():
 if a.get_path_length() != b.get_path_length():
 
-if args.relative_path_histogram:
+if histogram == HistogramType.RELATIVE:
 path_
diff erence_data.append(
 float(a.get_path_length()) / b.get_path_length())
 
-elif args.relative_log_path_histogram:
+elif histogram == HistogramType.LOG_RELATIVE:
 path_
diff erence_data.append(
 log(float(a.get_path_length()) / b.get_path_length()))
 
-elif args.absolute_path_histogram:
+elif histogram == HistogramType.ABSOLUTE:
 path_
diff erence_data.append(
 a.get_path_length() - b.get_path_length())
 
@@ -347,8 +361,7 @@ def compare_results(results_old: AnalysisRun, results_new: 
AnalysisRun,
 for b in neq_new:
 res.append((None, b))
 
-if args.relative_log_path_histogram or args.relative_path_histogram or \
-args.absolute_path_histogram:
+if histogram:
 from matplotlib import pyplot
 pyplot.hist(path_
diff erence_data, bins=100)
 pyplot.show()
@@ -394,7 +407,8 @@ def derive_stats(results: AnalysisRun) -> Stats:
 
 # TODO: compare_results decouples comparison from the output, we should
 #   do it here as well
-def 

[clang] 4a7b3d4 - [analyzer] SATestAdd.py: Parse arguments with argparse

2020-06-16 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-06-16T13:30:00+03:00
New Revision: 4a7b3d406f1eca8c9bb8091f92da55ff2c72ab44

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

LOG: [analyzer] SATestAdd.py: Parse arguments with argparse

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

Added: 


Modified: 
clang/utils/analyzer/SATestAdd.py

Removed: 




diff  --git a/clang/utils/analyzer/SATestAdd.py 
b/clang/utils/analyzer/SATestAdd.py
index 83ff3d719ea1..7d68ef261dbf 100755
--- a/clang/utils/analyzer/SATestAdd.py
+++ b/clang/utils/analyzer/SATestAdd.py
@@ -45,18 +45,18 @@
 import SATestBuild
 from ProjectMap import ProjectMap, ProjectInfo
 
+import argparse
 import os
 import sys
 
 
-def add_new_project(name: str, build_mode: int):
+def add_new_project(project: ProjectInfo):
 """
 Add a new project for testing: build it and add to the Project Map file.
 :param name: is a short string used to identify a project.
 """
 
-project_info = ProjectInfo(name, build_mode)
-test_info = SATestBuild.TestInfo(project_info,
+test_info = SATestBuild.TestInfo(project,
  is_reference_build=True)
 tester = SATestBuild.ProjectTester(test_info)
 
@@ -71,37 +71,55 @@ def add_new_project(name: str, build_mode: int):
 # Add the project name to the project map.
 project_map = ProjectMap(should_exist=False)
 
-if is_existing_project(project_map, name):
-print(f"Warning: Project with name '{name}' already exists.",
+if is_existing_project(project_map, project):
+print(f"Warning: Project with name '{project.name}' already exists.",
   file=sys.stdout)
 print("Reference output has been regenerated.", file=sys.stdout)
 else:
-project_map.projects.append(project_info)
+project_map.projects.append(project)
 project_map.save()
 
 
-def is_existing_project(project_map: ProjectMap, project_name: str) -> bool:
-return any(existing_project.name == project_name
+def is_existing_project(project_map: ProjectMap, project: ProjectInfo) -> bool:
+return any(existing_project.name == project.name
for existing_project in project_map.projects)
 
 
-# TODO: Use argparse
 # TODO: Add an option not to build.
 # TODO: Set the path to the Repository directory.
 if __name__ == "__main__":
-if len(sys.argv) < 2 or sys.argv[1] in ("-h", "--help"):
-print("Add a new project for testing to the analyzer"
-  "\nUsage: ", sys.argv[0],
-  "project_ID \n"
-  "mode: 0 for single file project, "
-  "1 for scan_build, "
-  "2 for single file c++11 project", file=sys.stderr)
-sys.exit(-1)
-
-build_mode = 1
-if len(sys.argv) >= 3:
-build_mode = int(sys.argv[2])
-
-assert((build_mode == 0) | (build_mode == 1) | (build_mode == 2))
-
-add_new_project(sys.argv[1], build_mode)
+parser = argparse.ArgumentParser()
+
+parser.add_argument("name", nargs=1, help="Name of the new project")
+parser.add_argument("--mode", action="store", default=1, type=int,
+choices=[0, 1, 2],
+help="Build mode: 0 for single file project, "
+"1 for scan_build, "
+"2 for single file c++11 project")
+parser.add_argument("--source", action="store", default="script",
+choices=["script", "git", "zip"],
+help=f"Source type of the new project: "
+f"'git' for getting from git "
+f"(please provide --origin and --commit), "
+f"'zip' for unpacking source from a zip file, "
+f"'script' for downloading source by running "
+f"a custom script {SATestBuild.DOWNLOAD_SCRIPT}")
+parser.add_argument("--origin", action="store", default="",
+help="Origin link for a git repository")
+parser.add_argument("--commit", action="store", default="",
+help="Git hash for a commit to checkout")
+
+args = parser.parse_args()
+
+if args.source == "git" and (args.origin == "" or args.commit == ""):
+parser.error(
+"Please provide both --origin and --commit if source is 'git'")
+
+if args.source != "git" and (args.origin != "" or args.commit != ""):
+parser.error("Options --origin and --commit don't make sense when "
+ "source is not 'git'")
+
+project = ProjectInfo(args.name[0], args.mode, args.source, args.origin,
+  args.commit)
+
+add_new_project(project)



___

[clang] bbb8f17 - [analyzer] SATest: Add posibility to download source from git and zip

2020-06-16 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-06-16T13:30:00+03:00
New Revision: bbb8f171364b78c6290fcdbf48b214a870dd1caf

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

LOG: [analyzer] SATest: Add posibility to download source from git and zip

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

Added: 


Modified: 
clang/utils/analyzer/ProjectMap.py
clang/utils/analyzer/SATestBuild.py

Removed: 




diff  --git a/clang/utils/analyzer/ProjectMap.py 
b/clang/utils/analyzer/ProjectMap.py
index 182a05c1a935..5b15e405d26c 100644
--- a/clang/utils/analyzer/ProjectMap.py
+++ b/clang/utils/analyzer/ProjectMap.py
@@ -1,7 +1,8 @@
 import json
 import os
 
-from typing import Any, Dict, List, NamedTuple, Optional
+from enum import Enum
+from typing import Any, Dict, List, NamedTuple, Optional, Tuple
 
 
 JSON = Dict[str, Any]
@@ -10,12 +11,21 @@
 DEFAULT_MAP_FILE = "projects.json"
 
 
+class DownloadType(str, Enum):
+GIT = "git"
+ZIP = "zip"
+SCRIPT = "script"
+
+
 class ProjectInfo(NamedTuple):
 """
 Information about a project to analyze.
 """
 name: str
 mode: int
+source: DownloadType = DownloadType.SCRIPT
+origin: str = ""
+commit: str = ""
 enabled: bool = True
 
 
@@ -73,12 +83,29 @@ def _parse_project(raw_project: JSON) -> ProjectInfo:
 name: str = raw_project["name"]
 build_mode: int = raw_project["mode"]
 enabled: bool = raw_project.get("enabled", True)
-return ProjectInfo(name, build_mode, enabled)
+source: DownloadType = raw_project.get("source", "zip")
+
+if source == DownloadType.GIT:
+origin, commit = ProjectMap._get_git_params(raw_project)
+else:
+origin, commit = "", ""
+
+return ProjectInfo(name, build_mode, source, origin, commit,
+   enabled)
 
 except KeyError as e:
 raise ValueError(
 f"Project info is required to have a '{e.args[0]}' field")
 
+@staticmethod
+def _get_git_params(raw_project: JSON) -> Tuple[str, str]:
+try:
+return raw_project["origin"], raw_project["commit"]
+except KeyError as e:
+raise ValueError(
+f"Profect info is required to have a '{e.args[0]}' field "
+f"if it has a 'git' source")
+
 @staticmethod
 def _create_empty(path: str):
 ProjectMap._save([], path)

diff  --git a/clang/utils/analyzer/SATestBuild.py 
b/clang/utils/analyzer/SATestBuild.py
index 8b0b80318471..41cb5db44762 100755
--- a/clang/utils/analyzer/SATestBuild.py
+++ b/clang/utils/analyzer/SATestBuild.py
@@ -44,7 +44,7 @@
 """
 import CmpRuns
 import SATestUtils
-from ProjectMap import ProjectInfo, ProjectMap
+from ProjectMap import DownloadType, ProjectInfo, ProjectMap
 
 import argparse
 import glob
@@ -57,6 +57,7 @@
 import sys
 import threading
 import time
+import zipfile
 
 from queue import Queue
 # mypy has problems finding InvalidFileException in the module
@@ -198,63 +199,6 @@ def run_cleanup_script(directory: str, build_log_file: IO):
verbose=VERBOSE)
 
 
-def download_and_patch(directory: str, build_log_file: IO):
-"""
-Download the project and apply the local patchfile if it exists.
-"""
-cached_source = os.path.join(directory, CACHED_SOURCE_DIR_NAME)
-
-# If the we don't already have the cached source, run the project's
-# download script to download it.
-if not os.path.exists(cached_source):
-download(directory, build_log_file)
-if not os.path.exists(cached_source):
-stderr(f"Error: '{cached_source}' not found after download.\n")
-exit(1)
-
-patched_source = os.path.join(directory, PATCHED_SOURCE_DIR_NAME)
-
-# Remove potentially stale patched source.
-if os.path.exists(patched_source):
-shutil.rmtree(patched_source)
-
-# Copy the cached source and apply any patches to the copy.
-shutil.copytree(cached_source, patched_source, symlinks=True)
-apply_patch(directory, build_log_file)
-
-
-def download(directory: str, build_log_file: IO):
-"""
-Run the script to download the project, if it exists.
-"""
-script_path = os.path.join(directory, DOWNLOAD_SCRIPT)
-SATestUtils.run_script(script_path, build_log_file, directory,
-   out=LOCAL.stdout, err=LOCAL.stderr,
-   verbose=VERBOSE)
-
-
-def apply_patch(directory: str, build_log_file: IO):
-patchfile_path = os.path.join(directory, PATCHFILE_NAME)
-patched_source = os.path.join(directory, PATCHED_SOURCE_DIR_NAME)
-
-if not os.path.exists(patchfile_path):
-stdout("  No local 

[clang] d9944da - [analyzer] SATest: Introduce a single entrypoint for regression scripts

2020-06-16 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-06-16T13:30:01+03:00
New Revision: d9944da273c42846947b028c02b7a59880ca50ed

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

LOG: [analyzer] SATest: Introduce a single entrypoint for regression scripts

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

Added: 
clang/utils/analyzer/SATest.py

Modified: 
clang/utils/analyzer/CmpRuns.py
clang/utils/analyzer/SATestAdd.py
clang/utils/analyzer/SATestBuild.py
clang/utils/analyzer/SATestUpdateDiffs.py

Removed: 




diff  --git a/clang/utils/analyzer/CmpRuns.py b/clang/utils/analyzer/CmpRuns.py
old mode 100755
new mode 100644
index d80481da03f1..f7f28d9dc72e
--- a/clang/utils/analyzer/CmpRuns.py
+++ b/clang/utils/analyzer/CmpRuns.py
@@ -25,7 +25,6 @@
 
diff  = compare_results(resultsA, resultsB)
 
 """
-import argparse
 import json
 import os
 import plistlib
@@ -524,51 +523,7 @@ def dump_scan_build_results_
diff (dir_old: ResultsDirectory,
 len(results_new.diagnostics)
 
 
-def generate_option_parser():
-parser = argparse.ArgumentParser()
-
-parser.add_argument("--root-old", dest="root_old",
-help="Prefix to ignore on source files for "
-"OLD directory",
-action="store", type=str, default="")
-parser.add_argument("--root-new", dest="root_new",
-help="Prefix to ignore on source files for "
-"NEW directory",
-action="store", type=str, default="")
-parser.add_argument("--verbose-log", dest="verbose_log",
-help="Write additional information to LOG "
-"[default=None]",
-action="store", type=str, default=None,
-metavar="LOG")
-parser.add_argument("--stats-only", action="store_true", dest="stats_only",
-default=False, help="Only show statistics on reports")
-parser.add_argument("--show-stats", action="store_true", dest="show_stats",
-default=False, help="Show change in statistics")
-parser.add_argument("--histogram", action="store", default=None,
-choices=[HistogramType.RELATIVE.value,
- HistogramType.LOG_RELATIVE.value,
- HistogramType.ABSOLUTE.value],
-help="Show histogram of paths 
diff erences. "
-"Requires matplotlib")
-parser.add_argument("old", nargs=1, help="Directory with old results")
-parser.add_argument("new", nargs=1, help="Directory with new results")
-
-return parser
-
-
-def main():
-parser = generate_option_parser()
-args = parser.parse_args()
-
-dir_old = ResultsDirectory(args.old[0], args.root_old)
-dir_new = ResultsDirectory(args.new[0], args.root_new)
-
-dump_scan_build_results_
diff (dir_old, dir_new,
- show_stats=args.show_stats,
- stats_only=args.stats_only,
- histogram=args.histogram,
- verbose_log=args.verbose_log)
-
-
-if __name__ == '__main__':
-main()
+if __name__ == "__main__":
+print("CmpRuns.py should not be used on its own.")
+print("Please use 'SATest.py compare' instead")
+sys.exit(1)

diff  --git a/clang/utils/analyzer/SATest.py b/clang/utils/analyzer/SATest.py
new file mode 100755
index ..4fb7bf749947
--- /dev/null
+++ b/clang/utils/analyzer/SATest.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+
+import SATestAdd
+import SATestBuild
+import SATestUpdateDiffs
+import CmpRuns
+
+from ProjectMap import ProjectInfo, ProjectMap
+
+import argparse
+import sys
+
+
+def add(parser, args):
+if args.source == "git" and (args.origin == "" or args.commit == ""):
+parser.error(
+"Please provide both --origin and --commit if source is 'git'")
+
+if args.source != "git" and (args.origin != "" or args.commit != ""):
+parser.error("Options --origin and --commit don't make sense when "
+ "source is not 'git'")
+
+project = ProjectInfo(args.name[0], args.mode, args.source, args.origin,
+  args.commit)
+
+SATestAdd.add_new_project(project)
+
+
+def build(parser, args):
+SATestBuild.VERBOSE = args.verbose
+tester = SATestBuild.RegressionTester(args.jobs, args.override_compiler,
+  args.extra_analyzer_config,
+  args.regenerate,
+  args.strictness)
+tests_passed = tester.test_all()
+
+if not tests_passed:
+

[clang] fb4b565 - [analyzer] SATest: Move from csv to json project maps

2020-06-16 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-06-16T13:30:00+03:00
New Revision: fb4b565212b0158e2b41ffec71a7c4282907cda9

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

LOG: [analyzer] SATest: Move from csv to json project maps

Summary:
JSON format is a bit more verbose and easier to reason about
and extend.  For this reason, before extending SATestBuild
functionality it is better to refactor the part of how we
configure the whole system.

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

Added: 
clang/utils/analyzer/ProjectMap.py

Modified: 
clang/utils/analyzer/SATestAdd.py
clang/utils/analyzer/SATestBuild.py
clang/utils/analyzer/SATestUpdateDiffs.py

Removed: 




diff  --git a/clang/utils/analyzer/ProjectMap.py 
b/clang/utils/analyzer/ProjectMap.py
new file mode 100644
index ..182a05c1a935
--- /dev/null
+++ b/clang/utils/analyzer/ProjectMap.py
@@ -0,0 +1,94 @@
+import json
+import os
+
+from typing import Any, Dict, List, NamedTuple, Optional
+
+
+JSON = Dict[str, Any]
+
+
+DEFAULT_MAP_FILE = "projects.json"
+
+
+class ProjectInfo(NamedTuple):
+"""
+Information about a project to analyze.
+"""
+name: str
+mode: int
+enabled: bool = True
+
+
+class ProjectMap:
+"""
+Project map stores info about all the "registered" projects.
+"""
+def __init__(self, path: Optional[str] = None, should_exist: bool = True):
+"""
+:param path: optional path to a project JSON file, when None defaults
+ to DEFAULT_MAP_FILE.
+:param should_exist: flag to tell if it's an exceptional situation when
+ the project file doesn't exist, creates an empty
+ project list instead if we are not expecting it to
+ exist.
+"""
+if path is None:
+path = os.path.join(os.path.abspath(os.curdir), DEFAULT_MAP_FILE)
+
+if not os.path.exists(path):
+if should_exist:
+raise ValueError(
+f"Cannot find the project map file {path}"
+f"\nRunning script for the wrong directory?\n")
+else:
+self._create_empty(path)
+
+self.path = path
+self._load_projects()
+
+def save(self):
+"""
+Save project map back to its original file.
+"""
+self._save(self.projects, self.path)
+
+def _load_projects(self):
+with open(self.path) as raw_data:
+raw_projects = json.load(raw_data)
+
+if not isinstance(raw_projects, list):
+raise ValueError(
+"Project map should be a list of JSON objects")
+
+self.projects = self._parse(raw_projects)
+
+@staticmethod
+def _parse(raw_projects: List[JSON]) -> List[ProjectInfo]:
+return [ProjectMap._parse_project(raw_project)
+for raw_project in raw_projects]
+
+@staticmethod
+def _parse_project(raw_project: JSON) -> ProjectInfo:
+try:
+name: str = raw_project["name"]
+build_mode: int = raw_project["mode"]
+enabled: bool = raw_project.get("enabled", True)
+return ProjectInfo(name, build_mode, enabled)
+
+except KeyError as e:
+raise ValueError(
+f"Project info is required to have a '{e.args[0]}' field")
+
+@staticmethod
+def _create_empty(path: str):
+ProjectMap._save([], path)
+
+@staticmethod
+def _save(projects: List[ProjectInfo], path: str):
+with open(path, "w") as output:
+json.dump(ProjectMap._convert_infos_to_dicts(projects),
+  output, indent=2)
+
+@staticmethod
+def _convert_infos_to_dicts(projects: List[ProjectInfo]) -> List[JSON]:
+return [project._asdict() for project in projects]

diff  --git a/clang/utils/analyzer/SATestAdd.py 
b/clang/utils/analyzer/SATestAdd.py
index 012d8ec3fd9a..83ff3d719ea1 100755
--- a/clang/utils/analyzer/SATestAdd.py
+++ b/clang/utils/analyzer/SATestAdd.py
@@ -43,13 +43,11 @@
   > changes_for_analyzer.patch
 """
 import SATestBuild
+from ProjectMap import ProjectMap, ProjectInfo
 
-import csv
 import os
 import sys
 
-from typing import IO
-
 
 def add_new_project(name: str, build_mode: int):
 """
@@ -57,9 +55,10 @@ def add_new_project(name: str, build_mode: int):
 :param name: is a short string used to identify a project.
 """
 
-project_info = SATestBuild.ProjectInfo(name, build_mode,
-   is_reference_build=True)
-tester = SATestBuild.ProjectTester(project_info)
+project_info = ProjectInfo(name, build_mode)

[clang] dc8a77d - [analyzer] ProjectMap: Do not serialize fields with default values

2020-06-16 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-06-16T13:30:01+03:00
New Revision: dc8a77de7db71dc52b0c75b3bb5437d9ae0ccc8c

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

LOG: [analyzer] ProjectMap: Do not serialize fields with default values

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

Added: 


Modified: 
clang/utils/analyzer/ProjectMap.py

Removed: 




diff  --git a/clang/utils/analyzer/ProjectMap.py 
b/clang/utils/analyzer/ProjectMap.py
index 5b15e405d26c..62b7e48fde9b 100644
--- a/clang/utils/analyzer/ProjectMap.py
+++ b/clang/utils/analyzer/ProjectMap.py
@@ -118,4 +118,17 @@ def _save(projects: List[ProjectInfo], path: str):
 
 @staticmethod
 def _convert_infos_to_dicts(projects: List[ProjectInfo]) -> List[JSON]:
-return [project._asdict() for project in projects]
+return [ProjectMap._convert_info_to_dict(project)
+for project in projects]
+
+@staticmethod
+def _convert_info_to_dict(project: ProjectInfo) -> JSON:
+whole_dict = project._asdict()
+defaults = project._field_defaults
+
+# there is no need in serializing fields with default values
+for field, default_value in defaults.items():
+if whole_dict[field] == default_value:
+del whole_dict[field]
+
+return whole_dict



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


[clang] 29353e6 - [analyzer] LoopWidening: fix crash by avoiding aliased references invalidation

2020-06-09 Thread Valeriy Savchenko via cfe-commits

Author: Abbas Sabra
Date: 2020-06-09T12:55:54+03:00
New Revision: 29353e69d25c0f13cd2704ce2269af464d0751a8

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

LOG: [analyzer] LoopWidening: fix crash by avoiding aliased references 
invalidation

Summary: LoopWidening is invalidating references coming from type
aliases which lead to a crash.

Patch by Abbas Sabra!

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

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
clang/test/Analysis/loop-widening-preserve-reference-type.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp 
b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
index 9a7b1a24b819..47e34dd84b9a 100644
--- a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
+++ b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
@@ -67,8 +67,10 @@ ProgramStateRef getWidenedLoopState(ProgramStateRef 
PrevState,
   }
 
   // References should not be invalidated.
-  auto Matches = 
match(findAll(stmt(hasDescendant(varDecl(hasType(referenceType())).bind(MatchRef,
-   *LCtx->getDecl()->getBody(), ASTCtx);
+  auto Matches = match(
+  findAll(stmt(hasDescendant(
+  
varDecl(hasType(hasCanonicalType(referenceType(.bind(MatchRef,
+  *LCtx->getDecl()->getBody(), ASTCtx);
   for (BoundNodes Match : Matches) {
 const VarDecl *VD = Match.getNodeAs(MatchRef);
 assert(VD);

diff  --git a/clang/test/Analysis/loop-widening-preserve-reference-type.cpp 
b/clang/test/Analysis/loop-widening-preserve-reference-type.cpp
index b5746d1fe767..38dcb4fbb6ac 100644
--- a/clang/test/Analysis/loop-widening-preserve-reference-type.cpp
+++ b/clang/test/Analysis/loop-widening-preserve-reference-type.cpp
@@ -12,3 +12,11 @@ void invalid_type_region_access() {
   for (int i = 0; i < 10; ++i) { }
   clang_analyzer_eval( != 0); // expected-warning{{TRUE}}
 }   // expected-warning@-1{{reference cannot be 
bound to dereferenced null pointer in well-defined C++ code; comparison may be 
assumed to always evaluate to true}}
+
+using AR = const A &;
+void invalid_type_alias_region_access() {
+  AR x = B();
+  for (int i = 0; i < 10; ++i) {
+  }
+  clang_analyzer_eval( != 0); // expected-warning{{TRUE}}
+} // expected-warning@-1{{reference cannot be bound to dereferenced null 
pointer in well-defined C++ code; comparison may be assumed to always evaluate 
to true}}



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


[clang] 5395389 - [analyzer] SATestBuild.py: Make verbosity level a cmd option

2020-05-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-05-28T20:47:06+03:00
New Revision: 5395389475bcaba16966ab62125f2f54ea81c915

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

LOG: [analyzer] SATestBuild.py: Make verbosity level a cmd option

Reviewers: NoQ, dcoughlin

Subscribers: xazax.hun, baloghadamsoftware, szepet, a.sidorin, mikhail.ramalho, 
Szelethus, donat.nagy, dkrupp, Charusso, ASDenysPetrov, cfe-commits

Tags: #clang

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

Added: 


Modified: 
clang/utils/analyzer/SATestBuild.py

Removed: 




diff  --git a/clang/utils/analyzer/SATestBuild.py 
b/clang/utils/analyzer/SATestBuild.py
index e2fe6a95138b..5ff430d5fcf3 100755
--- a/clang/utils/analyzer/SATestBuild.py
+++ b/clang/utils/analyzer/SATestBuild.py
@@ -389,7 +389,7 @@ def test(self) -> bool:
 start_time = time.time()
 
 project_dir = self.get_project_dir()
-if VERBOSE == 1:
+if VERBOSE >= 1:
 stdout(f"  Build directory: {project_dir}.\n")
 
 # Set the build results directory.
@@ -431,7 +431,7 @@ def build(self, directory: str, output_dir: str):
 
 # Clean up scan build results.
 if os.path.exists(output_dir):
-if VERBOSE == 1:
+if VERBOSE >= 1:
 stdout(f"  Removing old results: {output_dir}\n")
 
 shutil.rmtree(output_dir)
@@ -517,7 +517,7 @@ def scan_build(self, directory: str, output_dir: str, 
build_log_file: IO):
 
 command_to_run = command_prefix + command
 
-if VERBOSE == 1:
+if VERBOSE >= 1:
 stdout(f"  Executing: {command_to_run}\n")
 
 check_call(command_to_run, cwd=cwd,
@@ -575,7 +575,7 @@ def analyze_preprocessed(self, directory: str, output_dir: 
str):
 log_path = os.path.join(fail_path, file_name + ".stderr.txt")
 with open(log_path, "w+") as log_file:
 try:
-if VERBOSE == 1:
+if VERBOSE >= 1:
 stdout(f"  Executing: {command}\n")
 
 check_call(command, cwd=directory, stderr=log_file,
@@ -744,7 +744,7 @@ def run_cmp_results(directory: str, strictness: int = 0) -> 
bool:
 for ref_dir, new_dir in zip(ref_list, new_list):
 assert(ref_dir != new_dir)
 
-if VERBOSE == 1:
+if VERBOSE >= 1:
 stdout(f"  Comparing Results: {ref_dir} {new_dir}\n")
 
 patched_source = os.path.join(directory, PATCHED_SOURCE_DIR_NAME)
@@ -818,7 +818,7 @@ def remove_log_file(output_dir: str):
 
 # Clean up the log file.
 if os.path.exists(build_log_path):
-if VERBOSE == 1:
+if VERBOSE >= 1:
 stdout(f"  Removing log file: {build_log_path}\n")
 
 os.remove(build_log_path)
@@ -887,29 +887,31 @@ def validate_project_file(map_file: IO):
 
 if __name__ == "__main__":
 # Parse command line arguments.
-Parser = argparse.ArgumentParser(
+parser = argparse.ArgumentParser(
 description="Test the Clang Static Analyzer.")
 
-Parser.add_argument("--strictness", dest="strictness", type=int, default=0,
+parser.add_argument("--strictness", dest="strictness", type=int, default=0,
 help="0 to fail on runtime errors, 1 to fail when the "
 "number of found bugs are 
diff erent from the "
 "reference, 2 to fail on any 
diff erence from the "
 "reference. Default is 0.")
-Parser.add_argument("-r", dest="regenerate", action="store_true",
+parser.add_argument("-r", dest="regenerate", action="store_true",
 default=False, help="Regenerate reference output.")
-Parser.add_argument("--override-compiler", action="store_true",
+parser.add_argument("--override-compiler", action="store_true",
 default=False, help="Call scan-build with "
 "--override-compiler option.")
-Parser.add_argument("-j", "--jobs", dest="jobs", type=int,
+parser.add_argument("-j", "--jobs", dest="jobs", type=int,
 default=0,
 help="Number of projects to test concurrently")
-Parser.add_argument("--extra-analyzer-config",
+parser.add_argument("--extra-analyzer-config",
 dest="extra_analyzer_config", type=str,
 default="",
 help="Arguments passed to to -analyzer-config")
+parser.add_argument("-v", "--verbose", action="count", default=0)
 
-args = Parser.parse_args()
+args = parser.parse_args()
 
+VERBOSE = args.verbose
 tester = RegressionTester(args.jobs, args.override_compiler,

[clang] 116dcbe - [analyzer] Remove unused function declaration. NFC.

2020-05-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-05-28T20:28:17+03:00
New Revision: 116dcbebc6a1648b4acd1a1a391c1d66a3eb4b5f

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

LOG: [analyzer] Remove unused function declaration. NFC.

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 0822a9461fa7..a14b29c6face 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -801,7 +801,6 @@ class RangeConstraintManager : public 
RangedConstraintManager {
   RangeSet::Factory F;
 
   RangeSet getRange(ProgramStateRef State, SymbolRef Sym);
-  const RangeSet *getRangeForMinusSymbol(ProgramStateRef State, SymbolRef Sym);
 
   RangeSet getSymLTRange(ProgramStateRef St, SymbolRef Sym,
  const llvm::APSInt ,



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


[clang] db3b970 - [analyzer] Remove unused function. NFC.

2020-05-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-05-28T20:22:50+03:00
New Revision: db3b970a84325e326bbcec4bc3e5e663f148a481

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

LOG: [analyzer] Remove unused function. NFC.

Added: 


Modified: 
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 6f92b965ce5b..0822a9461fa7 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -929,30 +929,6 @@ RangeSet RangeConstraintManager::getRange(ProgramStateRef 
State,
   return SymbolicRangeInferrer::inferRange(getBasicVals(), F, State, Sym);
 }
 
-// FIXME: Once SValBuilder supports unary minus, we should use SValBuilder to
-//obtain the negated symbolic expression instead of constructing the
-//symbol manually. This will allow us to support finding ranges of not
-//only negated SymSymExpr-type expressions, but also of other, simpler
-//expressions which we currently do not know how to negate.
-const RangeSet*
-RangeConstraintManager::getRangeForMinusSymbol(ProgramStateRef State,
-   SymbolRef Sym) {
-  if (const SymSymExpr *SSE = dyn_cast(Sym)) {
-if (SSE->getOpcode() == BO_Sub) {
-  QualType T = Sym->getType();
-  SymbolManager  = State->getSymbolManager();
-  SymbolRef negSym = SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub,
-  SSE->getLHS(), T);
-  if (const RangeSet *negV = State->get(negSym)) {
-if (T->isUnsignedIntegerOrEnumerationType() ||
-T->isSignedIntegerOrEnumerationType())
-  return negV;
-  }
-}
-  }
-  return nullptr;
-}
-
 
//======
 // assumeSymX methods: protected interface for RangeConstraintManager.
 
//======/



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


[clang] 2a09daf - [analyzer] Generalize bitwise AND rules for ranges

2020-05-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-05-28T18:55:49+03:00
New Revision: 2a09daff0f902e70a08f2b30f3461fb8848f5ab1

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

LOG: [analyzer] Generalize bitwise AND rules for ranges

Summary:
Previously the current solver started reasoning about bitwise AND
expressions only when one of the operands is a constant.  However,
very similar logic could be applied to ranges.  This commit addresses
this shortcoming.  Additionally, it refines how we deal with negative
operands.

rdar://problem/54359410

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

Added: 
clang/test/Analysis/uninit-exhaustive-switch-bug.c

Modified: 
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/test/Analysis/constant-folding.c
clang/test/Analysis/switch-case.c

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 570161543805..b73c395d80fa 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -430,9 +430,9 @@ class SymbolicRangeInferrer
RangeSet RHS, QualType T) {
 switch (Op) {
 case BO_Or:
-  return VisitOrOperator(LHS, RHS, T);
+  return VisitBinaryOperator(LHS, RHS, T);
 case BO_And:
-  return VisitAndOperator(LHS, RHS, T);
+  return VisitBinaryOperator(LHS, RHS, T);
 default:
   return infer(T);
 }
@@ -464,19 +464,19 @@ class SymbolicRangeInferrer
  ValueFactory.Convert(To, Origin.To()));
   }
 
-  RangeSet VisitOrOperator(RangeSet LHS, RangeSet RHS, QualType T) {
+  template 
+  RangeSet VisitBinaryOperator(RangeSet LHS, RangeSet RHS, QualType T) {
 // We should propagate information about unfeasbility of one of the
 // operands to the resulting range.
 if (LHS.isEmpty() || RHS.isEmpty()) {
   return RangeFactory.getEmptySet();
 }
 
-APSIntType ResultType = ValueFactory.getAPSIntType(T);
-RangeSet DefaultRange = infer(T);
-
 Range CoarseLHS = fillGaps(LHS);
 Range CoarseRHS = fillGaps(RHS);
 
+APSIntType ResultType = ValueFactory.getAPSIntType(T);
+
 // We need to convert ranges to the resulting type, so we can compare 
values
 // and combine them in a meaningful (in terms of the given operation) way.
 auto ConvertedCoarseLHS = convert(CoarseLHS, ResultType);
@@ -485,74 +485,14 @@ class SymbolicRangeInferrer
 // It is hard to reason about ranges when conversion changes
 // borders of the ranges.
 if (!ConvertedCoarseLHS || !ConvertedCoarseRHS) {
-  return DefaultRange;
-}
-
-llvm::APSInt Zero = ResultType.getZeroValue();
-
-bool IsLHSPositiveOrZero = ConvertedCoarseLHS->From() >= Zero;
-bool IsRHSPositiveOrZero = ConvertedCoarseRHS->From() >= Zero;
-
-bool IsLHSNegative = ConvertedCoarseLHS->To() < Zero;
-bool IsRHSNegative = ConvertedCoarseRHS->To() < Zero;
-
-// Check if both ranges have the same sign.
-if ((IsLHSPositiveOrZero && IsRHSPositiveOrZero) ||
-(IsLHSNegative && IsRHSNegative)) {
-  // The result is definitely greater or equal than any of the operands.
-  const llvm::APSInt  =
-  std::max(ConvertedCoarseLHS->From(), ConvertedCoarseRHS->From());
-
-  // We estimate maximal value for positives as the maximal value for the
-  // given type.  For negatives, we estimate it with -1 (e.g. 0x).
-  //
-  // TODO: We basically, limit the resulting range from below (in absolute
-  //   numbers), but don't do anything with the upper bound.
-  //   For positive operands, it can be done as follows: for the upper
-  //   bound of LHS and RHS we calculate the most significant bit set.
-  //   Let's call it the N-th bit.  Then we can estimate the maximal
-  //   number to be 2^(N+1)-1, i.e. the number with all the bits up to
-  //   the N-th bit set.
-  const llvm::APSInt  = IsLHSNegative
-? ValueFactory.getValue(--Zero)
-: ValueFactory.getMaxValue(ResultType);
-
-  return {RangeFactory, ValueFactory.getValue(Min), Max};
-}
-
-// Otherwise, let's check if at least one of the operands is negative.
-if (IsLHSNegative || IsRHSNegative) {
-  // This means that the result is definitely negative as well.
-  return {RangeFactory, ValueFactory.getMinValue(ResultType),
-  ValueFactory.getValue(--Zero)};
-}
-
-// It is pretty hard to reason about operands with 
diff erent signs
-// (and especially with possibly 
diff erent signs).  We simply check if it
-// can be zero.  

[clang] 73c120a - [analyzer] Introduce reasoning about symbolic remainder operator

2020-05-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-05-28T18:56:38+03:00
New Revision: 73c120a9895a7e12e3c29a755d64096c8bd0220f

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

LOG: [analyzer] Introduce reasoning about symbolic remainder operator

Summary:
New logic tries to narrow possible result values of the remainder operation
based on its operands and their ranges.  It also tries to be conservative
with negative operands because according to the standard the sign of
the result is implementation-defined.

rdar://problem/44978988

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

Added: 
clang/test/Analysis/PR35418.cpp
clang/test/Analysis/uninit-bug-first-iteration-init.c

Modified: 
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
clang/test/Analysis/constant-folding.c
clang/test/Analysis/hangs.c

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index b73c395d80fa..6f92b965ce5b 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -433,6 +433,8 @@ class SymbolicRangeInferrer
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_And:
   return VisitBinaryOperator(LHS, RHS, T);
+case BO_Rem:
+  return VisitBinaryOperator(LHS, RHS, T);
 default:
   return infer(T);
 }
@@ -496,6 +498,46 @@ class SymbolicRangeInferrer
 return infer(T);
   }
 
+  /// Return a symmetrical range for the given range and type.
+  ///
+  /// If T is signed, return the smallest range [-x..x] that covers the 
original
+  /// range, or [-min(T), max(T)] if the aforementioned symmetric range doesn't
+  /// exist due to original range covering min(T)).
+  ///
+  /// If T is unsigned, return the smallest range [0..x] that covers the
+  /// original range.
+  Range getSymmetricalRange(Range Origin, QualType T) {
+APSIntType RangeType = ValueFactory.getAPSIntType(T);
+
+if (RangeType.isUnsigned()) {
+  return Range(ValueFactory.getMinValue(RangeType), Origin.To());
+}
+
+if (Origin.From().isMinSignedValue()) {
+  // If mini is a minimal signed value, absolute value of it is greater
+  // than the maximal signed value.  In order to avoid these
+  // complications, we simply return the whole range.
+  return {ValueFactory.getMinValue(RangeType),
+  ValueFactory.getMaxValue(RangeType)};
+}
+
+// At this point, we are sure that the type is signed and we can safely
+// use unary - operator.
+//
+// While calculating absolute maximum, we can use the following formula
+// because of these reasons:
+//   * If From >= 0 then To >= From and To >= -From.
+// AbsMax == To == max(To, -From)
+//   * If To <= 0 then -From >= -To and -From >= From.
+// AbsMax == -From == max(-From, To)
+//   * Otherwise, From <= 0, To >= 0, and
+// AbsMax == max(abs(From), abs(To))
+llvm::APSInt AbsMax = std::max(-Origin.From(), Origin.To());
+
+// Intersection is guaranteed to be non-empty.
+return {ValueFactory.getValue(-AbsMax), ValueFactory.getValue(AbsMax)};
+  }
+
   /// Return a range set subtracting zero from \p Domain.
   RangeSet assumeNonZero(RangeSet Domain, QualType T) {
 APSIntType IntType = ValueFactory.getAPSIntType(T);
@@ -635,6 +677,63 @@ RangeSet 
SymbolicRangeInferrer::VisitBinaryOperator(Range LHS,
   return infer(T);
 }
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS,
+Range RHS,
+QualType T) {
+  llvm::APSInt Zero = ValueFactory.getAPSIntType(T).getZeroValue();
+
+  Range ConservativeRange = getSymmetricalRange(RHS, T);
+
+  llvm::APSInt Max = ConservativeRange.To();
+  llvm::APSInt Min = ConservativeRange.From();
+
+  if (Max == Zero) {
+// It's an undefined behaviour to divide by 0 and it seems like we know
+// for sure that RHS is 0.  Let's say that the resulting range is
+// simply infeasible for that matter.
+return RangeFactory.getEmptySet();
+  }
+
+  // At this point, our conservative range is closed.  The result, however,
+  // couldn't be greater than the RHS' maximal absolute value.  Because of
+  // this reason, we turn the range into open (or half-open in case of
+  // unsigned integers).
+  //
+  // While we operate on integer values, an open interval (a, b) can be easily
+  // represented by the closed interval [a + 1, b - 1].  And this is exactly
+  // what we do next.
+  //
+  // If we are dealing with unsigned case, we shouldn't move the 

[clang] 47c4b8b - [analyzer] Generalize bitwise OR rules for ranges

2020-05-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-05-28T18:55:22+03:00
New Revision: 47c4b8bd68698b1827f39c3056783ed042faf718

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

LOG: [analyzer] Generalize bitwise OR rules for ranges

Summary:
Previously the current solver started reasoning about bitwise OR
expressions only when one of the operands is a constant.  However,
very similar logic could be applied to ranges.  This commit addresses
this shortcoming.  Additionally, it refines how we deal with negative
operands.

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

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h

clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/test/Analysis/constant-folding.c

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index ac218bc070e9..a001c0dc7030 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -157,6 +157,10 @@ class BasicValueFactory {
 
   const llvm::APSInt (QualType T, const llvm::APSInt ) {
 APSIntType TargetType = getAPSIntType(T);
+return Convert(TargetType, From);
+  }
+
+  const llvm::APSInt (APSIntType TargetType, const llvm::APSInt ) 
{
 if (TargetType == APSIntType(From))
   return From;
 
@@ -177,11 +181,19 @@ class BasicValueFactory {
   }
 
   const llvm::APSInt (QualType T) {
-return getValue(getAPSIntType(T).getMaxValue());
+return getMaxValue(getAPSIntType(T));
   }
 
   const llvm::APSInt (QualType T) {
-return getValue(getAPSIntType(T).getMinValue());
+return getMinValue(getAPSIntType(T));
+  }
+
+  const llvm::APSInt (APSIntType T) {
+return getValue(T.getMaxValue());
+  }
+
+  const llvm::APSInt (APSIntType T) {
+return getValue(T.getMinValue());
   }
 
   const llvm::APSInt (const llvm::APSInt ) {

diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
index 97c9c6d63eb2..a42eebd7d4e8 100644
--- 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
+++ 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -107,14 +107,17 @@ class RangeSet {
 return ranges.isSingleton() ? ranges.begin()->getConcreteValue() : nullptr;
   }
 
+  /// Get a minimal value covered by the ranges in the set
+  const llvm::APSInt () const;
+  /// Get a maximal value covered by the ranges in the set
+  const llvm::APSInt () const;
+
 private:
   void IntersectInRange(BasicValueFactory , Factory ,
 const llvm::APSInt , const llvm::APSInt ,
 PrimRangeSet , PrimRangeSet::iterator ,
 PrimRangeSet::iterator ) const;
 
-  const llvm::APSInt () const;
-
   bool pin(llvm::APSInt , llvm::APSInt ) const;
 
 public:
@@ -131,7 +134,6 @@ class RangeSet {
   }
 };
 
-
 class ConstraintRange {};
 using ConstraintRangeTy = llvm::ImmutableMap;
 

diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 368324d3d34f..570161543805 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -69,7 +69,19 @@ void RangeSet::IntersectInRange(BasicValueFactory , 
Factory ,
 
 const llvm::APSInt ::getMinValue() const {
   assert(!isEmpty());
-  return ranges.begin()->From();
+  return begin()->From();
+}
+
+const llvm::APSInt ::getMaxValue() const {
+  assert(!isEmpty());
+  // NOTE: It's a shame that we can't implement 'getMaxValue' without scanning
+  //   the whole tree to get to the last element.
+  //   llvm::ImmutableSet should support decrement for 'end' iterators
+  //   or reverse order iteration.
+  auto It = begin();
+  for (auto End = end(); std::next(It) != End; ++It) {
+  }
+  return It->To();
 }
 
 bool RangeSet::pin(llvm::APSInt , llvm::APSInt ) const {
@@ -426,22 +438,106 @@ class SymbolicRangeInferrer
 }
   }
 
+  
//===--===//
+  // Ranges and operators
+  
//===--===//
+
+  /// Return a rough approximation of the given range set.
+  ///
+  /// For the range set:
+  ///   { [x_0, y_0], [x_1, y_1], ... , [x_N, y_N] }
+  /// it will return the 

[clang] 1f57d76 - [analyzer] Refactor range inference for symbolic expressions

2020-05-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-05-28T18:54:52+03:00
New Revision: 1f57d76a8dd00611aaa4b33048be195ea9a2dc44

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

LOG: [analyzer] Refactor range inference for symbolic expressions

Summary:
This change introduces a new component to unite all of the reasoning
we have about operations on ranges in the analyzer's solver.
In many cases, we might conclude that the range for a symbolic operation
is much more narrow than the type implies.  While reasoning about
runtime conditions (especially in loops), we need to support more and
more of those little pieces of logic.  The new component mostly plays
a role of an organizer for those, and allows us to focus on the actual
reasoning about ranges and not dispatching manually on the types of the
nested symbolic expressions.

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

Added: 
clang/test/Analysis/double-ranges-bug.c

Modified: 

clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/test/Analysis/constant-folding.c

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
index c72f8292647d..97c9c6d63eb2 100644
--- 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
+++ 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -30,6 +30,10 @@ class Range : public std::pair {
   : std::pair(, ) {
 assert(from <= to);
   }
+
+  Range(const llvm::APSInt )
+  : std::pair(, ) 
{}
+
   bool Includes(const llvm::APSInt ) const {
 return *first <= v && v <= *second;
   }
@@ -89,6 +93,9 @@ class RangeSet {
   RangeSet(Factory , const llvm::APSInt , const llvm::APSInt )
   : ranges(F.add(F.getEmptySet(), Range(from, to))) {}
 
+  /// Construct a new RangeSet representing the given point as a range.
+  RangeSet(Factory , const llvm::APSInt ) : RangeSet(F, point, point) 
{}
+
   /// Profile - Generates a hash profile of this RangeSet for use
   ///  by FoldingSet.
   void Profile(llvm::FoldingSetNodeID ) const { ranges.Profile(ID); }

diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp 
b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index a3ea7d4c013b..368324d3d34f 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -16,6 +16,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableSet.h"
 #include "llvm/Support/raw_ostream.h"
@@ -23,10 +24,16 @@
 using namespace clang;
 using namespace ento;
 
+//===--===//
+//   RangeSet implementation
+//===--===//
+
 void RangeSet::IntersectInRange(BasicValueFactory , Factory ,
-  const llvm::APSInt , const llvm::APSInt ,
-  PrimRangeSet , PrimRangeSet::iterator ,
-  PrimRangeSet::iterator ) const {
+const llvm::APSInt ,
+const llvm::APSInt ,
+PrimRangeSet ,
+PrimRangeSet::iterator ,
+PrimRangeSet::iterator ) const {
   // There are six cases for each range R in the set:
   //   1. R is entirely before the intersection range.
   //   2. R is entirely after the intersection range.
@@ -66,6 +73,11 @@ const llvm::APSInt ::getMinValue() const {
 }
 
 bool RangeSet::pin(llvm::APSInt , llvm::APSInt ) const {
+  if (isEmpty()) {
+// This range is already infeasible.
+return false;
+  }
+
   // This function has nine cases, the cartesian product of range-testing
   // both the upper and lower bounds against the symbol's type.
   // Each case requires a 
diff erent pinning operation.
@@ -283,6 +295,207 @@ void RangeSet::print(raw_ostream ) const {
 }
 
 namespace {
+
+/// A little component aggregating all of the reasoning we have about
+/// the ranges of symbolic expressions.
+///
+/// Even when we don't know the exact values of the operands, we still
+/// can get a pretty good estimate of the result's range.
+class SymbolicRangeInferrer
+: public SymExprVisitor {
+public:

[clang] bb2ae74 - [analyzer] Merge implementations of SymInt, IntSym, and SymSym exprs

2020-05-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-05-28T18:54:27+03:00
New Revision: bb2ae74717a25ba268e7bd17a2a572d931ed094e

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

LOG: [analyzer] Merge implementations of SymInt, IntSym, and SymSym exprs

Summary:
SymIntExpr, IntSymExpr, and SymSymExpr share a big portion of logic
that used to be duplicated across all three classes.  New
implementation also adds an easy way of introducing another type of
operands into the mix.

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

Added: 


Modified: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
clang/lib/StaticAnalyzer/Core/SymbolManager.cpp

Removed: 




diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 2c505995bee0..390ced8c29f8 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -326,136 +326,83 @@ class BinarySymExpr : public SymExpr {
 Kind k = SE->getKind();
 return k >= BEGIN_BINARYSYMEXPRS && k <= END_BINARYSYMEXPRS;
   }
-};
-
-/// Represents a symbolic expression like 'x' + 3.
-class SymIntExpr : public BinarySymExpr {
-  const SymExpr *LHS;
-  const llvm::APSInt& RHS;
 
-public:
-  SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
- const llvm::APSInt , QualType t)
-  : BinarySymExpr(SymIntExprKind, op, t), LHS(lhs), RHS(rhs) {
-assert(lhs);
+protected:
+  static unsigned computeOperandComplexity(const SymExpr *Value) {
+return Value->computeComplexity();
   }
-
-  void dumpToStream(raw_ostream ) const override;
-
-  const SymExpr *getLHS() const { return LHS; }
-  const llvm::APSInt () const { return RHS; }
-
-  unsigned computeComplexity() const override {
-if (Complexity == 0)
-  Complexity = 1 + LHS->computeComplexity();
-return Complexity;
+  static unsigned computeOperandComplexity(const llvm::APSInt ) {
+return 1;
   }
 
-  static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
-  BinaryOperator::Opcode op, const llvm::APSInt& rhs,
-  QualType t) {
-ID.AddInteger((unsigned) SymIntExprKind);
-ID.AddPointer(lhs);
-ID.AddInteger(op);
-ID.AddPointer();
-ID.Add(t);
+  static const llvm::APSInt *getPointer(const llvm::APSInt ) {
+return 
   }
+  static const SymExpr *getPointer(const SymExpr *Value) { return Value; }
 
-  void Profile(llvm::FoldingSetNodeID& ID) override {
-Profile(ID, LHS, getOpcode(), RHS, getType());
-  }
-
-  // Implement isa support.
-  static bool classof(const SymExpr *SE) {
-return SE->getKind() == SymIntExprKind;
-  }
+  static void dumpToStreamImpl(raw_ostream , const SymExpr *Value);
+  static void dumpToStreamImpl(raw_ostream , const llvm::APSInt );
+  static void dumpToStreamImpl(raw_ostream , BinaryOperator::Opcode op);
 };
 
-/// Represents a symbolic expression like 3 - 'x'.
-class IntSymExpr : public BinarySymExpr {
-  const llvm::APSInt& LHS;
-  const SymExpr *RHS;
+/// Template implementation for all binary symbolic expressions
+template 
+class BinarySymExprImpl : public BinarySymExpr {
+  LHSTYPE LHS;
+  RHSTYPE RHS;
 
 public:
-  IntSymExpr(const llvm::APSInt , BinaryOperator::Opcode op,
- const SymExpr *rhs, QualType t)
-  : BinarySymExpr(IntSymExprKind, op, t), LHS(lhs), RHS(rhs) {
-assert(rhs);
+  BinarySymExprImpl(LHSTYPE lhs, BinaryOperator::Opcode op, RHSTYPE rhs,
+QualType t)
+  : BinarySymExpr(ClassKind, op, t), LHS(lhs), RHS(rhs) {
+assert(getPointer(lhs));
+assert(getPointer(rhs));
   }
 
-  void dumpToStream(raw_ostream ) const override;
+  void dumpToStream(raw_ostream ) const override {
+dumpToStreamImpl(os, LHS);
+dumpToStreamImpl(os, getOpcode());
+dumpToStreamImpl(os, RHS);
+  }
 
-  const SymExpr *getRHS() const { return RHS; }
-  const llvm::APSInt () const { return LHS; }
+  LHSTYPE getLHS() const { return LHS; }
+  RHSTYPE getRHS() const { return RHS; }
 
   unsigned computeComplexity() const override {
 if (Complexity == 0)
-  Complexity = 1 + RHS->computeComplexity();
+  Complexity =
+  computeOperandComplexity(RHS) + computeOperandComplexity(LHS);
 return Complexity;
   }
 
-  static void Profile(llvm::FoldingSetNodeID& ID, const llvm::APSInt& lhs,
-  BinaryOperator::Opcode op, const SymExpr *rhs,
-  QualType t) {
-ID.AddInteger((unsigned) IntSymExprKind);
-ID.AddPointer();
+  static void Profile(llvm::FoldingSetNodeID , LHSTYPE lhs,
+  BinaryOperator::Opcode op, RHSTYPE rhs, 

[clang] bd06c41 - [analyzer] Allow bindings of the CompoundLiteralRegion

2020-05-28 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-05-28T14:11:57+03:00
New Revision: bd06c417e6c717cbe33b566d7bbaf27fb47e763a

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

LOG: [analyzer] Allow bindings of the CompoundLiteralRegion

Summary:
CompoundLiteralRegions have been properly modeled before, but
'getBindingForElement` was not changed to accommodate this change
properly.

rdar://problem/46144644

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

Added: 
clang/test/Analysis/retain-release-compound-literal.m

Modified: 
clang/lib/StaticAnalyzer/Core/RegionStore.cpp
clang/test/Analysis/compound-literals.c
clang/unittests/StaticAnalyzer/StoreTest.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp 
b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 2a55c9964712..57fde32bc01d 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1628,10 +1628,6 @@ 
RegionStoreManager::findLazyBinding(RegionBindingsConstRef B,
 
 SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
   const ElementRegion* R) {
-  // We do not currently model bindings of the CompoundLiteralregion.
-  if (isa(R->getBaseRegion()))
-return UnknownVal();
-
   // Check if the region has a binding.
   if (const Optional  = B.getDirectBinding(R))
 return *V;

diff  --git a/clang/test/Analysis/compound-literals.c 
b/clang/test/Analysis/compound-literals.c
index f8b9121494c1..42e6a55a30c7 100644
--- a/clang/test/Analysis/compound-literals.c
+++ b/clang/test/Analysis/compound-literals.c
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -triple=i386-apple-darwin10 -analyze 
-analyzer-checker=debug.ExprInspection -verify %s
+// RUN: %clang_cc1 -triple=i386-apple-darwin10 -verify %s -analyze \
+// RUN:   -analyzer-checker=debug.ExprInspection
+
+#define NULL 0
 void clang_analyzer_eval(int);
 
 // pr28449: Used to crash.
@@ -6,3 +9,15 @@ void foo(void) {
   static const unsigned short array[] = (const unsigned short[]){0x0F00};
   clang_analyzer_eval(array[0] == 0x0F00); // expected-warning{{TRUE}}
 }
+
+// check that we propagate info through compound literal regions
+void bar() {
+  int *integers = (int[]){1, 2, 3};
+  clang_analyzer_eval(integers[0] == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(integers[1] == 2); // expected-warning{{TRUE}}
+  clang_analyzer_eval(integers[2] == 3); // expected-warning{{TRUE}}
+
+  int **pointers = (int *[]){[0], NULL};
+  clang_analyzer_eval(pointers[0] == NULL); // expected-warning{{FALSE}}
+  clang_analyzer_eval(pointers[1] == NULL); // expected-warning{{TRUE}}
+}

diff  --git a/clang/test/Analysis/retain-release-compound-literal.m 
b/clang/test/Analysis/retain-release-compound-literal.m
new file mode 100644
index ..29a125346363
--- /dev/null
+++ b/clang/test/Analysis/retain-release-compound-literal.m
@@ -0,0 +1,25 @@
+// RUN: %clang_analyze_cc1 -verify -Wno-objc-root-class %s \
+// RUN:   -analyzer-checker=core,osx.cocoa.RetainCount
+
+#define NULL 0
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#define CF_CONSUMED __attribute__((cf_consumed))
+
+void clang_analyzer_eval(int);
+
+typedef const void *CFTypeRef;
+
+extern CFTypeRef CFCreate() CF_RETURNS_RETAINED;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+extern void CFRelease(CFTypeRef cf);
+
+void bar(CFTypeRef *v) {}
+
+void test1() {
+  CFTypeRef *values = (CFTypeRef[]){
+  CFCreate(),  // no-warning
+  CFCreate(),  // expected-warning{{leak}}
+  CFCreate()}; // no-warning
+  CFRelease(values[0]);
+  CFRelease(values[2]);
+}

diff  --git a/clang/unittests/StaticAnalyzer/StoreTest.cpp 
b/clang/unittests/StaticAnalyzer/StoreTest.cpp
index c8b930bf3247..17b64ce622f8 100644
--- a/clang/unittests/StaticAnalyzer/StoreTest.cpp
+++ b/clang/unittests/StaticAnalyzer/StoreTest.cpp
@@ -15,89 +15,139 @@ namespace clang {
 namespace ento {
 namespace {
 
+class StoreTestConsumer : public ExprEngineConsumer {
+public:
+  StoreTestConsumer(CompilerInstance ) : ExprEngineConsumer(C) {}
+
+  bool HandleTopLevelDecl(DeclGroupRef DG) override {
+for (const auto *D : DG)
+  performTest(D);
+return true;
+  }
+
+private:
+  virtual void performTest(const Decl *D) = 0;
+};
+
+template  class TestAction : public ASTFrontendAction {
+public:
+  std::unique_ptr CreateASTConsumer(CompilerInstance ,
+ StringRef File) override {
+return std::make_unique(Compiler);
+  }
+};
+
 // Test that we can put a value into an int-type variable and load it
 // back from that variable. Test what happens if default bindings are used.
-class VariableBindConsumer : public ExprEngineConsumer {
-  void 

[clang] a5b2503 - [analyzer] SATestBuild.py: Fix hang when one of the tasks fails

2020-05-22 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-05-22T19:15:00+03:00
New Revision: a5b2503a8ab4fb21345fa9e2316530cdfaec1a60

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

LOG: [analyzer] SATestBuild.py: Fix hang when one of the tasks fails

Summary:
Tasks can crash with many different exceptions including SystemExit.
Bare except still causes a warning, so let's use BaseException instead.

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

Added: 


Modified: 
clang/utils/analyzer/SATestBuild.py

Removed: 




diff  --git a/clang/utils/analyzer/SATestBuild.py 
b/clang/utils/analyzer/SATestBuild.py
index 39fa7ece4362..e2fe6a95138b 100755
--- a/clang/utils/analyzer/SATestBuild.py
+++ b/clang/utils/analyzer/SATestBuild.py
@@ -633,7 +633,7 @@ def run(self):
 
 self.tasks_queue.task_done()
 
-except CalledProcessError:
+except BaseException:
 self.failure_flag.set()
 raise
 



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


[clang] 475d120 - [analyzer] SumTimerInfo.py: Partially modernize

2020-05-22 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-05-22T13:51:58+03:00
New Revision: 475d1202837071959f3f69d3512c820538d81543

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

LOG: [analyzer] SumTimerInfo.py: Partially modernize

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

Added: 


Modified: 
clang/utils/analyzer/SumTimerInfo.py

Removed: 




diff  --git a/clang/utils/analyzer/SumTimerInfo.py 
b/clang/utils/analyzer/SumTimerInfo.py
index 5d86f763f001..eed17e02e32e 100644
--- a/clang/utils/analyzer/SumTimerInfo.py
+++ b/clang/utils/analyzer/SumTimerInfo.py
@@ -6,8 +6,6 @@
 Statistics are enabled by passing '-internal-stats' option to scan-build
 (or '-analyzer-stats' to the analyzer).
 """
-from __future__ import absolute_import, division, print_function
-
 import sys
 
 if __name__ == '__main__':
@@ -17,64 +15,65 @@
 sys.exit(-1)
 
 f = open(sys.argv[1], 'r')
-Time = 0.0
-TotalTime = 0.0
-MaxTime = 0.0
-Warnings = 0
-Count = 0
-FunctionsAnalyzed = 0
-ReachableBlocks = 0
-ReachedMaxSteps = 0
-NumSteps = 0
-NumInlinedCallSites = 0
-NumBifurcatedCallSites = 0
-MaxCFGSize = 0
+time = 0.0
+total_time = 0.0
+max_time = 0.0
+warnings = 0
+count = 0
+functions_analyzed = 0
+reachable_blocks = 0
+reached_max_steps = 0
+num_steps = 0
+num_inlined_call_sites = 0
+num_bifurcated_call_sites = 0
+max_cfg_size = 0
+
 for line in f:
-if ("Analyzer Total Time" in line):
+if "Analyzer total time" in line:
 s = line.split()
-Time = Time + float(s[6])
-Count = Count + 1
-if (float(s[6]) > MaxTime):
-MaxTime = float(s[6])
-if ("warning generated." in line) or ("warnings generated" in line):
+time = time + float(s[6])
+count = count + 1
+if float(s[6]) > max_time:
+max_time = float(s[6])
+if "warning generated." in line or "warnings generated" in line:
 s = line.split()
-Warnings = Warnings + int(s[0])
+warnings = warnings + int(s[0])
 if "The # of functions analysed (as top level)" in line:
 s = line.split()
-FunctionsAnalyzed = FunctionsAnalyzed + int(s[0])
+functions_analyzed = functions_analyzed + int(s[0])
 if "The % of reachable basic blocks" in line:
 s = line.split()
-ReachableBlocks = ReachableBlocks + int(s[0])
+reachable_blocks = reachable_blocks + int(s[0])
 if "The # of times we reached the max number of steps" in line:
 s = line.split()
-ReachedMaxSteps = ReachedMaxSteps + int(s[0])
+reached_max_steps = reached_max_steps + int(s[0])
 if "The maximum number of basic blocks in a function" in line:
 s = line.split()
-if MaxCFGSize < int(s[0]):
-MaxCFGSize = int(s[0])
+if max_cfg_size < int(s[0]):
+max_cfg_size = int(s[0])
 if "The # of steps executed" in line:
 s = line.split()
-NumSteps = NumSteps + int(s[0])
+num_steps = num_steps + int(s[0])
 if "The # of times we inlined a call" in line:
 s = line.split()
-NumInlinedCallSites = NumInlinedCallSites + int(s[0])
+num_inlined_call_sites = num_inlined_call_sites + int(s[0])
 if "The # of times we split the path due \
 to imprecise dynamic dispatch info" in line:
 s = line.split()
-NumBifurcatedCallSites = NumBifurcatedCallSites + int(s[0])
+num_bifurcated_call_sites = num_bifurcated_call_sites + int(s[0])
 if ")  Total" in line:
 s = line.split()
-TotalTime = TotalTime + float(s[6])
+total_time = total_time + float(s[6])
 
-print("TU Count %d" % (Count))
-print("Time %f" % (Time))
-print("Warnings %d" % (Warnings))
-print("Functions Analyzed %d" % (FunctionsAnalyzed))
-print("Reachable Blocks %d" % (ReachableBlocks))
-print("Reached Max Steps %d" % (ReachedMaxSteps))
-print("Number of Steps %d" % (NumSteps))
-print("Number of Inlined calls %d (bifurcated %d)" % (
-NumInlinedCallSites, NumBifurcatedCallSites))
-print("MaxTime %f" % (MaxTime))
-print("TotalTime %f" % (TotalTime))
-print("Max CFG Size %d" % (MaxCFGSize))
+print(f"TU count {count}")
+print(f"Time {time}")
+print(f"Warnings {warnings}")
+print(f"Functions analyzed {functions_analyzed}")
+print(f"Reachable blocks {reachable_blocks}")
+print(f"Reached max steps {reached_max_steps}")
+print(f"Number of steps 

[clang] 5a9aff1 - [analyzer] SATestUpdateDiffs.py: Refactor and add type annotations

2020-05-22 Thread Valeriy Savchenko via cfe-commits

Author: Valeriy Savchenko
Date: 2020-05-22T13:51:58+03:00
New Revision: 5a9aff12ff3bc68109f41930ec296b7a19cbe76c

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

LOG: [analyzer] SATestUpdateDiffs.py: Refactor and add type annotations

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

Added: 


Modified: 
clang/utils/analyzer/SATestUpdateDiffs.py

Removed: 




diff  --git a/clang/utils/analyzer/SATestUpdateDiffs.py 
b/clang/utils/analyzer/SATestUpdateDiffs.py
index ac2832d40e6e..e89b06dd75eb 100755
--- a/clang/utils/analyzer/SATestUpdateDiffs.py
+++ b/clang/utils/analyzer/SATestUpdateDiffs.py
@@ -3,67 +3,67 @@
 """
 Update reference results for static analyzer.
 """
-from __future__ import absolute_import, division, print_function
-
 import SATestBuild
 
-from subprocess import check_call
 import os
+import shutil
 import sys
 
+from subprocess import check_call
+
 Verbose = 0
 
 
-def runCmd(Command, **kwargs):
-if Verbose:
-print("Executing %s" % Command)
-check_call(Command, shell=True, **kwargs)
+def update_reference_results(project_name: str, build_mode: int):
+project_info = SATestBuild.ProjectInfo(project_name, build_mode)
+tester = SATestBuild.ProjectTester(project_info)
+project_dir = tester.get_project_dir()
 
+tester.is_reference_build = True
+ref_results_path = os.path.join(project_dir, tester.get_output_dir())
 
-def updateReferenceResults(ProjName, ProjBuildMode):
-ProjInfo = SATestBuild.ProjectInfo(ProjName, ProjBuildMode)
-ProjTester = SATestBuild.ProjectTester(ProjInfo)
-ProjDir = ProjTester.get_project_dir()
+tester.is_reference_build = False
+created_results_path = os.path.join(project_dir, tester.get_output_dir())
 
-ProjTester.is_reference_build = True
-RefResultsPath = os.path.join(ProjDir, ProjTester.get_output_dir())
+if not os.path.exists(created_results_path):
+print("New results not found, was SATestBuild.py previously run?",
+  file=sys.stderr)
+sys.exit(1)
 
-ProjTester.is_reference_build = False
-CreatedResultsPath = os.path.join(ProjDir, ProjTester.get_output_dir())
+build_log_path = SATestBuild.get_build_log_path(ref_results_path)
+build_log_dir = os.path.dirname(os.path.abspath(build_log_path))
 
-if not os.path.exists(CreatedResultsPath):
-print("New results not found, was SATestBuild.py "
-  "previously run?", file=sys.stderr)
-sys.exit(1)
+os.makedirs(build_log_dir)
+
+with open(build_log_path, "w+") as build_log_file:
+def run_cmd(command: str):
+if Verbose:
+print(f"Executing {command}")
+check_call(command, shell=True, stdout=build_log_file)
 
-BuildLogPath = SATestBuild.get_build_log_path(RefResultsPath)
-Dirname = os.path.dirname(os.path.abspath(BuildLogPath))
-runCmd("mkdir -p '%s'" % Dirname)
-with open(BuildLogPath, "w+") as PBuildLogFile:
 # Remove reference results: in git, and then again for a good measure
 # with rm, as git might not remove things fully if there are empty
 # directories involved.
-runCmd('git rm -r -q "%s"' % (RefResultsPath,), stdout=PBuildLogFile)
-runCmd('rm -rf "%s"' % (RefResultsPath,), stdout=PBuildLogFile)
+run_cmd(f"git rm -r -q '{ref_results_path}'")
+shutil.rmtree(ref_results_path)
 
 # Replace reference results with a freshly computed once.
-runCmd('cp -r "%s" "%s"' % (CreatedResultsPath, RefResultsPath,),
-   stdout=PBuildLogFile)
+shutil.copytree(created_results_path, ref_results_path, symlinks=True)
 
 # Run cleanup script.
-SATestBuild.run_cleanup_script(ProjDir, PBuildLogFile)
+SATestBuild.run_cleanup_script(project_dir, build_log_file)
 
 SATestBuild.normalize_reference_results(
-ProjDir, RefResultsPath, ProjBuildMode)
+project_dir, ref_results_path, build_mode)
 
 # Clean up the generated 
diff erence results.
-SATestBuild.cleanup_reference_results(RefResultsPath)
+SATestBuild.cleanup_reference_results(ref_results_path)
 
-runCmd('git add "%s"' % (RefResultsPath,), stdout=PBuildLogFile)
+run_cmd(f"git add '{ref_results_path}'")
 
 
 def main(argv):
-if len(argv) == 2 and argv[1] in ('-h', '--help'):
+if len(argv) == 2 and argv[1] in ("-h", "--help"):
 print("Update static analyzer reference results based "
   "\non the previous run of SATestBuild.py.\n"
   "\nN.B.: Assumes that SATestBuild.py was just run",
@@ -71,8 +71,8 @@ def main(argv):
 sys.exit(1)
 
 with open(SATestBuild.get_project_map_path(), "r") as f:
-for ProjName, 

  1   2   >