martong created this revision.
martong added reviewers: NoQ, steakhal.
Herald added subscribers: manas, ASDenysPetrov, gamesh411, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, baloghadamsoftware, 
xazax.hun.
Herald added a reviewer: Szelethus.
Herald added a project: All.
martong requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This patch adds a new descendant to the SymExpr hierarchy. This way, now we
can assign constraints to symbolic unary expressions. This time, only
the unary minus is handled, later patches might extend with other unary
operators.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D125318

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def
  clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
  clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
  clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
  clang/test/Analysis/unary-sym-expr.c

Index: clang/test/Analysis/unary-sym-expr.c
===================================================================
--- /dev/null
+++ clang/test/Analysis/unary-sym-expr.c
@@ -0,0 +1,16 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:   -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -analyzer-config eagerly-assume=false \
+// RUN:   -verify
+
+void clang_analyzer_eval(int);
+
+int test(int flag) {
+  if (-flag == 0) {
+    clang_analyzer_eval(-flag == 0); // expected-warning{{TRUE}}
+    clang_analyzer_eval(-flag > 0);  // expected-warning{{FALSE}}
+    clang_analyzer_eval(-flag < 0);  // expected-warning{{FALSE}}
+  }
+  (void)(flag);
+  return 42;
+}
Index: clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -70,6 +70,11 @@
   os << ')';
 }
 
+void UnarySymExpr::dumpToStream(raw_ostream &os) const {
+  os << UnaryOperator::getOpcodeStr(Op);
+  Operand->dumpToStream(os);
+}
+
 void SymbolConjured::dumpToStream(raw_ostream &os) const {
   os << getKindStr() << getSymbolID() << '{' << T << ", LC" << LCtx->getID();
   if (S)
@@ -134,6 +139,9 @@
     case SymExpr::SymbolCastKind:
       itr.push_back(cast<SymbolCast>(SE)->getOperand());
       return;
+    case SymExpr::UnarySymExprKind:
+      itr.push_back(cast<UnarySymExpr>(SE)->getOperand());
+      return;
     case SymExpr::SymIntExprKind:
       itr.push_back(cast<SymIntExpr>(SE)->getLHS());
       return;
@@ -306,6 +314,22 @@
   return cast<SymSymExpr>(data);
 }
 
+const UnarySymExpr *SymbolManager::getUnarySymExpr(const SymExpr *Operand,
+                                                   UnaryOperator::Opcode Opc,
+                                                   QualType T) {
+  llvm::FoldingSetNodeID ID;
+  UnarySymExpr::Profile(ID, Operand, Opc, T);
+  void *InsertPos;
+  SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
+  if (!data) {
+    data = (UnarySymExpr *)BPAlloc.Allocate<UnarySymExpr>();
+    new (data) UnarySymExpr(Operand, Opc, T);
+    DataSet.InsertNode(data, InsertPos);
+  }
+
+  return cast<UnarySymExpr>(data);
+}
+
 QualType SymbolConjured::getType() const {
   return T;
 }
@@ -465,6 +489,9 @@
   case SymExpr::SymbolCastKind:
     KnownLive = isLive(cast<SymbolCast>(sym)->getOperand());
     break;
+  case SymExpr::UnarySymExprKind:
+    KnownLive = isLive(cast<UnarySymExpr>(sym)->getOperand());
+    break;
   }
 
   if (KnownLive)
Index: clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -90,6 +90,9 @@
   switch (val.getSubKind()) {
   case nonloc::ConcreteIntKind:
     return val.castAs<nonloc::ConcreteInt>().evalMinus(*this);
+  case nonloc::SymbolValKind:
+    return makeNonLoc(val.castAs<nonloc::SymbolVal>().getSymbol(), UO_Minus,
+                      val.getType(Context));
   default:
     return UnknownVal();
   }
Index: clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -99,6 +99,13 @@
   return nonloc::SymbolVal(SymMgr.getSymSymExpr(lhs, op, rhs, type));
 }
 
+NonLoc SValBuilder::makeNonLoc(const SymExpr *operand, UnaryOperator::Opcode op,
+                               QualType type) {
+  assert(operand);
+  assert(!Loc::isLocType(type));
+  return nonloc::SymbolVal(SymMgr.getUnarySymExpr(operand, op, type));
+}
+
 NonLoc SValBuilder::makeNonLoc(const SymExpr *operand,
                                QualType fromTy, QualType toTy) {
   assert(operand);
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def
@@ -33,6 +33,8 @@
 #define SYMBOL_RANGE(Id, First, Last)
 #endif
 
+SYMBOL(UnarySymExpr, SymExpr)
+
 ABSTRACT_SYMBOL(BinarySymExpr, SymExpr)
   SYMBOL(IntSymExpr, BinarySymExpr)
   SYMBOL(SymIntExpr, BinarySymExpr)
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -309,6 +309,52 @@
   }
 };
 
+/// Represents a symbolic expression involving a unary operator.
+class UnarySymExpr : public SymExpr {
+  const SymExpr *Operand;
+  UnaryOperator::Opcode Op;
+  QualType T;
+
+public:
+  UnarySymExpr(const SymExpr *In, UnaryOperator::Opcode Op, QualType T)
+      : SymExpr(UnarySymExprKind), Operand(In), Op(Op), T(T) {
+    assert(classof(this));
+    // Unary expressions are results of arithmetic. Pointer arithmetic is not
+    // handled by unary expressions, but it is instead handled by applying
+    // sub-regions to regions.
+    assert(isValidTypeForSymbol(T) && !Loc::isLocType(T));
+  }
+
+  unsigned computeComplexity() const override {
+    if (Complexity == 0)
+      Complexity = 1 + Operand->computeComplexity();
+    return Complexity;
+  }
+
+  const SymExpr *getOperand() const { return Operand; }
+  UnaryOperator::Opcode getOpcode() const { return Op; }
+  QualType getType() const override { return T; }
+
+  void dumpToStream(raw_ostream &os) const override;
+
+  static void Profile(llvm::FoldingSetNodeID &ID, const SymExpr *In,
+                      UnaryOperator::Opcode Op, QualType T) {
+    ID.AddInteger((unsigned)UnarySymExprKind);
+    ID.AddPointer(In);
+    ID.AddInteger(Op);
+    ID.Add(T);
+  }
+
+  void Profile(llvm::FoldingSetNodeID &ID) override {
+    Profile(ID, Operand, Op, T);
+  }
+
+  // Implement isa<T> support.
+  static bool classof(const SymExpr *SE) {
+    return SE->getKind() == UnarySymExprKind;
+  }
+};
+
 /// Represents a symbolic expression involving a binary operator
 class BinarySymExpr : public SymExpr {
   BinaryOperator::Opcode Op;
@@ -486,6 +532,9 @@
   const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
                                   const SymExpr *rhs, QualType t);
 
+  const UnarySymExpr *getUnarySymExpr(const SymExpr *operand,
+                                      UnaryOperator::Opcode op, QualType t);
+
   QualType getType(const SymExpr *SE) const {
     return SE->getType();
   }
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -349,6 +349,9 @@
   NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
                     const SymExpr *rhs, QualType type);
 
+  NonLoc makeNonLoc(const SymExpr *operand, UnaryOperator::Opcode op,
+                    QualType type);
+
   /// Create a NonLoc value for cast.
   NonLoc makeNonLoc(const SymExpr *operand, QualType fromTy, QualType toTy);
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to