Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(clang-apply-replacements) add_subdirectory(clang-rename) +add_subdirectory(clang-refactor) add_subdirectory(clang-reorder-fields) add_subdirectory(modularize) if(CLANG_ENABLE_STATIC_ANALYZER) @@ -23,4 +24,3 @@ if( CLANG_TOOLS_EXTRA_INCLUDE_DOCS ) add_subdirectory(docs) endif() - Index: clang-refactor/CMakeLists.txt =================================================================== --- /dev/null +++ clang-refactor/CMakeLists.txt @@ -0,0 +1,4 @@ +include_directories(modules) + +add_subdirectory(driver) +add_subdirectory(modules) Index: clang-refactor/driver/CMakeLists.txt =================================================================== --- /dev/null +++ clang-refactor/driver/CMakeLists.txt @@ -0,0 +1,17 @@ +set(LLVM_LINK_COMPONENTS + Support + ) + +add_clang_executable(clang-refactor + Driver.cpp + + ModuleManager.cpp + ) + +target_link_libraries(clang-refactor + clangAST + clangASTMatchers + clangBasic + clangFrontend + clangTooling + ) Index: clang-refactor/driver/Driver.cpp =================================================================== --- /dev/null +++ clang-refactor/driver/Driver.cpp @@ -0,0 +1,55 @@ +//===--- Driver.cpp - clang-refactor ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file This file implements a clang-refactor tool. +/// +////===----------------------------------------------------------------------===// + +#include "clang/Tooling/CommonOptionsParser.h" +#include "llvm/Support/raw_ostream.h" + +#include "ModuleManager.h" + +namespace clang { +namespace refactor { + +const char HelpHead[] = "USAGE: clang-refactor [subcommand] [options] " + " [... ]\n" + "\n" + "Subcommands:\n"; + +static int printHelpMessage() { + llvm::outs() << HelpHead; + return 1; +} + +int clangRefactorMain(int argc, const char **argv) { + ModuleManager Manager; + std::string Command = ""; + if (argc > 1) { + llvm::StringRef FirstArgument(argv[1]); + if (FirstArgument == "-h" || FirstArgument == "-help" || + FirstArgument == "--help") + return printHelpMessage(); + Command = argv[1]; + std::string Invocation = std::string(argv[0]) + " " + argv[1]; + argv[1] = Invocation.c_str(); + Manager.Dispatch(Command, argc - 1, argv + 1); + } else { + return printHelpMessage(); + } + return 0; +} + +} // end namespace refactor +} // end namespace clang + +int main(int argc, const char **argv) { + return clang::refactor::clangRefactorMain(argc, argv); +} Index: clang-refactor/driver/ModuleManager.h =================================================================== --- /dev/null +++ clang-refactor/driver/ModuleManager.h @@ -0,0 +1,40 @@ +//===--- ModuleManager.h - clang-refactor -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_REFACTOR_MODULE_MANAGER_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_REFACTOR_MODULE_MANAGER_H + +#include "llvm/ADT/StringRef.h" + +#include +#include +#include + +#include "core/RefactoringModule.h" + +using namespace llvm; + +namespace clang { +namespace refactor { + +class ModuleManager { +public: + void AddModule(StringRef Command, std::unique_ptr Module); + + int Dispatch(StringRef Command, int argc, const char **argv); + +private: + std::vector> RegisteredModules; + std::unordered_map CommandToModuleID; +}; + +} // end namespace refactor +} // end namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_REFACTOR_MODULE_MANAGER_H Index: clang-refactor/driver/ModuleManager.cpp =================================================================== --- /dev/null +++ clang-refactor/driver/ModuleManager.cpp @@ -0,0 +1,29 @@ +//===--- ModuleManager.cpp - clang-refactor ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ModuleManager.h" + +namespace clang { +namespace refactor { + +void ModuleManager::AddModule(StringRef Command, + std::unique_ptr Module) { + RegisteredModules.push_back(std::move(Module)); + CommandToModuleID[Command] = RegisteredModules.size() - 1; +} + +int ModuleManager::Dispatch(StringRef Command, int argc, const char **argv) { + if (CommandToModuleID.find(Command) != CommandToModuleID.end()) { + return RegisteredModules[CommandToModuleID[Command]]->run(argc, argv); + } + return 1; +} + +} // end namespace refactor +} // end namespace clang Index: clang-refactor/modules/CMakeLists.txt =================================================================== --- /dev/null +++ clang-refactor/modules/CMakeLists.txt @@ -0,0 +1 @@ +include_directories(core) Index: clang-refactor/modules/core/RefactoringModule.h =================================================================== --- /dev/null +++ clang-refactor/modules/core/RefactoringModule.h @@ -0,0 +1,169 @@ +//===--- RefactoringModule.h - clang-refactor -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_REFACTOR_REFACTORING_MODULE_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_REFACTOR_REFACTORING_MODULE_H + +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Signals.h" + +#include + +namespace clang { +namespace refactor { + +class RefactoringModule { +public: + RefactoringModule(const std::string &ModuleName, + const std::string &ModuleMetaDescription) + : ModuleName(ModuleName), ModuleMetaDescription(ModuleMetaDescription) {} + + // Refactoring consists of 3.5 stages: + // + // 0. Check arguments for validity. + // + // 1. Extract infromation needed for the refactoring upon tool invocation. + // + // 2. Handle translation unit and identify whether the refactoring can be + // applied. If it can, store the replacements. Panic otherwise. + // + // 3. Merge duplicate replacements, panic if there are conflicting ones. + // Process translation unit and apply refactoring. + // + // Few examples of how each of these stages would look like for future + // modules "rename" and "inline". + // + // Rename + // ====== + // + // 0. Check arguments for validity. + // + // 1. Rename operates with USRs, so the first stage would be finding the + // symbol, which will be renamed and storing its USR. + // + // 2. Check whether renaming will introduce any name conflicts. If it won't + // find each occurance of the symbol in translation unit using USR and store + // replacements. + // + // 3. Apply replacements or output diagnostics. Handle duplicates and panic if + // there are conflicts. + // + // Inline + // ====== + // + // 0. Check arguments for validity. + // + // 1. Find function, identify what the possible issues might be. + // + // 2. Check whether inlining will introduce any issues, e.g. there is a + // pointer passed somewhere to the inlined function and after inlining it the + // code will no longer compile. If it won't find function calls, add needed + // temprorary variables and replace the call with function body. + // + // 3. Apply replacements. Handle duplicates and panic if there are conflicts. + // + // Summary + // ======= + // + // As one can easily see, step 1 should be performed upon module invocation + // and it needs to process translation unit, from which the passed + // comes from. + // + // With appropriate facilities step 2 can be parallelized to process multiple + // translation units of the project independently. If none of them have any + // issues with applying this refactoring replacements are stored and queued + // for later. + // + // Step 3 can be parallelized even more easily. It basically consists of text + // replacements. + // + int run(int argc, const char **argv) { + // Register options. + llvm::cl::OptionCategory RefactoringModuleOptions(ModuleName.c_str(), + ModuleMetaDescription.c_str()); + registerCustomOptions(RefactoringModuleOptions); + registerCustomOptions(RefactoringModuleOptions); + // Parse options and get compilations. + llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); + tooling::CommonOptionsParser OptionsParser(argc, argv, + RefactoringModuleOptions); + tooling::RefactoringTool Tool(OptionsParser.getCompilations(), + OptionsParser.getSourcePathList()); + + // Actual routine. + checkArguments(); + extractRefactoringInformation(); + handleTranslationUnit(); + applyReplacementsOrOutputDiagnostics(); + return 0; + } + + // Routine for regiestering common modules options. + void registerCommonOptions(llvm::cl::OptionCategory &Category) { + } + + // A way for each tool to provide additional options. Overriding this one is + // optional. + virtual void registerCustomOptions(llvm::cl::OptionCategory &Category) {} + + // Step 0. + // Just checking arguments. + // + // Panic: if they are not valid. + virtual int checkArguments() = 0; + + // Step 1. + // + // Process translation and figure out what should be done. + // + // Panic: if refactoring can not be applied. E.g. unsupported cases like + // renaming macros etc. + virtual int extractRefactoringInformation() = 0; + + // Step 2. + // + // Find places where refactoring should be applied and store replacements for + // the future. + // + // Panic: if there are any issues with applying refactorings to the + // translation unit. + virtual int handleTranslationUnit() = 0; + + // Step 3. + // + // Handle duplicates. + // + // Panic: if there are conflicting replacements. + virtual int applyReplacementsOrOutputDiagnostics() = 0; + + virtual ~RefactoringModule() = default; + + StringRef getModuleName() { return ModuleName; } + + StringRef getModuleMetaDescription() { return ModuleMetaDescription; } + +private: + // ModuleName is the lowercase submodule name, which will be passed to + // clang-refactor to invoke the submodule tool. + const std::string ModuleName; + + // ModuleMetaDescription will appear as the module description upon calling + // $ clang-refactor --help + const std::string ModuleMetaDescription; +}; + +} // end namespace refactor +} // end namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_REFACTOR_REFACTORING_MODULE_H