clang 24.0.0git
SourceTransformationFrontendAction.cpp
Go to the documentation of this file.
1//===- SourceTransformationFrontendAction.cpp -----------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
26#include "llvm/ADT/StringRef.h"
27#include "llvm/Support/IOSandbox.h"
28#include "llvm/Support/Path.h"
29#include <memory>
30#include <string>
31#include <utility>
32#include <vector>
33
34using namespace clang;
35using namespace ssaf;
36
37namespace {
38
39/// Concrete `SourceEditEmitter` that buffers replacements until flushed.
40class AccumulatorSourceEditEmitter final : public SourceEditEmitter {
41public:
42 void addReplacement(clang::tooling::Replacement R) override {
43 Replacements.push_back(std::move(R));
44 }
45
46 std::vector<clang::tooling::Replacement> Replacements;
47};
48
49/// Concrete `TransformationReportEmitter` that buffers results until flushed.
50class AccumulatorReportEmitter final : public TransformationReportEmitter {
51public:
52 void addResult(StringRef RuleId, clang::SarifResultLevel Level,
53 clang::CharSourceRange Range, StringRef Message) override {
54 Results.push_back({RuleId.str(), Level, Range, Message.str()});
55 }
56
57 std::vector<ReportResult> Results;
58};
59
60/// Per-TU runner: owns the loaded `WPASuite`, the accumulator emitters, and
61/// the user-supplied `Transformation`. Inherits from `MultiplexConsumer` so
62/// the transformation's `ASTConsumer` virtuals are forwarded for free;
63/// serializes both outputs after the AST walk completes.
64class SourceTransformationRunner final : public MultiplexConsumer {
65public:
66 static std::unique_ptr<SourceTransformationRunner>
67 create(CompilerInstance &CI, StringRef InFile);
68
69private:
70 SourceTransformationRunner(WPASuite Suite, const SSAFOptions &Opts,
71 StringRef InFile);
72
73 void HandleTranslationUnit(ASTContext &Ctx) override;
74
75 WPASuite Suite;
76 AccumulatorSourceEditEmitter Edits;
77 AccumulatorReportEmitter Report;
78 const SSAFOptions &Opts;
79 std::string InFile;
80};
81
82} // namespace
83
84/// Returns the bare extension of \p Path (no leading dot), or `std::nullopt` if
85/// \p Path is empty or has no recognizable extension.
86static std::optional<StringRef> bareExtension(StringRef Path) {
87 StringRef Ext = llvm::sys::path::extension(Path);
88 if (!Ext.consume_front("."))
89 return std::nullopt;
90 return Ext;
91}
92
93/// Companion options required by `--ssaf-source-transformation=`. Values must
94/// match the `%select` branch order in
95/// `warn_ssaf_source_transformation_requires`.
97 STCompanion_WPAFile, // --ssaf-global-scope-analysis-result=
98 STCompanion_EditFile, // --ssaf-src-edit-file=
99 STCompanion_ReportFile, // --ssaf-transformation-report-file=
100 STCompanion_CompilationUnitId, // --ssaf-compilation-unit-id=
101};
102
103/// Options that depend on `--ssaf-source-transformation=` being set. Values
104/// must match the `%select` branch order in
105/// `warn_ssaf_option_ignored_without_source_transformation`.
107 STDependent_EditFile, // --ssaf-src-edit-file=
108 STDependent_ReportFile, // --ssaf-transformation-report-file=
109};
110
111/// Returns `true` if any orphan-option warning was reported. Every missing
112/// companion option fires its own diagnostic in a single pass so the user
113/// sees the full list of CLI mistakes at once.
115 const SSAFOptions &Opts) {
116 bool Reported = false;
117
118 if (!Opts.SourceTransformation.empty()) {
119 if (Opts.GlobalScopeAnalysisResult.empty()) {
120 Diags.Report(diag::warn_ssaf_source_transformation_requires)
122 Reported = true;
123 }
124 if (Opts.SrcEditFile.empty()) {
125 Diags.Report(diag::warn_ssaf_source_transformation_requires)
127 Reported = true;
128 }
129 if (Opts.TransformationReportFile.empty()) {
130 Diags.Report(diag::warn_ssaf_source_transformation_requires)
132 Reported = true;
133 }
134 if (Opts.CompilationUnitId.empty()) {
135 Diags.Report(diag::warn_ssaf_source_transformation_requires)
137 Reported = true;
138 }
139 } else {
140 if (!Opts.SrcEditFile.empty()) {
141 Diags.Report(diag::warn_ssaf_option_ignored_without_source_transformation)
143 Reported = true;
144 }
145 if (!Opts.TransformationReportFile.empty()) {
146 Diags.Report(diag::warn_ssaf_option_ignored_without_source_transformation)
148 Reported = true;
149 }
150 }
151
152 return Reported;
153}
154
155std::unique_ptr<SourceTransformationRunner>
156SourceTransformationRunner::create(CompilerInstance &CI, StringRef InFile) {
157 const SSAFOptions &Opts = CI.getSSAFOpts();
158 DiagnosticsEngine &Diags = CI.getDiagnostics();
159
160 if (reportOrphanOptionMisuse(Diags, Opts))
161 return nullptr;
162 if (Opts.SourceTransformation.empty())
163 return nullptr;
164
166 Diags.Report(diag::warn_ssaf_source_transformation_unknown_name)
167 << Opts.SourceTransformation;
168 return nullptr;
169 }
170
171 std::optional<StringRef> WPAExt =
173 std::unique_ptr<SerializationFormat> WPAFormat =
174 WPAExt && isFormatRegistered(*WPAExt) ? makeFormat(*WPAExt) : nullptr;
175 if (!WPAFormat) {
176 Diags.Report(diag::warn_ssaf_read_wpa_suite_failed)
177 << Opts.GlobalScopeAnalysisResult << "unknown serialization format";
178 return nullptr;
179 }
180 llvm::sys::sandbox::ScopedSetting Guard = llvm::sys::sandbox::scopedDisable();
181 llvm::Expected<WPASuite> SuiteOrErr =
182 WPAFormat->readWPASuite(Opts.GlobalScopeAnalysisResult);
183 if (!SuiteOrErr) {
184 Diags.Report(diag::warn_ssaf_read_wpa_suite_failed)
186 << llvm::toString(SuiteOrErr.takeError());
187 return nullptr;
188 }
189
190 return std::unique_ptr<SourceTransformationRunner>{
191 new SourceTransformationRunner(std::move(*SuiteOrErr), Opts, InFile)};
192}
193
194SourceTransformationRunner::SourceTransformationRunner(WPASuite Suite,
195 const SSAFOptions &Opts,
196 StringRef InFile)
197 : MultiplexConsumer(std::vector<std::unique_ptr<ASTConsumer>>{}),
198 Suite(std::move(Suite)), Opts(Opts), InFile(InFile) {
199 // The transformation must be constructed after Suite/Edits/Report start
200 // their lifetimes — those references are captured in its base ctor.
201 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
202 Consumers.push_back(makeTransformation(Opts.SourceTransformation, this->Suite,
203 Edits, Report));
204 assert(Consumers.front());
205 MultiplexConsumer::Consumers = std::move(Consumers);
206}
207
208void SourceTransformationRunner::HandleTranslationUnit(ASTContext &Ctx) {
209 // First, run the transformation.
211
212 llvm::sys::sandbox::ScopedSetting Guard = llvm::sys::sandbox::scopedDisable();
213
214 // Then serialize the source edits.
215 clang::tooling::TranslationUnitReplacements EditDoc;
216 EditDoc.MainSourceFile = InFile;
217 EditDoc.Replacements = std::move(Edits.Replacements);
218 if (auto Err = writeYAMLSourceEdits(EditDoc, Opts.SrcEditFile)) {
219 Ctx.getDiagnostics().Report(diag::warn_ssaf_write_src_edit_failed)
220 << Opts.SrcEditFile << llvm::toString(std::move(Err));
221 }
222
223 // And the transformation report.
224 ReportDocument ReportDoc{Opts.SourceTransformation, Ctx.getSourceManager(),
225 std::move(Report.Results)};
226 if (auto Err = writeSARIFTransformationReport(
227 ReportDoc, Opts.TransformationReportFile)) {
229 diag::warn_ssaf_write_transformation_report_failed)
230 << Opts.TransformationReportFile << llvm::toString(std::move(Err));
231 }
232}
233
235 default;
236
240
241std::unique_ptr<ASTConsumer>
243 StringRef InFile) {
244 auto WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
245 if (!WrappedConsumer)
246 return nullptr;
247
248 if (auto Runner = SourceTransformationRunner::create(CI, InFile)) {
249 CI.getCodeGenOpts().ClearASTBeforeBackend = false;
250 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
251 Consumers.reserve(2);
252 Consumers.push_back(std::move(WrappedConsumer));
253 Consumers.push_back(std::move(Runner));
254 return std::make_unique<MultiplexConsumer>(std::move(Consumers));
255 }
256 return WrappedConsumer;
257}
Defines the clang::ASTContext interface.
SourceTransformationDependent
Options that depend on --ssaf-source-transformation= being set.
SourceTransformationCompanion
Companion options required by --ssaf-source-transformation=.
static bool reportOrphanOptionMisuse(DiagnosticsEngine &Diags, const SSAFOptions &Opts)
Returns true if any orphan-option warning was reported.
static std::optional< StringRef > bareExtension(StringRef Path)
Returns the bare extension of Path (no leading dot), or std::nullopt if Path is empty or has no recog...
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
SourceManager & getSourceManager()
Definition ASTContext.h:887
DiagnosticsEngine & getDiagnostics() const
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
ssaf::SSAFOptions & getSSAFOpts()
CodeGenOptions & getCodeGenOpts()
Concrete class used by the front-end to report problems and issues.
Definition Diagnostic.h:234
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
void HandleTranslationUnit(ASTContext &Ctx) override
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
std::vector< std::unique_ptr< ASTConsumer > > Consumers
WrapperFrontendAction(std::unique_ptr< FrontendAction > WrappedAction)
Construct a WrapperFrontendAction from an existing action, taking ownership of it.
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
std::unique_ptr< FrontendAction > WrappedAction
std::string SrcEditFile
Path of the source-edit output file produced by the source transformation.
Definition SSAFOptions.h:48
std::string TransformationReportFile
Path of the transformation-report output file produced by the source transformation.
Definition SSAFOptions.h:53
std::string CompilationUnitId
Stable identifier used as the name of the CompilationUnit BuildNamespace of every produced TU summary...
Definition SSAFOptions.h:32
std::string SourceTransformation
Name of the SSAF source transformation to run.
Definition SSAFOptions.h:38
std::string GlobalScopeAnalysisResult
Path of the WPASuite input consumed by the source transformation.
Definition SSAFOptions.h:43
SourceTransformationFrontendAction(std::unique_ptr< FrontendAction > WrappedAction)
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions &DiagOpts, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
std::unique_ptr< SerializationFormat > makeFormat(llvm::StringRef FormatName)
Try to instantiate a SerializationFormat with a given name.
llvm::Error writeSARIFTransformationReport(const ReportDocument &Doc, llvm::StringRef Path)
Writes Doc to Path as a SARIF JSON document.
llvm::Error writeYAMLSourceEdits(const clang::tooling::TranslationUnitReplacements &Doc, llvm::StringRef Path)
Writes Doc to Path as a YAML document compatible with clang-apply-replacements.
bool isFormatRegistered(llvm::StringRef FormatName)
Check if a SerializationFormat was registered with a given name.
std::unique_ptr< Transformation > makeTransformation(llvm::StringRef Name, const WPASuite &Suite, SourceEditEmitter &Edits, TransformationReportEmitter &Report)
Try to instantiate a Transformation with a given name.
bool isTransformationRegistered(llvm::StringRef Name)
Check if a Transformation was registered with a given name.
Top level wrappers for InstallAPI frontend operations.
SarifResultLevel
The level of severity associated with a SarifResult.
Definition Sarif.h:165
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
std::string MainSourceFile
Name of the main source for the translation unit.
std::vector< Replacement > Replacements