Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,23 @@
set(LLVM_LINK_COMPONENTS
Option
Support
)
add_clang_tool(clang-rename ClangRename.cpp)
target_link_libraries(clang-rename
PRIVATE
clangBasic
clangFrontend
clangRewrite
clangTooling
clangToolingCore
clangToolingRefactor
)
install(PROGRAMS clang-rename.py
DESTINATION share/clang
COMPONENT clang-rename)
install(PROGRAMS clang-rename.el
DESTINATION share/clang
COMPONENT clang-rename)

View File

@@ -0,0 +1,233 @@
//===--- tools/extra/clang-rename/ClangRename.cpp - Clang rename tool -----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file implements a clang-rename tool that automatically finds and
/// renames symbols in C++ code.
///
//===----------------------------------------------------------------------===//
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
#include "clang/Tooling/ReplacementsYaml.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
#include <system_error>
using namespace llvm;
using namespace clang;
/// \brief An oldname -> newname rename.
struct RenameAllInfo {
unsigned Offset = 0;
std::string QualifiedName;
std::string NewName;
};
LLVM_YAML_IS_SEQUENCE_VECTOR(RenameAllInfo)
namespace llvm {
namespace yaml {
/// \brief Specialized MappingTraits to describe how a RenameAllInfo is
/// (de)serialized.
template <> struct MappingTraits<RenameAllInfo> {
static void mapping(IO &IO, RenameAllInfo &Info) {
IO.mapOptional("Offset", Info.Offset);
IO.mapOptional("QualifiedName", Info.QualifiedName);
IO.mapRequired("NewName", Info.NewName);
}
};
} // end namespace yaml
} // end namespace llvm
static cl::OptionCategory ClangRenameOptions("clang-rename common options");
static cl::list<unsigned> SymbolOffsets(
"offset",
cl::desc("Locates the symbol by offset as opposed to <line>:<column>."),
cl::ZeroOrMore, cl::cat(ClangRenameOptions));
static cl::opt<bool> Inplace("i", cl::desc("Overwrite edited <file>s."),
cl::cat(ClangRenameOptions));
static cl::list<std::string>
QualifiedNames("qualified-name",
cl::desc("The fully qualified name of the symbol."),
cl::ZeroOrMore, cl::cat(ClangRenameOptions));
static cl::list<std::string>
NewNames("new-name", cl::desc("The new name to change the symbol to."),
cl::ZeroOrMore, cl::cat(ClangRenameOptions));
static cl::opt<bool> PrintName(
"pn",
cl::desc("Print the found symbol's name prior to renaming to stderr."),
cl::cat(ClangRenameOptions));
static cl::opt<bool> PrintLocations(
"pl", cl::desc("Print the locations affected by renaming to stderr."),
cl::cat(ClangRenameOptions));
static cl::opt<std::string>
ExportFixes("export-fixes",
cl::desc("YAML file to store suggested fixes in."),
cl::value_desc("filename"), cl::cat(ClangRenameOptions));
static cl::opt<std::string>
Input("input", cl::desc("YAML file to load oldname-newname pairs from."),
cl::Optional, cl::cat(ClangRenameOptions));
static cl::opt<bool> Force("force",
cl::desc("Ignore nonexistent qualified names."),
cl::cat(ClangRenameOptions));
int main(int argc, const char **argv) {
tooling::CommonOptionsParser OP(argc, argv, ClangRenameOptions);
if (!Input.empty()) {
// Populate QualifiedNames and NewNames from a YAML file.
ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
llvm::MemoryBuffer::getFile(Input);
if (!Buffer) {
errs() << "clang-rename: failed to read " << Input << ": "
<< Buffer.getError().message() << "\n";
return 1;
}
std::vector<RenameAllInfo> Infos;
llvm::yaml::Input YAML(Buffer.get()->getBuffer());
YAML >> Infos;
for (const auto &Info : Infos) {
if (!Info.QualifiedName.empty())
QualifiedNames.push_back(Info.QualifiedName);
else
SymbolOffsets.push_back(Info.Offset);
NewNames.push_back(Info.NewName);
}
}
// Check the arguments for correctness.
if (NewNames.empty()) {
errs() << "clang-rename: -new-name must be specified.\n\n";
return 1;
}
if (SymbolOffsets.empty() == QualifiedNames.empty()) {
errs() << "clang-rename: -offset and -qualified-name can't be present at "
"the same time.\n";
return 1;
}
// Check if NewNames is a valid identifier in C++17.
LangOptions Options;
Options.CPlusPlus = true;
Options.CPlusPlus17 = true;
IdentifierTable Table(Options);
for (const auto &NewName : NewNames) {
auto NewNameTokKind = Table.get(NewName).getTokenID();
if (!tok::isAnyIdentifier(NewNameTokKind)) {
errs() << "ERROR: new name is not a valid identifier in C++17.\n\n";
return 1;
}
}
if (SymbolOffsets.size() + QualifiedNames.size() != NewNames.size()) {
errs() << "clang-rename: number of symbol offsets(" << SymbolOffsets.size()
<< ") + number of qualified names (" << QualifiedNames.size()
<< ") must be equal to number of new names(" << NewNames.size()
<< ").\n\n";
cl::PrintHelpMessage();
return 1;
}
auto Files = OP.getSourcePathList();
tooling::RefactoringTool Tool(OP.getCompilations(), Files);
tooling::USRFindingAction FindingAction(SymbolOffsets, QualifiedNames, Force);
Tool.run(tooling::newFrontendActionFactory(&FindingAction).get());
const std::vector<std::vector<std::string>> &USRList =
FindingAction.getUSRList();
const std::vector<std::string> &PrevNames = FindingAction.getUSRSpellings();
if (PrintName) {
for (const auto &PrevName : PrevNames) {
outs() << "clang-rename found name: " << PrevName << '\n';
}
}
if (FindingAction.errorOccurred()) {
// Diagnostics are already issued at this point.
return 1;
}
// Perform the renaming.
tooling::RenamingAction RenameAction(NewNames, PrevNames, USRList,
Tool.getReplacements(), PrintLocations);
std::unique_ptr<tooling::FrontendActionFactory> Factory =
tooling::newFrontendActionFactory(&RenameAction);
int ExitCode;
if (Inplace) {
ExitCode = Tool.runAndSave(Factory.get());
} else {
ExitCode = Tool.run(Factory.get());
if (!ExportFixes.empty()) {
std::error_code EC;
llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::F_None);
if (EC) {
llvm::errs() << "Error opening output file: " << EC.message() << '\n';
return 1;
}
// Export replacements.
tooling::TranslationUnitReplacements TUR;
const auto &FileToReplacements = Tool.getReplacements();
for (const auto &Entry : FileToReplacements)
TUR.Replacements.insert(TUR.Replacements.end(), Entry.second.begin(),
Entry.second.end());
yaml::Output YAML(OS);
YAML << TUR;
OS.close();
return 0;
}
// Write every file to stdout. Right now we just barf the files without any
// indication of which files start where, other than that we print the files
// in the same order we see them.
LangOptions DefaultLangOptions;
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
DiagnosticsEngine Diagnostics(
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
&DiagnosticPrinter, false);
auto &FileMgr = Tool.getFiles();
SourceManager Sources(Diagnostics, FileMgr);
Rewriter Rewrite(Sources, DefaultLangOptions);
Tool.applyAllReplacements(Rewrite);
for (const auto &File : Files) {
const auto *Entry = FileMgr.getFile(File);
const auto ID = Sources.getOrCreateFileID(Entry, SrcMgr::C_User);
Rewrite.getEditBuffer(ID).write(outs());
}
}
return ExitCode;
}

View File

@@ -0,0 +1,79 @@
;;; clang-rename.el --- Renames every occurrence of a symbol found at <offset>. -*- lexical-binding: t; -*-
;; Keywords: tools, c
;;; Commentary:
;; To install clang-rename.el make sure the directory of this file is in your
;; `load-path' and add
;;
;; (require 'clang-rename)
;;
;; to your .emacs configuration.
;;; Code:
(defgroup clang-rename nil
"Integration with clang-rename"
:group 'c)
(defcustom clang-rename-binary "clang-rename"
"Path to clang-rename executable."
:type '(file :must-match t)
:group 'clang-rename)
;;;###autoload
(defun clang-rename (new-name)
"Rename all instances of the symbol at point to NEW-NAME using clang-rename."
(interactive "sEnter a new name: ")
(save-some-buffers :all)
;; clang-rename should not be combined with other operations when undoing.
(undo-boundary)
(let ((output-buffer (get-buffer-create "*clang-rename*")))
(with-current-buffer output-buffer (erase-buffer))
(let ((exit-code (call-process
clang-rename-binary nil output-buffer nil
(format "-offset=%d"
;; clang-rename wants file (byte) offsets, not
;; buffer (character) positions.
(clang-rename--bufferpos-to-filepos
;; Emacs treats one character after a symbol as
;; part of the symbol, but clang-rename doesnt.
;; Use the beginning of the current symbol, if
;; available, to resolve the inconsistency.
(or (car (bounds-of-thing-at-point 'symbol))
(point))
'exact))
(format "-new-name=%s" new-name)
"-i" (buffer-file-name))))
(if (and (integerp exit-code) (zerop exit-code))
;; Success; revert current buffer so it gets the modifications.
(progn
(kill-buffer output-buffer)
(revert-buffer :ignore-auto :noconfirm :preserve-modes))
;; Failure; append exit code to output buffer and display it.
(let ((message (clang-rename--format-message
"clang-rename failed with %s %s"
(if (integerp exit-code) "exit status" "signal")
exit-code)))
(with-current-buffer output-buffer
(insert ?\n message ?\n))
(message "%s" message)
(display-buffer output-buffer))))))
(defalias 'clang-rename--bufferpos-to-filepos
(if (fboundp 'bufferpos-to-filepos)
'bufferpos-to-filepos
;; Emacs 24 doesnt have bufferpos-to-filepos, simulate it using
;; position-bytes.
(lambda (position &optional _quality _coding-system)
(1- (position-bytes position)))))
;; format-message is new in Emacs 25.1. Provide a fallback for older
;; versions.
(defalias 'clang-rename--format-message
(if (fboundp 'format-message) 'format-message 'format))
(provide 'clang-rename)
;;; clang-rename.el ends here

View File

@@ -0,0 +1,61 @@
'''
Minimal clang-rename integration with Vim.
Before installing make sure one of the following is satisfied:
* clang-rename is in your PATH
* `g:clang_rename_path` in ~/.vimrc points to valid clang-rename executable
* `binary` in clang-rename.py points to valid to clang-rename executable
To install, simply put this into your ~/.vimrc
noremap <leader>cr :pyf <path-to>/clang-rename.py<cr>
IMPORTANT NOTE: Before running the tool, make sure you saved the file.
All you have to do now is to place a cursor on a variable/function/class which
you would like to rename and press '<leader>cr'. You will be prompted for a new
name if the cursor points to a valid symbol.
'''
import vim
import subprocess
import sys
def main():
binary = 'clang-rename'
if vim.eval('exists("g:clang_rename_path")') == "1":
binary = vim.eval('g:clang_rename_path')
# Get arguments for clang-rename binary.
offset = int(vim.eval('line2byte(line("."))+col(".")')) - 2
if offset < 0:
print >> sys.stderr, '''Couldn\'t determine cursor position.
Is your file empty?'''
return
filename = vim.current.buffer.name
new_name_request_message = 'type new name:'
new_name = vim.eval("input('{}\n')".format(new_name_request_message))
# Call clang-rename.
command = [binary,
filename,
'-i',
'-offset', str(offset),
'-new-name', str(new_name)]
# FIXME: make it possible to run the tool on unsaved file.
p = subprocess.Popen(command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if stderr:
print stderr
# Reload all buffers in Vim.
vim.command("checktime")
if __name__ == '__main__':
main()