[analyzer] Use Clang's evaluation for global constants and default arguments.

Previously, we were handling only simple integer constants for globals and
the smattering of implicitly-valued expressions handled by Environment for
default arguments. Now, we can use any integer constant expression that
Clang can evaluate, in addition to everything we handled before.

PR15094 / <rdar://problem/12830437>

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175026 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index b6c44bf..2b069a0 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -37,9 +37,6 @@
   case Stmt::SubstNonTypeTemplateParmExprClass:
     E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
     break;
-  case Stmt::CXXDefaultArgExprClass:
-    E = cast<CXXDefaultArgExpr>(E)->getExpr();
-    break;
   default:
     // This is the base case: we can't look through more than we already have.
     return E;
@@ -75,7 +72,6 @@
 
   switch (S->getStmtClass()) {
   case Stmt::CXXBindTemporaryExprClass:
-  case Stmt::CXXDefaultArgExprClass:
   case Stmt::ExprWithCleanupsClass:
   case Stmt::GenericSelectionExprClass:
   case Stmt::OpaqueValueExprClass:
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index f092f1a..18ac096 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -639,7 +639,6 @@
     case Stmt::StringLiteralClass:
     case Stmt::ObjCStringLiteralClass:
     case Stmt::CXXBindTemporaryExprClass:
-    case Stmt::CXXDefaultArgExprClass:
     case Stmt::SubstNonTypeTemplateParmExprClass:
     case Stmt::CXXNullPtrLiteralExprClass: {
       Bldr.takeNodes(Pred);
@@ -650,6 +649,39 @@
       break;
     }
 
+    case Stmt::CXXDefaultArgExprClass: {
+      Bldr.takeNodes(Pred);
+      ExplodedNodeSet PreVisit;
+      getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
+
+      ExplodedNodeSet Tmp;
+      StmtNodeBuilder Bldr2(PreVisit, Tmp, *currBldrCtx);
+
+      const LocationContext *LCtx = Pred->getLocationContext();
+      const Expr *ArgE = cast<CXXDefaultArgExpr>(S)->getExpr();
+
+      // Avoid creating and destroying a lot of APSInts.
+      SVal V;
+      llvm::APSInt Result;
+
+      for (ExplodedNodeSet::iterator I = PreVisit.begin(), E = PreVisit.end();
+           I != E; ++I) {
+        ProgramStateRef State = (*I)->getState();
+
+        if (ArgE->EvaluateAsInt(Result, getContext()))
+          V = svalBuilder.makeIntVal(Result);
+        else
+          V = State->getSVal(ArgE, LCtx);
+
+        State = State->BindExpr(S, LCtx, V);
+        Bldr2.generateNode(S, *I, State);
+      }
+
+      getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
+      Bldr.addNodes(Dst);
+      break;
+    }
+
     case Expr::ObjCArrayLiteralClass:
     case Expr::ObjCDictionaryLiteralClass:
       // FIXME: explicitly model with a region and the actual contents
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index 399f9eb..9572f64 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1524,11 +1524,14 @@
     QualType CT = Ctx.getCanonicalType(T);
     if (CT.isConstQualified()) {
       if (const Expr *Init = VD->getInit()) {
-        if (const IntegerLiteral *IL =
-            dyn_cast<IntegerLiteral>(Init->IgnoreParenCasts())) {
-          const nonloc::ConcreteInt &V = svalBuilder.makeIntVal(IL);
-          return svalBuilder.evalCast(V, Init->getType(), IL->getType());
-        }
+        llvm::APSInt Result;
+        if (Init->EvaluateAsInt(Result, Ctx))
+          return svalBuilder.makeIntVal(Result);
+
+        if (Init->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
+          return svalBuilder.makeNull();
+
+        // FIXME: Handle other possible constant expressions.
       }
     }
 
diff --git a/test/Analysis/global-region-invalidation.c b/test/Analysis/global-region-invalidation.c
index 113e6ae..77de9dd 100644
--- a/test/Analysis/global-region-invalidation.c
+++ b/test/Analysis/global-region-invalidation.c
@@ -67,15 +67,29 @@
   return 3 / *m; // expected-warning {{Division by zero}}
 }
 
-extern const int x;
+extern const int y;
 int constIntGlobExtern() {
-  if (x == 0) {
+  if (y == 0) {
     foo();
-    return 5 / x; // expected-warning {{Division by zero}}
+    return 5 / y; // expected-warning {{Division by zero}}
   }
   return 0;
 }
 
+static void * const ptr = 0;
+void constPtrGlob() {
+  clang_analyzer_eval(ptr == 0); // expected-warning{{TRUE}}
+  foo();
+  clang_analyzer_eval(ptr == 0); // expected-warning{{TRUE}}
+}
+
+static const int x2 = x;
+void constIntGlob2() {
+  clang_analyzer_eval(x2 == 0); // expected-warning{{TRUE}}
+  foo();
+  clang_analyzer_eval(x2 == 0); // expected-warning{{TRUE}}
+}
+
 void testAnalyzerEvalIsPure() {
   extern int someGlobal;
   if (someGlobal == 0) {
diff --git a/test/Analysis/inline.cpp b/test/Analysis/inline.cpp
index 873b046..f0e69dd 100644
--- a/test/Analysis/inline.cpp
+++ b/test/Analysis/inline.cpp
@@ -216,7 +216,7 @@
 
   class Secret {
   public:
-    static const int value = 42;
+    static const int value = 40 + 2;
     int get(int i = value) {
       return i;
     }
@@ -225,16 +225,40 @@
   void testMethod() {
     Secret obj;
     clang_analyzer_eval(obj.get(1) == 1); // expected-warning{{TRUE}}
-
-    // FIXME: Should be 'TRUE'. See PR13673 or <rdar://problem/11720796>.
-    clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}}
-
-    // FIXME: Even if we constrain the variable, we still have a problem.
-    // See PR13385 or <rdar://problem/12156507>.
-    if (Secret::value != 42)
-      return;
+    clang_analyzer_eval(obj.get() == 42); // expected-warning{{TRUE}}
     clang_analyzer_eval(Secret::value == 42); // expected-warning{{TRUE}}
-    clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}}
+  }
+
+  enum ABC {
+    A = 0,
+    B = 1,
+    C = 2
+  };
+
+  int enumUser(ABC input = B) {
+    return static_cast<int>(input);
+  }
+
+  void testEnum() {
+    clang_analyzer_eval(enumUser(C) == 2); // expected-warning{{TRUE}}
+    clang_analyzer_eval(enumUser() == 1); // expected-warning{{TRUE}}
+  }
+
+
+  int exprUser(int input = 2 * 4) {
+    return input;
+  }
+
+  int complicatedExprUser(int input = 2 * Secret::value) {
+    return input;
+  }
+
+  void testExprs() {
+    clang_analyzer_eval(exprUser(1) == 1); // expected-warning{{TRUE}}
+    clang_analyzer_eval(exprUser() == 8); // expected-warning{{TRUE}}
+
+    clang_analyzer_eval(complicatedExprUser(1) == 1); // expected-warning{{TRUE}}
+    clang_analyzer_eval(complicatedExprUser() == 84); // expected-warning{{TRUE}}
   }
 }