https://github.com/jkorous-apple created https://github.com/llvm/llvm-project/pull/204214
Introduces the abstract base classes, registries, and force-linker anchor for the SSAF source-transformation library. A `Transformation` is an `ASTConsumer` that consumes a previously computed `WPASuite` and emits source edits and findings through two sinks: `SourceEditEmitter` (accumulates `clang::tooling::Replacement`s) and `TransformationReportEmitter` (accumulates `(ruleId, level, range, message)` tuples). The accumulated state is then handed to a `SourceEditFormat` and a `TransformationReportFormat` for serialization. Three `llvm::Registry`-backed registries — keyed by transformation name and by file extension respectively — let transformations and formats be linked in statically (with a force-linker anchor) or loaded dynamically as a clang plugin. Each registry exposes the standard `is*Registered` / `make*` / `printAvailable*` helpers used elsewhere in SSAF. No transformation or format ships yet; this commit only adds the plumbing. Existing tools (`clang-ssaf-format`, `clang-ssaf-linker`, `clang-ssaf-analyzer`) and the clang driver gain the new lib in their link line so the framework anchor resolves under static linking. Assisted-By: Claude Opus 4.7 >From 577a6f69afd9d3aa4745a9a0974ef1b010bc8df5 Mon Sep 17 00:00:00 2001 From: Jan Korous <[email protected]> Date: Fri, 12 Jun 2026 19:15:00 -0700 Subject: [PATCH] [clang][ssaf] Add source-transformation library scaffolding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces the abstract base classes, registries, and force-linker anchor for the SSAF source-transformation library. A `Transformation` is an `ASTConsumer` that consumes a previously computed `WPASuite` and emits source edits and findings through two sinks: `SourceEditEmitter` (accumulates `clang::tooling::Replacement`s) and `TransformationReportEmitter` (accumulates `(ruleId, level, range, message)` tuples). The accumulated state is then handed to a `SourceEditFormat` and a `TransformationReportFormat` for serialization. Three `llvm::Registry`-backed registries — keyed by transformation name and by file extension respectively — let transformations and formats be linked in statically (with a force-linker anchor) or loaded dynamically as a clang plugin. Each registry exposes the standard `is*Registered` / `make*` / `printAvailable*` helpers used elsewhere in SSAF. No transformation or format ships yet; this commit only adds the plumbing. Existing tools (`clang-ssaf-format`, `clang-ssaf-linker`, `clang-ssaf-analyzer`) and the clang driver gain the new lib in their link line so the framework anchor resolves under static linking. Assisted-By: Claude Opus 4.7 --- .../BuiltinAnchorSources.def | 1 + .../SourceTransformation/SourceEditEmitter.h | 29 +++++++ .../SourceTransformation/Transformation.h | 38 +++++++++ .../TransformationRegistry.h | 66 +++++++++++++++ .../TransformationReportEmitter.h | 35 ++++++++ clang/lib/Driver/CMakeLists.txt | 1 + clang/lib/FrontendTool/CMakeLists.txt | 1 + .../CMakeLists.txt | 1 + .../SourceTransformation/CMakeLists.txt | 13 +++ .../TransformationRegistry.cpp | 44 ++++++++++ .../tools/clang-ssaf-analyzer/CMakeLists.txt | 1 + clang/tools/clang-ssaf-format/CMakeLists.txt | 1 + clang/tools/clang-ssaf-linker/CMakeLists.txt | 1 + .../CMakeLists.txt | 4 + .../SourceTransformation/EmitterTest.cpp | 81 +++++++++++++++++++ .../SourceTransformation/RegistryTest.cpp | 78 ++++++++++++++++++ 16 files changed, 395 insertions(+) create mode 100644 clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/SourceEditEmitter.h create mode 100644 clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/Transformation.h create mode 100644 clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/TransformationRegistry.h create mode 100644 clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/TransformationReportEmitter.h create mode 100644 clang/lib/ScalableStaticAnalysisFramework/SourceTransformation/CMakeLists.txt create mode 100644 clang/lib/ScalableStaticAnalysisFramework/SourceTransformation/TransformationRegistry.cpp create mode 100644 clang/unittests/ScalableStaticAnalysisFramework/SourceTransformation/EmitterTest.cpp create mode 100644 clang/unittests/ScalableStaticAnalysisFramework/SourceTransformation/RegistryTest.cpp diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/BuiltinAnchorSources.def b/clang/include/clang/ScalableStaticAnalysisFramework/BuiltinAnchorSources.def index 7dd866047f556..ba4944ea984cb 100644 --- a/clang/include/clang/ScalableStaticAnalysisFramework/BuiltinAnchorSources.def +++ b/clang/include/clang/ScalableStaticAnalysisFramework/BuiltinAnchorSources.def @@ -23,6 +23,7 @@ ANCHOR(JSONFormatAnchorSource) ANCHOR(PointerFlowAnalysisAnchorSource) ANCHOR(PointerFlowExtractorAnchorSource) ANCHOR(PointerFlowJSONFormatAnchorSource) +ANCHOR(SSAFSourceTransformationAnchorSource) ANCHOR(UnsafeBufferUsageAnalysisAnchorSource) ANCHOR(UnsafeBufferUsageExtractorAnchorSource) ANCHOR(UnsafeBufferUsageJSONFormatAnchorSource) diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/SourceEditEmitter.h b/clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/SourceEditEmitter.h new file mode 100644 index 0000000000000..e96c9846a35f2 --- /dev/null +++ b/clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/SourceEditEmitter.h @@ -0,0 +1,29 @@ +//===- SourceEditEmitter.h --------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Abstract accumulator for source edits. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_SOURCETRANSFORMATION_SOURCEEDITEMITTER_H +#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_SOURCETRANSFORMATION_SOURCEEDITEMITTER_H + +#include "clang/Tooling/Core/Replacement.h" + +namespace clang::ssaf { + +class SourceEditEmitter { +public: + virtual ~SourceEditEmitter() = default; + + virtual void addReplacement(clang::tooling::Replacement R) = 0; +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_SOURCETRANSFORMATION_SOURCEEDITEMITTER_H diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/Transformation.h b/clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/Transformation.h new file mode 100644 index 0000000000000..5553b7796b1ad --- /dev/null +++ b/clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/Transformation.h @@ -0,0 +1,38 @@ +//===- Transformation.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Abstract base class for source transformations. A Transformation is an +// ASTConsumer that consumes a previously computed WPASuite. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_SOURCETRANSFORMATION_TRANSFORMATION_H +#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_SOURCETRANSFORMATION_TRANSFORMATION_H + +#include "clang/AST/ASTConsumer.h" +#include "clang/ScalableStaticAnalysisFramework/Core/WholeProgramAnalysis/WPASuite.h" +#include "clang/ScalableStaticAnalysisFramework/SourceTransformation/SourceEditEmitter.h" +#include "clang/ScalableStaticAnalysisFramework/SourceTransformation/TransformationReportEmitter.h" + +namespace clang::ssaf { + +class Transformation : public clang::ASTConsumer { +public: + Transformation(const WPASuite &Suite, SourceEditEmitter &Edits, + TransformationReportEmitter &Report) + : Suite(Suite), Edits(Edits), Report(Report) {} + +protected: + const WPASuite &Suite; + SourceEditEmitter &Edits; + TransformationReportEmitter &Report; +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_SOURCETRANSFORMATION_TRANSFORMATION_H diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/TransformationRegistry.h b/clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/TransformationRegistry.h new file mode 100644 index 0000000000000..231a810f60f26 --- /dev/null +++ b/clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/TransformationRegistry.h @@ -0,0 +1,66 @@ +//===- TransformationRegistry.h ---------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Registry for Transformations, and some helper functions. +// To register a transformation, insert this code: +// +// namespace clang::ssaf { +// // NOLINTNEXTLINE(misc-use-internal-linkage) +// volatile int MyTransformationAnchorSource = 0; +// } // namespace clang::ssaf +// static TransformationRegistry::Add<MyTransformation> +// X("MyTransformation", "My awesome transformation"); +// +// For a statically-linked transformation also extend the `AnchorSources` +// list in +// clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h +// (plugin-loaded transformations do not need an anchor — the dynamic loader +// runs every global ctor on load). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_SOURCETRANSFORMATION_TRANSFORMATIONREGISTRY_H +#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_SOURCETRANSFORMATION_TRANSFORMATIONREGISTRY_H + +#include "clang/ScalableStaticAnalysisFramework/Core/WholeProgramAnalysis/WPASuite.h" +#include "clang/ScalableStaticAnalysisFramework/SourceTransformation/SourceEditEmitter.h" +#include "clang/ScalableStaticAnalysisFramework/SourceTransformation/Transformation.h" +#include "clang/ScalableStaticAnalysisFramework/SourceTransformation/TransformationReportEmitter.h" +#include "clang/Support/Compiler.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Registry.h" +#include "llvm/Support/raw_ostream.h" +#include <memory> + +namespace clang::ssaf { + +/// Check if a Transformation was registered with a given name. +bool isTransformationRegistered(llvm::StringRef Name); + +/// Try to instantiate a Transformation with a given name. +/// This might return null if the construction of the desired Transformation +/// failed. +/// It's a fatal error if there is no transformation registered with the name. +std::unique_ptr<Transformation> +makeTransformation(llvm::StringRef Name, const WPASuite &Suite, + SourceEditEmitter &Edits, + TransformationReportEmitter &Report); + +/// Print the list of available Transformations. +void printAvailableTransformations(llvm::raw_ostream &OS); + +// Registry for adding new Transformation implementations. +using TransformationRegistry = + llvm::Registry<Transformation, const WPASuite &, SourceEditEmitter &, + TransformationReportEmitter &>; + +} // namespace clang::ssaf + +LLVM_DECLARE_REGISTRY(clang::ssaf::TransformationRegistry) + +#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_SOURCETRANSFORMATION_TRANSFORMATIONREGISTRY_H diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/TransformationReportEmitter.h b/clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/TransformationReportEmitter.h new file mode 100644 index 0000000000000..c48a35009c034 --- /dev/null +++ b/clang/include/clang/ScalableStaticAnalysisFramework/SourceTransformation/TransformationReportEmitter.h @@ -0,0 +1,35 @@ +//===- TransformationReportEmitter.h ----------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Abstract accumulator for the transformation report. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_SOURCETRANSFORMATION_TRANSFORMATIONREPORTEMITTER_H +#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_SOURCETRANSFORMATION_TRANSFORMATIONREPORTEMITTER_H + +#include "clang/Basic/Sarif.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/StringRef.h" + +namespace clang::ssaf { + +class TransformationReportEmitter { +public: + virtual ~TransformationReportEmitter() = default; + + /// An invalid \p Range signals "no location"; the format writer drops the + /// location object entirely rather than fabricating a placeholder. + virtual void addResult(llvm::StringRef RuleId, clang::SarifResultLevel Level, + clang::CharSourceRange Range, + llvm::StringRef Message) = 0; +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_SOURCETRANSFORMATION_TRANSFORMATIONREPORTEMITTER_H diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt index 5fe10052d267f..cd410899c450f 100644 --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -115,6 +115,7 @@ add_clang_library(clangDriver clangScalableStaticAnalysisFrameworkAnalyses clangScalableStaticAnalysisFrameworkCore clangScalableStaticAnalysisFrameworkFrontend + clangScalableStaticAnalysisFrameworkSourceTransformation clangSerialization clangLex clangOptions diff --git a/clang/lib/FrontendTool/CMakeLists.txt b/clang/lib/FrontendTool/CMakeLists.txt index 24623303e6bdb..543aa06090ec8 100644 --- a/clang/lib/FrontendTool/CMakeLists.txt +++ b/clang/lib/FrontendTool/CMakeLists.txt @@ -7,6 +7,7 @@ set(link_libs clangScalableStaticAnalysisFrameworkAnalyses clangScalableStaticAnalysisFrameworkCore clangScalableStaticAnalysisFrameworkFrontend + clangScalableStaticAnalysisFrameworkSourceTransformation clangBasic clangCodeGen clangDriver diff --git a/clang/lib/ScalableStaticAnalysisFramework/CMakeLists.txt b/clang/lib/ScalableStaticAnalysisFramework/CMakeLists.txt index e09c44b7cfd52..b214c06644db7 100644 --- a/clang/lib/ScalableStaticAnalysisFramework/CMakeLists.txt +++ b/clang/lib/ScalableStaticAnalysisFramework/CMakeLists.txt @@ -2,4 +2,5 @@ add_subdirectory(Analyses) add_subdirectory(Core) add_subdirectory(Frontend) add_subdirectory(Plugins) +add_subdirectory(SourceTransformation) add_subdirectory(Tool) diff --git a/clang/lib/ScalableStaticAnalysisFramework/SourceTransformation/CMakeLists.txt b/clang/lib/ScalableStaticAnalysisFramework/SourceTransformation/CMakeLists.txt new file mode 100644 index 0000000000000..c96a386977487 --- /dev/null +++ b/clang/lib/ScalableStaticAnalysisFramework/SourceTransformation/CMakeLists.txt @@ -0,0 +1,13 @@ +set(LLVM_LINK_COMPONENTS + Support + ) + +add_clang_library(clangScalableStaticAnalysisFrameworkSourceTransformation + TransformationRegistry.cpp + + LINK_LIBS + clangAST + clangBasic + clangScalableStaticAnalysisFrameworkCore + clangToolingCore + ) diff --git a/clang/lib/ScalableStaticAnalysisFramework/SourceTransformation/TransformationRegistry.cpp b/clang/lib/ScalableStaticAnalysisFramework/SourceTransformation/TransformationRegistry.cpp new file mode 100644 index 0000000000000..9d770c8bcd0f9 --- /dev/null +++ b/clang/lib/ScalableStaticAnalysisFramework/SourceTransformation/TransformationRegistry.cpp @@ -0,0 +1,44 @@ +//===- TransformationRegistry.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/ScalableStaticAnalysisFramework/SourceTransformation/TransformationRegistry.h" +#include <memory> + +using namespace clang; +using namespace ssaf; + +namespace clang::ssaf { +// NOLINTNEXTLINE(misc-use-internal-linkage) +volatile int SSAFSourceTransformationAnchorSource = 0; +} // namespace clang::ssaf + +LLVM_DEFINE_REGISTRY(clang::ssaf::TransformationRegistry) + +bool ssaf::isTransformationRegistered(llvm::StringRef Name) { + for (const auto &Entry : TransformationRegistry::entries()) + if (Entry.getName() == Name) + return true; + return false; +} + +std::unique_ptr<Transformation> +ssaf::makeTransformation(llvm::StringRef Name, const WPASuite &Suite, + SourceEditEmitter &Edits, + TransformationReportEmitter &Report) { + for (const auto &Entry : TransformationRegistry::entries()) + if (Entry.getName() == Name) + return Entry.instantiate(Suite, Edits, Report); + assert(false && "Unknown Transformation name"); + return nullptr; +} + +void ssaf::printAvailableTransformations(llvm::raw_ostream &OS) { + OS << "OVERVIEW: Available SSAF source transformations:\n\n"; + for (const auto &Entry : TransformationRegistry::entries()) + OS << " " << Entry.getName() << " - " << Entry.getDesc() << "\n"; +} diff --git a/clang/tools/clang-ssaf-analyzer/CMakeLists.txt b/clang/tools/clang-ssaf-analyzer/CMakeLists.txt index 67732867181b6..d58ec773ff04b 100644 --- a/clang/tools/clang-ssaf-analyzer/CMakeLists.txt +++ b/clang/tools/clang-ssaf-analyzer/CMakeLists.txt @@ -17,6 +17,7 @@ clang_target_link_libraries(clang-ssaf-analyzer clangBasic clangScalableStaticAnalysisFrameworkAnalyses clangScalableStaticAnalysisFrameworkCore + clangScalableStaticAnalysisFrameworkSourceTransformation clangScalableStaticAnalysisFrameworkTool ) diff --git a/clang/tools/clang-ssaf-format/CMakeLists.txt b/clang/tools/clang-ssaf-format/CMakeLists.txt index 33ce432be3f4a..5d7a6c70c73fb 100644 --- a/clang/tools/clang-ssaf-format/CMakeLists.txt +++ b/clang/tools/clang-ssaf-format/CMakeLists.txt @@ -17,6 +17,7 @@ clang_target_link_libraries(clang-ssaf-format clangBasic clangScalableStaticAnalysisFrameworkAnalyses clangScalableStaticAnalysisFrameworkCore + clangScalableStaticAnalysisFrameworkSourceTransformation clangScalableStaticAnalysisFrameworkTool ) diff --git a/clang/tools/clang-ssaf-linker/CMakeLists.txt b/clang/tools/clang-ssaf-linker/CMakeLists.txt index af65aaa3b1aeb..89d72a45a734e 100644 --- a/clang/tools/clang-ssaf-linker/CMakeLists.txt +++ b/clang/tools/clang-ssaf-linker/CMakeLists.txt @@ -12,5 +12,6 @@ clang_target_link_libraries(clang-ssaf-linker clangBasic clangScalableStaticAnalysisFrameworkAnalyses clangScalableStaticAnalysisFrameworkCore + clangScalableStaticAnalysisFrameworkSourceTransformation clangScalableStaticAnalysisFrameworkTool ) diff --git a/clang/unittests/ScalableStaticAnalysisFramework/CMakeLists.txt b/clang/unittests/ScalableStaticAnalysisFramework/CMakeLists.txt index e852d99d34781..8090ea96cbd5c 100644 --- a/clang/unittests/ScalableStaticAnalysisFramework/CMakeLists.txt +++ b/clang/unittests/ScalableStaticAnalysisFramework/CMakeLists.txt @@ -24,6 +24,8 @@ add_distinct_clang_unittest(ClangScalableAnalysisTests Serialization/JSONFormatTest/JSONFormatTest.cpp Serialization/JSONFormatTest/LUSummaryTest.cpp Serialization/JSONFormatTest/TUSummaryTest.cpp + SourceTransformation/EmitterTest.cpp + SourceTransformation/RegistryTest.cpp SummaryData/SummaryDataTest.cpp SummaryNameTest.cpp TestFixture.cpp @@ -39,8 +41,10 @@ add_distinct_clang_unittest(ClangScalableAnalysisTests clangScalableStaticAnalysisFrameworkAnalyses clangScalableStaticAnalysisFrameworkCore clangScalableStaticAnalysisFrameworkFrontend + clangScalableStaticAnalysisFrameworkSourceTransformation clangSerialization clangTooling + clangToolingCore LINK_LIBS LLVMTestingSupport diff --git a/clang/unittests/ScalableStaticAnalysisFramework/SourceTransformation/EmitterTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/SourceTransformation/EmitterTest.cpp new file mode 100644 index 0000000000000..d730c6c337c45 --- /dev/null +++ b/clang/unittests/ScalableStaticAnalysisFramework/SourceTransformation/EmitterTest.cpp @@ -0,0 +1,81 @@ +//===- EmitterTest.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/Basic/Sarif.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/ScalableStaticAnalysisFramework/SourceTransformation/SourceEditEmitter.h" +#include "clang/ScalableStaticAnalysisFramework/SourceTransformation/TransformationReportEmitter.h" +#include "gtest/gtest.h" +#include <vector> + +using namespace llvm; +using namespace clang; +using namespace ssaf; + +namespace { + +class RecordingEditEmitter : public SourceEditEmitter { +public: + std::vector<clang::tooling::Replacement> Replacements; + + void addReplacement(clang::tooling::Replacement R) override { + Replacements.push_back(std::move(R)); + } +}; + +class RecordingReportEmitter : public TransformationReportEmitter { +public: + struct Entry { + std::string RuleId; + clang::SarifResultLevel Level; + clang::CharSourceRange Range; + std::string Message; + }; + std::vector<Entry> Results; + + void addResult(StringRef RuleId, clang::SarifResultLevel Level, + clang::CharSourceRange Range, StringRef Message) override { + Results.push_back({RuleId.str(), Level, Range, Message.str()}); + } +}; + +TEST(SourceEditEmitterTest, AccumulatesInOrder) { + RecordingEditEmitter E; + E.addReplacement(clang::tooling::Replacement("a.cpp", 0, 0, "// 1")); + E.addReplacement(clang::tooling::Replacement("a.cpp", 10, 0, "// 2")); + ASSERT_EQ(E.Replacements.size(), 2u); + EXPECT_EQ(E.Replacements[0].getReplacementText(), "// 1"); + EXPECT_EQ(E.Replacements[1].getReplacementText(), "// 2"); + EXPECT_EQ(E.Replacements[0].getOffset(), 0u); + EXPECT_EQ(E.Replacements[1].getOffset(), 10u); +} + +TEST(TransformationReportEmitterTest, AccumulatesInOrder) { + RecordingReportEmitter R; + R.addResult("rule-a", clang::SarifResultLevel::Note, clang::CharSourceRange{}, + "first"); + R.addResult("rule-b", clang::SarifResultLevel::Warning, + clang::CharSourceRange{}, "second"); + ASSERT_EQ(R.Results.size(), 2u); + EXPECT_EQ(R.Results[0].RuleId, "rule-a"); + EXPECT_EQ(R.Results[0].Level, clang::SarifResultLevel::Note); + EXPECT_EQ(R.Results[0].Message, "first"); + EXPECT_EQ(R.Results[1].RuleId, "rule-b"); + EXPECT_EQ(R.Results[1].Level, clang::SarifResultLevel::Warning); + EXPECT_EQ(R.Results[1].Message, "second"); +} + +TEST(TransformationReportEmitterTest, AcceptsInvalidRange) { + RecordingReportEmitter R; + R.addResult("rule", clang::SarifResultLevel::Note, clang::CharSourceRange{}, + "no-location"); + ASSERT_EQ(R.Results.size(), 1u); + EXPECT_FALSE(R.Results[0].Range.isValid()); +} + +} // namespace diff --git a/clang/unittests/ScalableStaticAnalysisFramework/SourceTransformation/RegistryTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/SourceTransformation/RegistryTest.cpp new file mode 100644 index 0000000000000..0c68cd95dd499 --- /dev/null +++ b/clang/unittests/ScalableStaticAnalysisFramework/SourceTransformation/RegistryTest.cpp @@ -0,0 +1,78 @@ +//===- RegistryTest.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 "TestFixture.h" +#include "clang/ScalableStaticAnalysisFramework/SourceTransformation/Transformation.h" +#include "clang/ScalableStaticAnalysisFramework/SourceTransformation/TransformationRegistry.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; +using namespace ssaf; + +namespace { + +class StubEditEmitter : public SourceEditEmitter { +public: + void addReplacement(clang::tooling::Replacement) override {} +}; + +class StubReportEmitter : public TransformationReportEmitter { +public: + void addResult(StringRef, clang::SarifResultLevel, clang::CharSourceRange, + StringRef) override {} +}; + +class StubTransformation : public Transformation { +public: + using Transformation::Transformation; +}; + +} // namespace + +static TransformationRegistry::Add<StubTransformation> + RegisterStubTransformation("stub-transformation", + "A transformation for testing"); + +namespace { + +class TransformationRegistryTest : public TestFixture {}; + +TEST_F(TransformationRegistryTest, isTransformationRegistered) { + EXPECT_FALSE(isTransformationRegistered("not-a-transformation")); + EXPECT_TRUE(isTransformationRegistered("stub-transformation")); +} + +TEST_F(TransformationRegistryTest, makeTransformation) { + WPASuite Suite = makeWPASuite(); + StubEditEmitter Edits; + StubReportEmitter Report; + std::unique_ptr<Transformation> T = + makeTransformation("stub-transformation", Suite, Edits, Report); + EXPECT_NE(T, nullptr); +} + +TEST_F(TransformationRegistryTest, EnumeratingRegistryEntries) { + auto Entries = TransformationRegistry::entries(); + EXPECT_TRUE(llvm::any_of(Entries, [](const auto &Entry) { + return StringRef(Entry.getName()) == "stub-transformation"; + })); +} + +TEST_F(TransformationRegistryTest, PrintAvailableTransformations) { + std::string Buffer; + raw_string_ostream OS(Buffer); + printAvailableTransformations(OS); + EXPECT_NE(StringRef(Buffer).find("stub-transformation"), StringRef::npos); + EXPECT_NE(StringRef(Buffer).find("A transformation for testing"), + StringRef::npos); +} + +} // namespace _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
