[clang] 1638636 - [analyzer] Evaluate PredefinedExpressions

Balazs Benics via cfe-commits cfe-commits at lists.llvm.org
Sun Sep 13 23:44:34 PDT 2020


Author: Balazs Benics
Date: 2020-09-14T08:43:56+02:00
New Revision: 163863604f9c1ad3add238f9e8fb32cfd136f894

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

LOG: [analyzer] Evaluate PredefinedExpressions

We did not evaluate such expressions, just returned `Unknown` for such cases.
After this patch, we will be able to access a unique value identifying a template instantiation via the value of the `PRETTY_FUNCTION` predefined expression.

Reviewed By: vsavchenko

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

Added: 
    clang/test/Analysis/eval-predefined-exprs.cpp

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

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Core/Environment.cpp b/clang/lib/StaticAnalyzer/Core/Environment.cpp
index 556ff6af15de..cba20b967b6f 100644
--- a/clang/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Environment.cpp
@@ -116,6 +116,7 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry,
   case Stmt::StringLiteralClass:
   case Stmt::TypeTraitExprClass:
   case Stmt::SizeOfPackExprClass:
+  case Stmt::PredefinedExprClass:
     // Known constants; defer to SValBuilder.
     return svalBuilder.getConstantVal(cast<Expr>(S)).getValue();
 

diff  --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 32d2a3e30708..72b8ada1dfab 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -306,6 +306,14 @@ Optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
     return makeLoc(getRegionManager().getStringRegion(SL));
   }
 
+  case Stmt::PredefinedExprClass: {
+    const auto *PE = cast<PredefinedExpr>(E);
+    assert(PE->getFunctionName() &&
+           "Since we analyze only instantiated functions, PredefinedExpr "
+           "should have a function name.");
+    return makeLoc(getRegionManager().getStringRegion(PE->getFunctionName()));
+  }
+
   // Fast-path some expressions to avoid the overhead of going through the AST's
   // constant evaluator
   case Stmt::CharacterLiteralClass: {

diff  --git a/clang/test/Analysis/eval-predefined-exprs.cpp b/clang/test/Analysis/eval-predefined-exprs.cpp
new file mode 100644
index 000000000000..cc48a264f2d3
--- /dev/null
+++ b/clang/test/Analysis/eval-predefined-exprs.cpp
@@ -0,0 +1,109 @@
+// RUN: %clang_analyze_cc1 -std=c++17 -analyzer-checker=core,debug.ExprInspection -verify %s
+//
+// RUN: %clang_analyze_cc1 -std=c++17 -analyzer-checker=core,debug.ExprInspection -verify \
+// RUN:   -triple i386-pc-win32 -fms-compatibility -fms-extensions -DANALYZER_MS %s
+
+template <typename T>
+void clang_analyzer_dump(const T *);
+void clang_analyzer_warnIfReached();
+
+void builtin_unique_stable_name_of_lambda() {
+  auto y = [] {};
+  clang_analyzer_dump(__builtin_unique_stable_name(y));
+  // expected-warning at -1 {{&Element{"_ZTSZ36builtin_unique_stable_name_of_lambdavEUlvE11_12",0 S64b,char}}}
+}
+
+template <typename T, auto Value, typename U>
+void func(U param) {
+  clang_analyzer_dump(__func__);
+  clang_analyzer_dump(__FUNCTION__);
+  clang_analyzer_dump(__PRETTY_FUNCTION__);
+  // expected-warning at -3 {{&Element{"func",0 S64b,char}}}
+  // expected-warning at -3 {{&Element{"func",0 S64b,char}}}
+  // expected-warning at -3 {{&Element{"void func(U) [T = Class, Value = 42, U = char]",0 S64b,char}}}
+
+#ifdef ANALYZER_MS
+  clang_analyzer_dump(__FUNCDNAME__);
+  clang_analyzer_dump(L__FUNCTION__);
+  clang_analyzer_dump(__FUNCSIG__);
+  clang_analyzer_dump(L__FUNCSIG__);
+  // expected-warning at -4 {{&Element{"??$func at UClass@?1??foo@@YAXXZ@$0CK at D@@YAXD at Z",0 S64b,char}}}
+  // expected-warning at -4 {{&Element{L"func",0 S64b,wchar_t}}}
+  // expected-warning at -4 {{&Element{"void __cdecl func(U) [T = Class, Value = 42, U = char]",0 S64b,char}}}
+  // expected-warning at -4 {{&Element{L"void __cdecl func(U) [T = Class, Value = 42, U = char]",0 S64b,wchar_t}}}
+#endif
+}
+
+void foo() {
+  clang_analyzer_dump(__func__);
+  clang_analyzer_dump(__FUNCTION__);
+  clang_analyzer_dump(__PRETTY_FUNCTION__);
+  // expected-warning at -3 {{&Element{"foo",0 S64b,char}}}
+  // expected-warning at -3 {{&Element{"foo",0 S64b,char}}}
+  // expected-warning at -3 {{&Element{"void foo()",0 S64b,char}}}
+
+#ifdef ANALYZER_MS
+  clang_analyzer_dump(__FUNCDNAME__);
+  clang_analyzer_dump(L__FUNCTION__);
+  clang_analyzer_dump(__FUNCSIG__);
+  clang_analyzer_dump(L__FUNCSIG__);
+  // expected-warning at -4 {{&Element{"?foo@@YAXXZ",0 S64b,char}}}
+  // expected-warning at -4 {{&Element{L"foo",0 S64b,wchar_t}}}
+  // expected-warning at -4 {{&Element{"void __cdecl foo(void)",0 S64b,char}}}
+  // expected-warning at -4 {{&Element{L"void __cdecl foo(void)",0 S64b,wchar_t}}}
+#endif
+
+  func<struct Class, 42ull>('b'); // instantiate template
+}
+
+void test_builtin_unique_stable_name(int a) {
+  clang_analyzer_dump(__builtin_unique_stable_name(a));
+  // expected-warning at -1 {{&Element{"_ZTSi",0 S64b,char}}}
+}
+
+struct A {
+  A() {
+    clang_analyzer_dump(__func__);
+    clang_analyzer_dump(__FUNCTION__);
+    clang_analyzer_dump(__PRETTY_FUNCTION__);
+    // expected-warning at -3 {{&Element{"A",0 S64b,char}}}
+    // expected-warning at -3 {{&Element{"A",0 S64b,char}}}
+    // expected-warning at -3 {{&Element{"A::A()",0 S64b,char}}}
+
+#ifdef ANALYZER_MS
+    clang_analyzer_dump(__FUNCDNAME__);
+    clang_analyzer_dump(L__FUNCTION__);
+    clang_analyzer_dump(__FUNCSIG__);
+    clang_analyzer_dump(L__FUNCSIG__);
+    // expected-warning at -4 {{&Element{"??0A@@QAE at XZ",0 S64b,char}}}
+    // expected-warning at -4 {{&Element{L"A",0 S64b,wchar_t}}}
+    // expected-warning at -4 {{&Element{"__thiscall A::A(void)",0 S64b,char}}}
+    // expected-warning at -4 {{&Element{L"__thiscall A::A(void)",0 S64b,wchar_t}}}
+#endif
+  }
+  ~A() {
+    clang_analyzer_dump(__func__);
+    clang_analyzer_dump(__FUNCTION__);
+    clang_analyzer_dump(__PRETTY_FUNCTION__);
+    // expected-warning at -3 {{&Element{"~A",0 S64b,char}}}
+    // expected-warning at -3 {{&Element{"~A",0 S64b,char}}}
+    // expected-warning at -3 {{&Element{"A::~A()",0 S64b,char}}}
+
+#ifdef ANALYZER_MS
+    clang_analyzer_dump(__FUNCDNAME__);
+    clang_analyzer_dump(L__FUNCTION__);
+    clang_analyzer_dump(__FUNCSIG__);
+    clang_analyzer_dump(L__FUNCSIG__);
+    // expected-warning at -4 {{&Element{"??1A@@QAE at XZ",0 S64b,char}}}
+    // expected-warning at -4 {{&Element{L"~A",0 S64b,wchar_t}}}
+    // expected-warning at -4 {{&Element{"__thiscall A::~A(void)",0 S64b,char}}}
+    // expected-warning at -4 {{&Element{L"__thiscall A::~A(void)",0 S64b,wchar_t}}}
+#endif
+  }
+
+  template <typename> int dependent() {
+    // We should not analyze dependent functions.
+    // Such functions have no function name of predefined expressions such as: '__func__' etc.
+    clang_analyzer_warnIfReached(); // no-warning
+  }
+};


        


More information about the cfe-commits mailing list