Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[clang][dataflow] Change diagnoseFunction to use llvm::SmallVector instead of std::vector. #66014

Merged
merged 1 commit into from
Sep 13, 2023

Conversation

ymand
Copy link
Collaborator

@ymand ymand commented Sep 11, 2023

The template is agnostic as to the type used by the list, as long as it is
compatible with llvm::move and std::back_inserter. In practice, we've
encountered analyses which use different types (llvm::SmallVector vs
std::vector), so it seems preferable to leave this open to the caller.

@ymand ymand requested review from a team as code owners September 11, 2023 21:46
@llvmbot llvmbot added clang Clang issues not falling into any other category clang-tidy clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang:analysis labels Sep 11, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Sep 11, 2023

@llvm/pr-subscribers-clang-analysis

Changes

The template is agnostic as to the type used by the list, as long as it is
compatible with llvm::move and std::back_inserter. In practice, we've
encountered analyses which use different types (llvm::SmallVector vs
std::vector), so it seems preferable to leave this open to the caller.

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

3 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp (+2-2)
  • (modified) clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h (+4-4)
  • (modified) clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp (+2-2)
diff --git a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
index 183beb6bfb87d80..5811e2a4cd02266 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
@@ -56,8 +56,8 @@ void UncheckedOptionalAccessCheck::check(
   // `diagnoseFunction` with config options.
   if (llvm::Expected> Locs =
           dataflow::diagnoseFunction(*FuncDecl, *Result.Context,
-                                                     Diagnoser))
+                                     std::vector>(
+              *FuncDecl, *Result.Context, Diagnoser))
     for (const SourceLocation &Loc : *Locs)
       diag(Loc, "unchecked access to optional value");
   else
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
index abd34f40922121e..fd2d7fce09073bf 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
@@ -245,10 +245,10 @@ runDataflowAnalysis(
 ///   iterations.
 /// - This limit is still low enough to keep runtimes acceptable (on typical
 ///   machines) in cases where we hit the limit.
-template 
-llvm::Expected> diagnoseFunction(
+template 
+llvm::Expected diagnoseFunction(
     const FunctionDecl &FuncDecl, ASTContext &ASTCtx,
-    llvm::function_ref(
+    llvm::function_ref &)>
         Diagnoser,
@@ -263,7 +263,7 @@ llvm::Expected> diagnoseFunction(
   DataflowAnalysisContext AnalysisContext(std::move(OwnedSolver));
   Environment Env(AnalysisContext, FuncDecl);
   AnalysisT Analysis(ASTCtx);
-  std::vector Diagnostics;
+  DiagnosticList Diagnostics;
   if (llvm::Error Err =
           runTypeErasedDataflowAnalysis(
               *Context, Analysis, Env,
diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
index af34a2afd24685a..3a8253508016caa 100644
--- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
@@ -98,12 +98,12 @@ TEST(DataflowAnalysisTest, DiagnoseFunctionDiagnoserCalledOnEachElement) {
       cast(findValueDecl(AST->getASTContext(), "target"));
   auto Diagnoser = [](const CFGElement &Elt, ASTContext &,
                       const TransferStateForDiagnostics &) {
-    std::vector Diagnostics(1);
+    llvm::SmallVector Diagnostics(1);
     llvm::raw_string_ostream OS(Diagnostics.front());
     Elt.dumpToStream(OS);
     return Diagnostics;
   };
-  auto Result = diagnoseFunction(
+  auto Result = diagnoseFunction>(
       *Func, AST->getASTContext(), Diagnoser);
   // `diagnoseFunction` provides no guarantees about the order in which elements
   // are visited, so we use `UnorderedElementsAre`.

@llvmbot
Copy link
Collaborator

llvmbot commented Sep 11, 2023

@llvm/pr-subscribers-clang

Changes

The template is agnostic as to the type used by the list, as long as it is
compatible with llvm::move and std::back_inserter. In practice, we've
encountered analyses which use different types (llvm::SmallVector vs
std::vector), so it seems preferable to leave this open to the caller.

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

3 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp (+2-2)
  • (modified) clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h (+4-4)
  • (modified) clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp (+2-2)
diff --git a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
index 183beb6bfb87d80..5811e2a4cd02266 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
@@ -56,8 +56,8 @@ void UncheckedOptionalAccessCheck::check(
   // `diagnoseFunction` with config options.
   if (llvm::Expected> Locs =
           dataflow::diagnoseFunction(*FuncDecl, *Result.Context,
-                                                     Diagnoser))
+                                     std::vector>(
+              *FuncDecl, *Result.Context, Diagnoser))
     for (const SourceLocation &Loc : *Locs)
       diag(Loc, "unchecked access to optional value");
   else
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
index abd34f40922121e..fd2d7fce09073bf 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
@@ -245,10 +245,10 @@ runDataflowAnalysis(
 ///   iterations.
 /// - This limit is still low enough to keep runtimes acceptable (on typical
 ///   machines) in cases where we hit the limit.
-template 
-llvm::Expected> diagnoseFunction(
+template 
+llvm::Expected diagnoseFunction(
     const FunctionDecl &FuncDecl, ASTContext &ASTCtx,
-    llvm::function_ref(
+    llvm::function_ref &)>
         Diagnoser,
@@ -263,7 +263,7 @@ llvm::Expected> diagnoseFunction(
   DataflowAnalysisContext AnalysisContext(std::move(OwnedSolver));
   Environment Env(AnalysisContext, FuncDecl);
   AnalysisT Analysis(ASTCtx);
-  std::vector Diagnostics;
+  DiagnosticList Diagnostics;
   if (llvm::Error Err =
           runTypeErasedDataflowAnalysis(
               *Context, Analysis, Env,
diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
index af34a2afd24685a..3a8253508016caa 100644
--- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
@@ -98,12 +98,12 @@ TEST(DataflowAnalysisTest, DiagnoseFunctionDiagnoserCalledOnEachElement) {
       cast(findValueDecl(AST->getASTContext(), "target"));
   auto Diagnoser = [](const CFGElement &Elt, ASTContext &,
                       const TransferStateForDiagnostics &) {
-    std::vector Diagnostics(1);
+    llvm::SmallVector Diagnostics(1);
     llvm::raw_string_ostream OS(Diagnostics.front());
     Elt.dumpToStream(OS);
     return Diagnostics;
   };
-  auto Result = diagnoseFunction(
+  auto Result = diagnoseFunction>(
       *Func, AST->getASTContext(), Diagnoser);
   // `diagnoseFunction` provides no guarantees about the order in which elements
   // are visited, so we use `UnorderedElementsAre`.

@llvmbot
Copy link
Collaborator

llvmbot commented Sep 11, 2023

@llvm/pr-subscribers-clang-tidy

Changes

The template is agnostic as to the type used by the list, as long as it is
compatible with llvm::move and std::back_inserter. In practice, we've
encountered analyses which use different types (llvm::SmallVector vs
std::vector), so it seems preferable to leave this open to the caller.

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

3 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp (+2-2)
  • (modified) clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h (+4-4)
  • (modified) clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp (+2-2)
diff --git a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
index 183beb6bfb87d80..5811e2a4cd02266 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
@@ -56,8 +56,8 @@ void UncheckedOptionalAccessCheck::check(
   // `diagnoseFunction` with config options.
   if (llvm::Expected> Locs =
           dataflow::diagnoseFunction(*FuncDecl, *Result.Context,
-                                                     Diagnoser))
+                                     std::vector>(
+              *FuncDecl, *Result.Context, Diagnoser))
     for (const SourceLocation &Loc : *Locs)
       diag(Loc, "unchecked access to optional value");
   else
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
index abd34f40922121e..fd2d7fce09073bf 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
@@ -245,10 +245,10 @@ runDataflowAnalysis(
 ///   iterations.
 /// - This limit is still low enough to keep runtimes acceptable (on typical
 ///   machines) in cases where we hit the limit.
-template 
-llvm::Expected> diagnoseFunction(
+template 
+llvm::Expected diagnoseFunction(
     const FunctionDecl &FuncDecl, ASTContext &ASTCtx,
-    llvm::function_ref(
+    llvm::function_ref &)>
         Diagnoser,
@@ -263,7 +263,7 @@ llvm::Expected> diagnoseFunction(
   DataflowAnalysisContext AnalysisContext(std::move(OwnedSolver));
   Environment Env(AnalysisContext, FuncDecl);
   AnalysisT Analysis(ASTCtx);
-  std::vector Diagnostics;
+  DiagnosticList Diagnostics;
   if (llvm::Error Err =
           runTypeErasedDataflowAnalysis(
               *Context, Analysis, Env,
diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
index af34a2afd24685a..3a8253508016caa 100644
--- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
@@ -98,12 +98,12 @@ TEST(DataflowAnalysisTest, DiagnoseFunctionDiagnoserCalledOnEachElement) {
       cast(findValueDecl(AST->getASTContext(), "target"));
   auto Diagnoser = [](const CFGElement &Elt, ASTContext &,
                       const TransferStateForDiagnostics &) {
-    std::vector Diagnostics(1);
+    llvm::SmallVector Diagnostics(1);
     llvm::raw_string_ostream OS(Diagnostics.front());
     Elt.dumpToStream(OS);
     return Diagnostics;
   };
-  auto Result = diagnoseFunction(
+  auto Result = diagnoseFunction>(
       *Func, AST->getASTContext(), Diagnoser);
   // `diagnoseFunction` provides no guarantees about the order in which elements
   // are visited, so we use `UnorderedElementsAre`.

Copy link
Collaborator

@Xazax-hun Xazax-hun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@martinboehme
Copy link
Contributor

I'm not convinced of the value of this change. Wouldn't it be simpler to keep the template arguments of diagnoseFunction() unchanged and instead change the return type to be llvm::Expected<llvm::SmallVector<Diagnostic>>? In other words, always return an llvm::SmallVector instead of a std::vector?

I think llvm::SmallVector makes sense for both callsites that currently exist (and ones that we might add in the future). This patch currently lets UncheckedOptionalAccessCheck::check() continue to use std::vector, but I think llvm::SmallVector makes sense there as well, as in the common case, we expect only a small number of diagnostics or none at all. This seems like it would be true for any function that wants to call diagnoseFunction() in the future as well.

@ymand
Copy link
Collaborator Author

ymand commented Sep 12, 2023

I think llvm::SmallVector makes sense for both callsites that currently exist (and ones that we might add in the future). This patch currently lets UncheckedOptionalAccessCheck::check() continue to use std::vector, but I think llvm::SmallVector makes sense there as well, as in the common case, we expect only a small number of diagnostics or none at all. This seems like it would be true for any function that wants to call diagnoseFunction() in the future as well.

FWIW, I also plan to followup with exactly that change to UncheckedOptionalAccessCheck -- I just didn't think it belonged grouped with this one.

@ymand
Copy link
Collaborator Author

ymand commented Sep 12, 2023

Updated to enforce llvm::SmallVector, per Martin's recommendation. PTAL.

@martinboehme
Copy link
Contributor

Updated to enforce llvm::SmallVector, per Martin's recommendation. PTAL.

LGTM, but note that the PR title is now out of date.

@ymand ymand changed the title [clang][dataflow] Change diagnoseFunction to take type of diagnostic list instead of diagnostic itself. [clang][dataflow] Change diagnoseFunction to use llvm::SmallVector instead of std::vector. Sep 13, 2023
…` instead of `std::vector`.

The template is agnostic as to the type used by the list, as long as it is
compatible with `llvm::move` and `std::back_inserter`. `llvm::SmallVector` seems
generally more appropriate than `std::vector` in this context, so we set that as
the expected list type.
@ymand ymand merged commit 004a7ce into llvm:main Sep 13, 2023
1 of 2 checks passed
ZijunZhaoCCK pushed a commit to ZijunZhaoCCK/llvm-project that referenced this pull request Sep 19, 2023
…` instead of `std::vector`. (llvm#66014)

The template is agnostic as to the type used by the list, as long as it
is
compatible with `llvm::move` and `std::back_inserter`. In practice,
we've
encountered analyses which use different types (`llvm::SmallVector` vs
`std::vector`), so it seems preferable to leave this open to the caller.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:analysis clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang Clang issues not falling into any other category clang-tidy
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants