================
@@ -0,0 +1,102 @@
+//===- EntityPointerLevelTest.cpp 
-----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include 
"clang/ScalableStaticAnalysis/Analyses/EntityPointerLevel/EntityPointerLevel.h"
+#include "FindDecl.h"
+#include "clang/AST/Decl.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <memory>
+#include <vector>
+
+using namespace clang;
+using namespace ssaf;
+using testing::ElementsAre;
+
+namespace {
+
+static std::vector<unsigned> levelsOf(const DeclPointerLevels &DPLs) {
+  std::vector<unsigned> Levels;
+  for (const DeclPointerLevel &DPL : DPLs)
+    Levels.push_back(DPL.PointerLevel);
+  return Levels;
+}
+
+// `elaborateHigherDeclPointerLevels` expands a DeclPointerLevel into an
+// ascending, exhaustive vector of DeclPointerLevels for the same declaration,
+// from the given level up to the maximum pointer level of the declared type.
+TEST(EntityPointerLevelTest, ElaborateHigherDeclPointerLevels) {
+  std::unique_ptr<ASTUnit> AST =
+      tooling::buildASTFromCodeWithArgs(R"cpp(
+    int *p;         // one pointer level
+    int **q;        // two pointer levels
+    int ***r;       // three pointer levels
+    int *arr[10];   // array of pointers: two levels (array + pointer)
+  )cpp",
+                                        {"-Wno-unused"});
+  ASSERT_TRUE(AST);
+  ASTContext &Ctx = AST->getASTContext();
+
+  // Elaborate the decl named `Name` starting at `StartLevel`, checking that
+  // every result shares the input's declaration and is-return flag, and return
+  // the produced pointer levels.
+  auto elaborate = [&](StringRef Name, unsigned StartLevel) {
+    const NamedDecl *ND = findDeclByName(Name, Ctx);
+    EXPECT_NE(ND, nullptr) << "decl not found: " << Name.str();
+    if (!ND)
+      return std::vector<unsigned>{};
+    DeclPointerLevels DPLs = elaborateHigherDeclPointerLevels(
+        DeclPointerLevel{ND, StartLevel, /*IsReturn=*/false});
+    for (const DeclPointerLevel &DPL : DPLs) {
+      EXPECT_TRUE(DPL.Decl == ND);
+      EXPECT_FALSE(DPL.IsReturn);
+    }
+    return levelsOf(DPLs);
+  };
+
+  EXPECT_THAT(elaborate("p", 1), ElementsAre(1U));         // int*
+  EXPECT_THAT(elaborate("q", 1), ElementsAre(1U, 2U));     // int**
+  EXPECT_THAT(elaborate("r", 1), ElementsAre(1U, 2U, 3U)); // int***
+  EXPECT_THAT(elaborate("arr", 1), ElementsAre(1U, 2U));   // int*[10]
+  EXPECT_THAT(elaborate("r", 2), ElementsAre(2U, 3U));
+  EXPECT_THAT(elaborate("r", 3), ElementsAre(3U));
+}
+
+// For a function entity (IsReturn=true), the maximum pointer level is bounded
+// by the return type, whose reference must be stripped first.
+TEST(EntityPointerLevelTest, ElaborateHigherDeclPointerLevelsForReturn) {
+  std::unique_ptr<ASTUnit> AST =
+      tooling::buildASTFromCodeWithArgs(R"cpp(
+    int **&refret();  // reference to int**: two pointer levels
+    int *valret();    // int*: one pointer level
+  )cpp",
+                                        {"-Wno-unused"});
+  ASSERT_TRUE(AST);
+  ASTContext &Ctx = AST->getASTContext();
+
+  auto elaborateReturn = [&](StringRef Name, unsigned StartLevel) {
+    const FunctionDecl *FD = findFnByName(Name, Ctx);
+    EXPECT_NE(FD, nullptr) << "function not found: " << Name.str();
+    if (!FD)
+      return std::vector<unsigned>{};
+    DeclPointerLevels DPLs = elaborateHigherDeclPointerLevels(
+        DeclPointerLevel{FD, StartLevel, /*IsReturn=*/true});
+    for (const DeclPointerLevel &DPL : DPLs) {
+      EXPECT_TRUE(DPL.Decl == FD);
+      EXPECT_TRUE(DPL.IsReturn);
+    }
+    return levelsOf(DPLs);
+  };
----------------
steakhal wrote:

Isn't this largely the same across the two functions? Can we hoist it into a 
static helper function?

I can see now that this differs in the `IsReturn` alright.

https://github.com/llvm/llvm-project/pull/218196
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to