1f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek//===- unittest/Tooling/RefactoringTest.cpp - Refactoring unit tests ------===// 2f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek// 3f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek// The LLVM Compiler Infrastructure 4f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek// 5f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek// This file is distributed under the University of Illinois Open Source 6f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek// License. See LICENSE.TXT for details. 7f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek// 8f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek//===----------------------------------------------------------------------===// 9f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 10f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "RewriterTestContext.h" 11a13d2bceaea04cb7c16b4cfbeb06f12f8e90c6c9Benjamin Kramer#include "clang/AST/ASTContext.h" 12f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/AST/ASTConsumer.h" 13f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/AST/DeclCXX.h" 14f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/AST/DeclGroup.h" 15f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/AST/RecursiveASTVisitor.h" 16f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Tooling/Refactoring.h" 17f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Basic/Diagnostic.h" 18f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Basic/FileManager.h" 19f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Basic/LangOptions.h" 20f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Basic/SourceManager.h" 21f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Frontend/CompilerInstance.h" 22f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Frontend/DiagnosticOptions.h" 23f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Frontend/FrontendAction.h" 24f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Frontend/TextDiagnosticPrinter.h" 25305c613af6cfc40e519c75d9d2c84c6fa9a841c0Ted Kremenek#include "clang/Rewrite/Core/Rewriter.h" 26f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "clang/Tooling/Tooling.h" 27f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "llvm/ADT/SmallString.h" 28f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "llvm/Support/Path.h" 29f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek#include "gtest/gtest.h" 30f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 31f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimeknamespace clang { 32f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimeknamespace tooling { 33f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 34f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekclass ReplacementTest : public ::testing::Test { 35f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek protected: 36f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacement createReplacement(SourceLocation Start, unsigned Length, 37f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek llvm::StringRef ReplacementText) { 38f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek return Replacement(Context.Sources, Start, Length, ReplacementText); 39f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek } 40f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 41f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek RewriterTestContext Context; 42f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}; 43f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 44f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, CanDeleteAllText) { 45f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek FileID ID = Context.createInMemoryFile("input.cpp", "text"); 46f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek SourceLocation Location = Context.getLocation(ID, 1, 1); 47f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacement Replace(createReplacement(Location, 4, "")); 48f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(Replace.apply(Context.Rewrite)); 49f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ("", Context.getRewrittenText(ID)); 50f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 51f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 52f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, CanDeleteAllTextInTextWithNewlines) { 53f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek FileID ID = Context.createInMemoryFile("input.cpp", "line1\nline2\nline3"); 54f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek SourceLocation Location = Context.getLocation(ID, 1, 1); 55f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacement Replace(createReplacement(Location, 17, "")); 56f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(Replace.apply(Context.Rewrite)); 57f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ("", Context.getRewrittenText(ID)); 58f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 59f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 60f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, CanAddText) { 61f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek FileID ID = Context.createInMemoryFile("input.cpp", ""); 62f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek SourceLocation Location = Context.getLocation(ID, 1, 1); 63f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacement Replace(createReplacement(Location, 0, "result")); 64f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(Replace.apply(Context.Rewrite)); 65f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ("result", Context.getRewrittenText(ID)); 66f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 67f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 68f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, CanReplaceTextAtPosition) { 69f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek FileID ID = Context.createInMemoryFile("input.cpp", 70f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek "line1\nline2\nline3\nline4"); 71f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek SourceLocation Location = Context.getLocation(ID, 2, 3); 72f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacement Replace(createReplacement(Location, 12, "x")); 73f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(Replace.apply(Context.Rewrite)); 74f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ("line1\nlixne4", Context.getRewrittenText(ID)); 75f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 76f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 77f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, CanReplaceTextAtPositionMultipleTimes) { 78f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek FileID ID = Context.createInMemoryFile("input.cpp", 79f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek "line1\nline2\nline3\nline4"); 80f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek SourceLocation Location1 = Context.getLocation(ID, 2, 3); 81f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacement Replace1(createReplacement(Location1, 12, "x\ny\n")); 82f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(Replace1.apply(Context.Rewrite)); 83f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ("line1\nlix\ny\nne4", Context.getRewrittenText(ID)); 84f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 85f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek // Since the original source has not been modified, the (4, 4) points to the 86f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek // 'e' in the original content. 87f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek SourceLocation Location2 = Context.getLocation(ID, 4, 4); 88f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacement Replace2(createReplacement(Location2, 1, "f")); 89f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(Replace2.apply(Context.Rewrite)); 90f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ("line1\nlix\ny\nnf4", Context.getRewrittenText(ID)); 91f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 92f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 93f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, ApplyFailsForNonExistentLocation) { 94f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacement Replace("nonexistent-file.cpp", 0, 1, ""); 95f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_FALSE(Replace.apply(Context.Rewrite)); 96f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 97f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 98f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, CanRetrivePath) { 99f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacement Replace("/path/to/file.cpp", 0, 1, ""); 100f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ("/path/to/file.cpp", Replace.getFilePath()); 101f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 102f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 103f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, ReturnsInvalidPath) { 104f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacement Replace1(Context.Sources, SourceLocation(), 0, ""); 105f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(Replace1.getFilePath().empty()); 106f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 107f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacement Replace2; 108f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(Replace2.getFilePath().empty()); 109f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 110f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 111f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, CanApplyReplacements) { 112f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek FileID ID = Context.createInMemoryFile("input.cpp", 113f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek "line1\nline2\nline3\nline4"); 114f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacements Replaces; 115f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 116f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 5, "replaced")); 117f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 3, 1), 118f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 5, "other")); 119f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite)); 120f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID)); 121f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 122f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 123f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, SkipsDuplicateReplacements) { 124f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek FileID ID = Context.createInMemoryFile("input.cpp", 125f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek "line1\nline2\nline3\nline4"); 126f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacements Replaces; 127f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 128f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 5, "replaced")); 129f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 130f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 5, "replaced")); 131f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 132f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 5, "replaced")); 133f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite)); 134f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ("line1\nreplaced\nline3\nline4", Context.getRewrittenText(ID)); 135f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 136f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 137f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(ReplacementTest, ApplyAllFailsIfOneApplyFails) { 138f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek // This test depends on the value of the file name of an invalid source 139f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek // location being in the range ]a, z[. 140f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek FileID IDa = Context.createInMemoryFile("a.cpp", "text"); 141f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek FileID IDz = Context.createInMemoryFile("z.cpp", "text"); 142f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacements Replaces; 143f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replaces.insert(Replacement(Context.Sources, Context.getLocation(IDa, 1, 1), 144f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 4, "a")); 145f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replaces.insert(Replacement(Context.Sources, SourceLocation(), 146f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 5, "2")); 147f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replaces.insert(Replacement(Context.Sources, Context.getLocation(IDz, 1, 1), 148f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 4, "z")); 149f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_FALSE(applyAllReplacements(Replaces, Context.Rewrite)); 150f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ("a", Context.getRewrittenText(IDa)); 151f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ("z", Context.getRewrittenText(IDz)); 152f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 153f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 154f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekclass FlushRewrittenFilesTest : public ::testing::Test { 155f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek public: 156f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek FlushRewrittenFilesTest() { 157f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek std::string ErrorInfo; 158f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek TemporaryDirectory = llvm::sys::Path::GetTemporaryDirectory(&ErrorInfo); 159f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek assert(ErrorInfo.empty()); 160f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek } 161f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 162f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek ~FlushRewrittenFilesTest() { 163f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek std::string ErrorInfo; 164f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek TemporaryDirectory.eraseFromDisk(true, &ErrorInfo); 165f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek assert(ErrorInfo.empty()); 166f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek } 167f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 168f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek FileID createFile(llvm::StringRef Name, llvm::StringRef Content) { 169f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek llvm::SmallString<1024> Path(TemporaryDirectory.str()); 170f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek llvm::sys::path::append(Path, Name); 171f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek std::string ErrorInfo; 172f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek llvm::raw_fd_ostream OutStream(Path.c_str(), 173f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek ErrorInfo, llvm::raw_fd_ostream::F_Binary); 174f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek assert(ErrorInfo.empty()); 175f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek OutStream << Content; 176f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek OutStream.close(); 177f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek const FileEntry *File = Context.Files.getFile(Path); 178f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek assert(File != NULL); 179f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek return Context.Sources.createFileID(File, SourceLocation(), SrcMgr::C_User); 180f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek } 181f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 182f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek std::string getFileContentFromDisk(llvm::StringRef Name) { 183f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek llvm::SmallString<1024> Path(TemporaryDirectory.str()); 184f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek llvm::sys::path::append(Path, Name); 185f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek // We need to read directly from the FileManager without relaying through 186f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek // a FileEntry, as otherwise we'd read through an already opened file 187f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek // descriptor, which might not see the changes made. 188f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek // FIXME: Figure out whether there is a way to get the SourceManger to 189f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek // reopen the file. 190f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek return Context.Files.getBufferForFile(Path, NULL)->getBuffer(); 191f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek } 192f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 193f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek llvm::sys::Path TemporaryDirectory; 194f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek RewriterTestContext Context; 195f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}; 196f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 197f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST_F(FlushRewrittenFilesTest, StoresChangesOnDisk) { 198f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek FileID ID = createFile("input.cpp", "line1\nline2\nline3\nline4"); 199f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacements Replaces; 200f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 201f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 5, "replaced")); 202f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite)); 203f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_FALSE(Context.Rewrite.overwriteChangedFiles()); 204f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ("line1\nreplaced\nline3\nline4", 205f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek getFileContentFromDisk("input.cpp")); 206f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 207f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 208f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimeknamespace { 209f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimektemplate <typename T> 210f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekclass TestVisitor : public clang::RecursiveASTVisitor<T> { 211f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekpublic: 212f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek bool runOver(StringRef Code) { 213f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek return runToolOnCode(new TestAction(this), Code); 214f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek } 215f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 216f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekprotected: 217f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek clang::SourceManager *SM; 218f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 219f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekprivate: 220f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek class FindConsumer : public clang::ASTConsumer { 221f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek public: 222f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {} 223f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 224f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek virtual void HandleTranslationUnit(clang::ASTContext &Context) { 225f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Visitor->TraverseDecl(Context.getTranslationUnitDecl()); 226f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek } 227f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 228f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek private: 229f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek TestVisitor *Visitor; 230f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek }; 231f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 232f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek class TestAction : public clang::ASTFrontendAction { 233f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek public: 234f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek TestAction(TestVisitor *Visitor) : Visitor(Visitor) {} 235f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 236f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek virtual clang::ASTConsumer* CreateASTConsumer( 237f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek clang::CompilerInstance& compiler, llvm::StringRef dummy) { 238f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Visitor->SM = &compiler.getSourceManager(); 239f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek /// TestConsumer will be deleted by the framework calling us. 240f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek return new FindConsumer(Visitor); 241f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek } 242f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 243f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek private: 244f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek TestVisitor *Visitor; 245f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek }; 246f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}; 247f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} // end namespace 248f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 249f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekvoid expectReplacementAt(const Replacement &Replace, 250f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek StringRef File, unsigned Offset, unsigned Length) { 251f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek ASSERT_TRUE(Replace.isApplicable()); 252f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ(File, Replace.getFilePath()); 253f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ(Offset, Replace.getOffset()); 254f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_EQ(Length, Replace.getLength()); 255f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 256f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 257f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekclass ClassDeclXVisitor : public TestVisitor<ClassDeclXVisitor> { 258f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekpublic: 259f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek bool VisitCXXRecordDecl(CXXRecordDecl *Record) { 260f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek if (Record->getName() == "X") { 261f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replace = Replacement(*SM, Record, ""); 262f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek } 263f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek return true; 264f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek } 265f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacement Replace; 266f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}; 267f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 268f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST(Replacement, CanBeConstructedFromNode) { 269f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek ClassDeclXVisitor ClassDeclX; 270f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(ClassDeclX.runOver(" class X;")); 271f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek expectReplacementAt(ClassDeclX.Replace, "input.cc", 5, 7); 272f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 273f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 274f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST(Replacement, ReplacesAtSpellingLocation) { 275f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek ClassDeclXVisitor ClassDeclX; 276f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(ClassDeclX.runOver("#define A(Y) Y\nA(class X);")); 277f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek expectReplacementAt(ClassDeclX.Replace, "input.cc", 17, 7); 278f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 279f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 280f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekclass CallToFVisitor : public TestVisitor<CallToFVisitor> { 281f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimekpublic: 282f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek bool VisitCallExpr(CallExpr *Call) { 283f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek if (Call->getDirectCallee()->getName() == "F") { 284f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replace = Replacement(*SM, Call, ""); 285f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek } 286f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek return true; 287f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek } 288f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek Replacement Replace; 289f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek}; 290f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 291f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST(Replacement, FunctionCall) { 292f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek CallToFVisitor CallToF; 293f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(CallToF.runOver("void F(); void G() { F(); }")); 294f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek expectReplacementAt(CallToF.Replace, "input.cc", 21, 3); 295f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 296f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 297f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel KlimekTEST(Replacement, TemplatedFunctionCall) { 298f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek CallToFVisitor CallToF; 299f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek EXPECT_TRUE(CallToF.runOver( 300f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek "template <typename T> void F(); void G() { F<int>(); }")); 301f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek expectReplacementAt(CallToF.Replace, "input.cc", 43, 8); 302f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} 303f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek 304f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} // end namespace tooling 305f9d4cbd3dd1eb4cf3ec3c5ec7acc310415beeefdManuel Klimek} // end namespace clang 306