Files
TheRock/compiler/amd-llvm/clang/unittests/StaticAnalyzer/UnsignedStatDemo.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

151 lines
5.3 KiB
C++

//=== UnsignedStatDemo.cpp --------------------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This checker demonstrates the use of UnsignedEPStat for per-entry-point
// statistics. It conditionally sets a statistic based on the entry point name.
//
//===----------------------------------------------------------------------===//
#include "CheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/EntryPointStats.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/MemoryBuffer.h"
#include "gtest/gtest.h"
#include <optional>
using namespace clang;
using namespace ento;
static UnsignedEPStat DemoStat("DemoStat");
namespace {
class UnsignedStatTesterChecker : public Checker<check::BeginFunction> {
public:
void checkBeginFunction(CheckerContext &C) const {
StringRef Name;
if (const Decl *D = C.getStackFrame()->getDecl())
if (const FunctionDecl *F = D->getAsFunction())
Name = F->getName();
// Conditionally set the statistic based on the function name (leaving it
// undefined for all other functions)
if (Name == "func_one")
DemoStat.set(1);
else if (Name == "func_two")
DemoStat.set(2);
else
; // For any other function (e.g., "func_none") don't set the statistic
}
};
void addUnsignedStatTesterChecker(AnalysisASTConsumer &AnalysisConsumer,
AnalyzerOptions &AnOpts) {
AnOpts.CheckersAndPackages = {{"test.DemoStatChecker", true}};
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<UnsignedStatTesterChecker>(
"test.DemoStatChecker", "DescriptionOfDemoStatChecker");
});
}
// Find the index of a column in the CSV header.
// Returns std::nullopt if the column is not found.
static std::optional<unsigned>
findColumnIndex(llvm::ArrayRef<llvm::StringRef> Header,
llvm::StringRef ColumnName) {
auto Iter = llvm::find(Header, ColumnName);
if (Iter != Header.end())
return std::distance(Header.begin(), Iter);
return std::nullopt;
}
// Parse CSV content and extract a mapping from one column to another.
// KeyColumn is used as the map key (e.g., "DebugName").
// ValueColumn is used as the map value (e.g., "DemoStat").
// Returns a map from key column values to value column values.
static llvm::StringMap<std::string>
parseCSVColumnMapping(llvm::StringRef CSVContent, llvm::StringRef KeyColumn,
llvm::StringRef ValueColumn) {
llvm::StringMap<std::string> Result;
// Parse CSV: first line is header, subsequent lines are data
llvm::SmallVector<llvm::StringRef, 8> Lines;
CSVContent.split(Lines, '\n', -1, false);
if (Lines.size() < 2) // Need at least header + one data row
return Result;
// Parse header to find column indices
llvm::SmallVector<llvm::StringRef, 32> Header;
Lines[0].split(Header, ',');
std::optional<unsigned> KeyIdx = findColumnIndex(Header, KeyColumn);
std::optional<unsigned> ValueIdx = findColumnIndex(Header, ValueColumn);
if (!KeyIdx || !ValueIdx)
return Result;
// Parse data rows and extract mappings
for (auto Line : llvm::drop_begin(Lines)) {
llvm::SmallVector<llvm::StringRef, 32> Row;
Line.split(Row, ',');
if (Row.size() <= std::max(*KeyIdx, *ValueIdx))
continue;
llvm::StringRef KeyVal = Row[*KeyIdx].trim().trim('"');
llvm::StringRef ValueVal = Row[*ValueIdx].trim().trim('"');
if (!KeyVal.empty())
Result[KeyVal] = ValueVal.str();
}
return Result;
}
TEST(UnsignedStat, ExplicitlySetUnsignedStatistic) {
llvm::SmallString<128> TempMetricsCsvPath;
std::error_code EC =
llvm::sys::fs::createTemporaryFile("ep_stats", "csv", TempMetricsCsvPath);
ASSERT_FALSE(EC);
std::vector<std::string> Args = {
"-Xclang", "-analyzer-config", "-Xclang",
std::string("dump-entry-point-stats-to-csv=") +
TempMetricsCsvPath.str().str()};
// Clean up on exit
llvm::scope_exit Cleanup(
[&]() { llvm::sys::fs::remove(TempMetricsCsvPath); });
EXPECT_TRUE(runCheckerOnCodeWithArgs<addUnsignedStatTesterChecker>(
R"cpp(
void func_one() {}
void func_two() {}
void func_none() {}
)cpp",
Args));
auto BufferOrError = llvm::MemoryBuffer::getFile(TempMetricsCsvPath);
ASSERT_TRUE(BufferOrError);
llvm::StringRef CSVContent = BufferOrError.get()->getBuffer();
// Parse the CSV and extract function statistics
llvm::StringMap<std::string> FunctionStats =
parseCSVColumnMapping(CSVContent, "DebugName", "DemoStat");
// Verify the expected values
ASSERT_TRUE(FunctionStats.count("func_one()"));
EXPECT_EQ(FunctionStats["func_one()"], "1");
ASSERT_TRUE(FunctionStats.count("func_two()"));
EXPECT_EQ(FunctionStats["func_two()"], "2");
ASSERT_TRUE(FunctionStats.count("func_none()"));
EXPECT_EQ(FunctionStats["func_none()"], ""); // Not set, should be empty
}
} // namespace