#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/Any.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
/// is being changed, e.g. the call to a refactored method.
AtomicChange(const SourceManager &SM, SourceLocation KeyPosition);
+ AtomicChange(const SourceManager &SM, SourceLocation KeyPosition,
+ llvm::Any Metadata);
+
/// Creates an atomic change for \p FilePath with a customized key.
AtomicChange(llvm::StringRef FilePath, llvm::StringRef Key)
: Key(Key), FilePath(FilePath) {}
return RemovedHeaders;
}
+ const llvm::Any &getMetadata() const { return Metadata; }
+
private:
AtomicChange() {}
std::vector<std::string> InsertedHeaders;
std::vector<std::string> RemovedHeaders;
tooling::Replacements Replaces;
+
+ // This field stores metadata which is ignored for the purposes of applying
+ // edits to source, but may be useful for other consumers of AtomicChanges. In
+ // particular, consumers can use this to direct how they want to consume each
+ // edit.
+ llvm::Any Metadata;
};
using AtomicChanges = std::vector<AtomicChange>;
#include "clang/Tooling/Refactoring/AtomicChange.h"
#include "clang/Tooling/Transformer/MatchConsumer.h"
#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/ADT/Any.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Error.h"
struct Edit {
CharSourceRange Range;
std::string Replacement;
+ llvm::Any Metadata;
};
/// Maps a match result to a list of concrete edits (with possible
RangeSelector TargetRange;
TextGenerator Replacement;
TextGenerator Note;
+ llvm::Any Metadata;
};
/// Lifts a list of `ASTEdit`s into an `EditGenerator`.
/// Removes the source selected by \p S.
ASTEdit remove(RangeSelector S);
+inline ASTEdit withMetadata(ASTEdit edit, llvm::Any Metadata) {
+ edit.Metadata = std::move(Metadata);
+ return edit;
+}
+
/// The following three functions are a low-level part of the RewriteRule
/// API. We expose them for use in implementing the fixtures that interpret
/// RewriteRule, like Transformer and TransfomerTidy, or for more advanced
Key = FilePath + ":" + std::to_string(FileIDAndOffset.second);
}
+AtomicChange::AtomicChange(const SourceManager &SM, SourceLocation KeyPosition,
+ llvm::Any M)
+ : AtomicChange(SM, KeyPosition) {
+ Metadata = std::move(M);
+}
+
AtomicChange::AtomicChange(std::string Key, std::string FilePath,
std::string Error,
std::vector<std::string> InsertedHeaders,
transformer::Edit T;
T.Range = *EditRange;
T.Replacement = std::move(*Replacement);
+ T.Metadata = E.Metadata;
Edits.push_back(std::move(T));
}
return Edits;
auto ID = Result.SourceManager->getFileID(T.Range.getBegin());
auto Iter = ChangesByFileID
.emplace(ID, AtomicChange(*Result.SourceManager,
- T.Range.getBegin()))
+ T.Range.getBegin(), T.Metadata))
.first;
auto &AC = Iter->second;
if (auto Err = AC.replace(*Result.SourceManager, T.Range, T.Replacement)) {
Replacement(Context.Sources, SourceLocation(), 0, "b")));
}
+TEST_F(AtomicChangeTest, Metadata) {
+ AtomicChange Change(Context.Sources, DefaultLoc, 17);
+ const llvm::Any &Metadata = Change.getMetadata();
+ ASSERT_TRUE(llvm::any_isa<int>(Metadata));
+ EXPECT_EQ(llvm::any_cast<int>(Metadata), 17);
+}
+
+TEST_F(AtomicChangeTest, NoMetadata) {
+ AtomicChange Change(Context.Sources, DefaultLoc);
+ EXPECT_FALSE(Change.getMetadata().hasValue());
+}
+
class ApplyAtomicChangesTest : public ::testing::Test {
protected:
ApplyAtomicChangesTest() : FilePath("file.cc") {
Input, Expected);
}
+TEST_F(TransformerTest, WithMetadata) {
+ std::string Input = R"cc(
+ int f() {
+ int x = 5;
+ return 7;
+ }
+ )cc";
+
+ Transformer T(
+ makeRule(declStmt().bind("decl"),
+ withMetadata(remove(statement(std::string("decl"))), 17)),
+ consumer());
+ T.registerMatchers(&MatchFinder);
+ auto Factory = newFrontendActionFactory(&MatchFinder);
+ EXPECT_TRUE(runToolOnCodeWithArgs(
+ Factory->create(), Input, std::vector<std::string>(), "input.cc",
+ "clang-tool", std::make_shared<PCHContainerOperations>(), {}));
+ ASSERT_EQ(Changes.size(), 1u);
+ const llvm::Any &Metadata = Changes[0].getMetadata();
+ ASSERT_TRUE(llvm::any_isa<int>(Metadata));
+ EXPECT_THAT(llvm::any_cast<int>(Metadata), 17);
+}
+
TEST_F(TransformerTest, MultiChange) {
std::string Input = R"cc(
void foo() {