[clang] [analyzer] Teach -analyze-function about USRs, extend documentation (PR #161666)

via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 2 06:31:19 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Balazs Benics (steakhal)

<details>
<summary>Changes</summary>

This flag is really convinient in most cases.
It's easy to figure out what value to pass for most cases. However, it can sometimes match too many times, like for template functions that has non-decuded (aka. explicitly specified) template parameters - because they don't appear in the parameter list, thus they are not accounted for in the current logic.

It would be nice to improve `getFunctionName` but I'd say to just settle on using USRs. So this PR enables passing USRs to the flag, while keeping previous behavior.

---
Full diff: https://github.com/llvm/llvm-project/pull/161666.diff


5 Files Affected:

- (modified) clang/docs/analyzer/developer-docs/DebugChecks.rst (+16) 
- (modified) clang/include/clang/CrossTU/CrossTranslationUnit.h (+2-2) 
- (modified) clang/lib/CrossTU/CrossTranslationUnit.cpp (+2-2) 
- (modified) clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (+4-1) 
- (added) clang/test/Analysis/analyzeOneFunction.cpp (+18) 


``````````diff
diff --git a/clang/docs/analyzer/developer-docs/DebugChecks.rst b/clang/docs/analyzer/developer-docs/DebugChecks.rst
index 767ef6565d335..b3b908941317e 100644
--- a/clang/docs/analyzer/developer-docs/DebugChecks.rst
+++ b/clang/docs/analyzer/developer-docs/DebugChecks.rst
@@ -9,6 +9,22 @@ The analyzer contains a number of checkers which can aid in debugging. Enable
 them by using the "-analyzer-checker=" flag, followed by the name of the
 checker.
 
+These checkers are especially useful when analyzing a specific function, using
+the `-analyze-function` flag. The flag accepts the function name for C code,
+like `-analyze-function=myfunction`.
+For C++ code, due to overloading, the function name must include the
+parameter list, like `-analyze-function="myfunction(int, _Bool)"`.
+
+Note that `bool` must be spelled as `_Bool` in the parameter list.
+Refer to the output of `-analyzer-display-progress` to find the fully qualified
+function name.
+
+There are cases when this name can still collide. For example with template
+function instances with non-deducible (aka. explicit) template parameters.
+In such cases, prefer passing a USR instead of a function name can resolve this
+ambiguity, like this: `-analyze-function="c:@S at Window@F at overloaded#I#"`.
+
+Use the `clang-extdef-mapping` tool to find the USR for different functions.
 
 General Analysis Dumpers
 ========================
diff --git a/clang/include/clang/CrossTU/CrossTranslationUnit.h b/clang/include/clang/CrossTU/CrossTranslationUnit.h
index e6b608a10e61b..9e0721edfc323 100644
--- a/clang/include/clang/CrossTU/CrossTranslationUnit.h
+++ b/clang/include/clang/CrossTU/CrossTranslationUnit.h
@@ -180,8 +180,8 @@ class CrossTranslationUnitContext {
   llvm::Expected<const VarDecl *> importDefinition(const VarDecl *VD,
                                                    ASTUnit *Unit);
 
-  /// Get a name to identify a named decl.
-  static std::optional<std::string> getLookupName(const NamedDecl *ND);
+  /// Get a name to identify a decl.
+  static std::optional<std::string> getLookupName(const Decl *D);
 
   /// Emit diagnostics for the user for potential configuration errors.
   void emitCrossTUDiagnostics(const IndexError &IE);
diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp
index 847913d4b03fd..0287845a741ed 100644
--- a/clang/lib/CrossTU/CrossTranslationUnit.cpp
+++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp
@@ -252,9 +252,9 @@ CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI)
 CrossTranslationUnitContext::~CrossTranslationUnitContext() {}
 
 std::optional<std::string>
-CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) {
+CrossTranslationUnitContext::getLookupName(const Decl *D) {
   SmallString<128> DeclUSR;
-  bool Ret = index::generateUSRForDecl(ND, DeclUSR);
+  bool Ret = index::generateUSRForDecl(D, DeclUSR);
   if (Ret)
     return {};
   return std::string(DeclUSR);
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 53466e7a75b0f..e9ba374851726 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -659,8 +659,11 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
 AnalysisConsumer::AnalysisMode
 AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {
   if (!Opts.AnalyzeSpecificFunction.empty() &&
-      AnalysisDeclContext::getFunctionName(D) != Opts.AnalyzeSpecificFunction)
+      AnalysisDeclContext::getFunctionName(D) != Opts.AnalyzeSpecificFunction &&
+      cross_tu::CrossTranslationUnitContext::getLookupName(D).value_or("") !=
+          Opts.AnalyzeSpecificFunction) {
     return AM_None;
+  }
 
   // Unless -analyze-all is specified, treat decls differently depending on
   // where they came from:
diff --git a/clang/test/Analysis/analyzeOneFunction.cpp b/clang/test/Analysis/analyzeOneFunction.cpp
new file mode 100644
index 0000000000000..3a362dfd9a08c
--- /dev/null
+++ b/clang/test/Analysis/analyzeOneFunction.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s \
+// RUN:   -analyze-function="Window::overloaded(int)"
+
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s \
+// RUN:   -analyze-function="c:@S at Window@F at overloaded#I#"
+
+// RUN: %clang_extdef_map %s | FileCheck %s
+// CHECK:      27:c:@S at Window@F at overloaded#I#
+// CHECK-NEXT: 27:c:@S at Window@F at overloaded#C#
+// CHECK-NEXT: 27:c:@S at Window@F at overloaded#d#
+
+void clang_analyzer_warnIfReached();
+
+struct Window {
+  void overloaded(double) { clang_analyzer_warnIfReached(); } // not analyzed, thus not reachable
+  void overloaded(char) { clang_analyzer_warnIfReached(); }   // not analyzed, thus not reachable
+  void overloaded(int) { clang_analyzer_warnIfReached(); } // expected-warning {{REACHABLE}}
+};

``````````

</details>


https://github.com/llvm/llvm-project/pull/161666


More information about the cfe-commits mailing list