forked from OSchip/llvm-project
[libclang] Add CXRewriter to libclang API
Differential Revision: https://reviews.llvm.org/D86992
This commit is contained in:
parent
35b35a373d
commit
69e5abb57b
|
@ -0,0 +1,63 @@
|
|||
/*===-- clang-c/Rewrite.h - C CXRewriter --------------------------*- 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 *|
|
||||
|* *|
|
||||
|*===----------------------------------------------------------------------===*/
|
||||
|
||||
#ifndef LLVM_CLANG_C_REWRITE_H
|
||||
#define LLVM_CLANG_C_REWRITE_H
|
||||
|
||||
#include "clang-c/CXString.h"
|
||||
#include "clang-c/ExternC.h"
|
||||
#include "clang-c/Index.h"
|
||||
#include "clang-c/Platform.h"
|
||||
|
||||
LLVM_CLANG_C_EXTERN_C_BEGIN
|
||||
|
||||
typedef void *CXRewriter;
|
||||
|
||||
/**
|
||||
* Create CXRewriter.
|
||||
*/
|
||||
CINDEX_LINKAGE CXRewriter clang_CXRewriter_create(CXTranslationUnit TU);
|
||||
|
||||
/**
|
||||
* Insert the specified string at the specified location in the original buffer.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_CXRewriter_insertTextBefore(CXRewriter Rew, CXSourceLocation Loc,
|
||||
const char *Insert);
|
||||
|
||||
/**
|
||||
* Replace the specified range of characters in the input with the specified
|
||||
* replacement.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_CXRewriter_replaceText(CXRewriter Rew, CXSourceRange ToBeReplaced,
|
||||
const char *Replacement);
|
||||
|
||||
/**
|
||||
* Remove the specified range.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_CXRewriter_removeText(CXRewriter Rew, CXSourceRange ToBeRemoved);
|
||||
|
||||
/**
|
||||
* Save all changed files to disk.
|
||||
* Returns 1 if any files were not saved successfully, returns 0 otherwise.
|
||||
*/
|
||||
CINDEX_LINKAGE int clang_CXRewriter_overwriteChangedFiles(CXRewriter Rew);
|
||||
|
||||
/**
|
||||
* Write out rewritten version of the main file to stdout.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_CXRewriter_writeMainFileToStdOut(CXRewriter Rew);
|
||||
|
||||
/**
|
||||
* Free the given CXRewriter.
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_CXRewriter_dispose(CXRewriter Rew);
|
||||
|
||||
LLVM_CLANG_C_EXTERN_C_END
|
||||
|
||||
#endif
|
|
@ -20,6 +20,7 @@ set(SOURCES
|
|||
CXType.cpp
|
||||
Indexing.cpp
|
||||
FatalErrorHandler.cpp
|
||||
Rewrite.cpp
|
||||
|
||||
ADDITIONAL_HEADERS
|
||||
CIndexDiagnostic.h
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
//===- Rewrite.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-c/Rewrite.h"
|
||||
#include "CXSourceLocation.h"
|
||||
#include "CXTranslationUnit.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Frontend/ASTUnit.h"
|
||||
#include "clang/Rewrite/Core/Rewriter.h"
|
||||
|
||||
CXRewriter clang_CXRewriter_create(CXTranslationUnit TU) {
|
||||
if (clang::cxtu::isNotUsableTU(TU)) {
|
||||
LOG_BAD_TU(TU);
|
||||
return {};
|
||||
}
|
||||
clang::ASTUnit *AU = clang::cxtu::getASTUnit(TU);
|
||||
assert(AU);
|
||||
return reinterpret_cast<CXRewriter>(
|
||||
new clang::Rewriter(AU->getSourceManager(), AU->getLangOpts()));
|
||||
}
|
||||
|
||||
void clang_CXRewriter_insertTextBefore(CXRewriter Rew, CXSourceLocation Loc,
|
||||
const char *Insert) {
|
||||
assert(Rew);
|
||||
clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew);
|
||||
R.InsertTextBefore(clang::cxloc::translateSourceLocation(Loc), Insert);
|
||||
}
|
||||
|
||||
void clang_CXRewriter_replaceText(CXRewriter Rew, CXSourceRange ToBeReplaced,
|
||||
const char *Replacement) {
|
||||
assert(Rew);
|
||||
clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew);
|
||||
R.ReplaceText(clang::cxloc::translateCXRangeToCharRange(ToBeReplaced),
|
||||
Replacement);
|
||||
}
|
||||
|
||||
void clang_CXRewriter_removeText(CXRewriter Rew, CXSourceRange ToBeRemoved) {
|
||||
assert(Rew);
|
||||
clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew);
|
||||
R.RemoveText(clang::cxloc::translateCXRangeToCharRange(ToBeRemoved));
|
||||
}
|
||||
|
||||
int clang_CXRewriter_overwriteChangedFiles(CXRewriter Rew) {
|
||||
assert(Rew);
|
||||
clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew);
|
||||
return R.overwriteChangedFiles();
|
||||
}
|
||||
|
||||
void clang_CXRewriter_writeMainFileToStdOut(CXRewriter Rew) {
|
||||
assert(Rew);
|
||||
clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew);
|
||||
R.getEditBuffer(R.getSourceMgr().getMainFileID()).write(llvm::outs());
|
||||
}
|
||||
|
||||
void clang_CXRewriter_dispose(CXRewriter Rew) {
|
||||
if (Rew)
|
||||
delete reinterpret_cast<clang::Rewriter *>(Rew);
|
||||
}
|
|
@ -385,3 +385,10 @@ clang_uninstall_llvm_fatal_error_handler
|
|||
clang_Cursor_getVarDeclInitializer
|
||||
clang_Cursor_hasVarDeclGlobalStorage
|
||||
clang_Cursor_hasVarDeclExternalStorage
|
||||
clang_CXRewriter_create
|
||||
clang_CXRewriter_insertTextBefore
|
||||
clang_CXRewriter_replaceText
|
||||
clang_CXRewriter_removeText
|
||||
clang_CXRewriter_overwriteChangedFiles
|
||||
clang_CXRewriter_writeMainFileToStdOut
|
||||
clang_CXRewriter_dispose
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang-c/Index.h"
|
||||
#include "clang-c/Rewrite.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
|
@ -842,3 +843,90 @@ TEST_F(LibclangParseTest, clang_Cursor_hasVarDeclExternalStorageTrue) {
|
|||
},
|
||||
nullptr);
|
||||
}
|
||||
class LibclangRewriteTest : public LibclangParseTest {
|
||||
public:
|
||||
CXRewriter Rew = nullptr;
|
||||
std::string Filename;
|
||||
CXFile File = nullptr;
|
||||
|
||||
void SetUp() override {
|
||||
LibclangParseTest::SetUp();
|
||||
Filename = "file.cpp";
|
||||
WriteFile(Filename, "int main() { return 0; }");
|
||||
ClangTU = clang_parseTranslationUnit(Index, Filename.c_str(), nullptr, 0,
|
||||
nullptr, 0, TUFlags);
|
||||
Rew = clang_CXRewriter_create(ClangTU);
|
||||
File = clang_getFile(ClangTU, Filename.c_str());
|
||||
}
|
||||
void TearDown() override {
|
||||
clang_CXRewriter_dispose(Rew);
|
||||
LibclangParseTest::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
static std::string getFileContent(const std::string& Filename) {
|
||||
std::ifstream RewrittenFile(Filename);
|
||||
std::string RewrittenFileContent;
|
||||
std::string Line;
|
||||
while (std::getline(RewrittenFile, Line)) {
|
||||
if (RewrittenFileContent.empty())
|
||||
RewrittenFileContent = Line;
|
||||
else {
|
||||
RewrittenFileContent += "\n" + Line;
|
||||
}
|
||||
}
|
||||
return RewrittenFileContent;
|
||||
}
|
||||
|
||||
TEST_F(LibclangRewriteTest, RewriteReplace) {
|
||||
CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5);
|
||||
CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9);
|
||||
CXSourceRange Rng = clang_getRange(B, E);
|
||||
|
||||
clang_CXRewriter_replaceText(Rew, Rng, "MAIN");
|
||||
|
||||
ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);
|
||||
EXPECT_EQ(getFileContent(Filename), "int MAIN() { return 0; }");
|
||||
}
|
||||
|
||||
TEST_F(LibclangRewriteTest, RewriteReplaceShorter) {
|
||||
CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5);
|
||||
CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9);
|
||||
CXSourceRange Rng = clang_getRange(B, E);
|
||||
|
||||
clang_CXRewriter_replaceText(Rew, Rng, "foo");
|
||||
|
||||
ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);
|
||||
EXPECT_EQ(getFileContent(Filename), "int foo() { return 0; }");
|
||||
}
|
||||
|
||||
TEST_F(LibclangRewriteTest, RewriteReplaceLonger) {
|
||||
CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5);
|
||||
CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9);
|
||||
CXSourceRange Rng = clang_getRange(B, E);
|
||||
|
||||
clang_CXRewriter_replaceText(Rew, Rng, "patatino");
|
||||
|
||||
ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);
|
||||
EXPECT_EQ(getFileContent(Filename), "int patatino() { return 0; }");
|
||||
}
|
||||
|
||||
TEST_F(LibclangRewriteTest, RewriteInsert) {
|
||||
CXSourceLocation Loc = clang_getLocation(ClangTU, File, 1, 5);
|
||||
|
||||
clang_CXRewriter_insertTextBefore(Rew, Loc, "ro");
|
||||
|
||||
ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);
|
||||
EXPECT_EQ(getFileContent(Filename), "int romain() { return 0; }");
|
||||
}
|
||||
|
||||
TEST_F(LibclangRewriteTest, RewriteRemove) {
|
||||
CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5);
|
||||
CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9);
|
||||
CXSourceRange Rng = clang_getRange(B, E);
|
||||
|
||||
clang_CXRewriter_removeText(Rew, Rng);
|
||||
|
||||
ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);
|
||||
EXPECT_EQ(getFileContent(Filename), "int () { return 0; }");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue