From 5dbd3e0d1d3aad9ce3bb5063d6932c880c498a8a Mon Sep 17 00:00:00 2001 From: LiuYuHui Date: Wed, 15 Jul 2020 15:31:22 +0800 Subject: [PATCH 1/5] refactor multiclass --- refactor_multiclass/CMakeLists.txt | 34 +++++++++++++++++++ refactor_multiclass/multiclass.cpp | 53 ++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 refactor_multiclass/CMakeLists.txt create mode 100644 refactor_multiclass/multiclass.cpp diff --git a/refactor_multiclass/CMakeLists.txt b/refactor_multiclass/CMakeLists.txt new file mode 100644 index 0000000..1013c5a --- /dev/null +++ b/refactor_multiclass/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.10) +project(find_labels) + +find_package(LLVM REQUIRED CONFIG) +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +add_definitions(${LLVM_DEFINITIONS}) +link_directories(${LLVM_LIBRARY_DIRS}) +llvm_map_components_to_libnames(llvm_libs x86asmparser bitreader support mc option profiledata) + +add_executable(find_labels multiclass.cpp) +target_include_directories(find_labels PRIVATE ${LLVM_INCLUDE_DIRS}) +target_link_libraries(find_labels PRIVATE + clangFrontend + clangSerialization + clangDriver + clangTooling + clangParse + clangSema + clangAnalysis + clangRewriteFrontend + clangRewrite + clangEdit + clangAST + clangLex + clangBasic + clangASTMatchers + ${llvm_libs}) +set_target_properties(find_labels PROPERTIES COMPILE_FLAGS -fno-rtti) +target_compile_options(find_labels PRIVATE -g) diff --git a/refactor_multiclass/multiclass.cpp b/refactor_multiclass/multiclass.cpp new file mode 100644 index 0000000..ccf1df4 --- /dev/null +++ b/refactor_multiclass/multiclass.cpp @@ -0,0 +1,53 @@ +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +// Declares clang::SyntaxOnlyAction. +#include "clang/Frontend/FrontendActions.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Tooling.h" +// Declares llvm::cl::extrahelp. +#include "clang/AST/Stmt.h" +#include "llvm/Support/CommandLine.h" +#include +using namespace clang::tooling; +using namespace llvm; +using namespace clang; +using namespace clang::ast_matchers; + +// Apply a custom category to all command-line options so that they are the +// only ones displayed. +static llvm::cl::OptionCategory MyToolCategory("my-tool options"); + +// CommonOptionsParser declares HelpMessage with a description of the common +// command-line options related to the compilation database and input files. +// It's nice to have this help message in all tools. +static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); + +// A help message for this specific tool can be added afterwards. + +auto LabelMatcher = cxxRecordDecl(isDerivedFrom(hasName("MulticlassMachine"))).bind("multiclass"); + +std::set func_names; +class labels_matcher : public MatchFinder::MatchCallback +{ +public: + void run(const MatchFinder::MatchResult &Result) + { + ASTContext *Context = Result.Context; + const CXXRecordDecl *FS = Result.Nodes.getNodeAs("multiclass"); + const auto &SM = Result.SourceManager; + llvm::outs() << FS->getName () ; + } +}; + +int main(int argc, const char **argv) +{ + CommonOptionsParser OptionsParser(argc, argv, MyToolCategory); + ClangTool Tool(OptionsParser.getCompilations(), + OptionsParser.getSourcePathList()); + + labels_matcher Printer; + MatchFinder Finder; + Finder.addMatcher(LabelMatcher, &Printer); + + return Tool.run(newFrontendActionFactory(&Finder).get()); +} From eeec93dfdca92715a7995b47e2a1f5508f698f03 Mon Sep 17 00:00:00 2001 From: LiuYuHui Date: Fri, 17 Jul 2020 10:59:05 +0800 Subject: [PATCH 2/5] support cxxmethod and cxxconstructor --- refactor_multiclass/CMakeLists.txt | 12 +-- refactor_multiclass/multiclass.cpp | 133 ++++++++++++++++++++++++++--- 2 files changed, 126 insertions(+), 19 deletions(-) diff --git a/refactor_multiclass/CMakeLists.txt b/refactor_multiclass/CMakeLists.txt index 1013c5a..4724428 100644 --- a/refactor_multiclass/CMakeLists.txt +++ b/refactor_multiclass/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(find_labels) +project(multiclass) find_package(LLVM REQUIRED CONFIG) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") @@ -12,9 +12,9 @@ add_definitions(${LLVM_DEFINITIONS}) link_directories(${LLVM_LIBRARY_DIRS}) llvm_map_components_to_libnames(llvm_libs x86asmparser bitreader support mc option profiledata) -add_executable(find_labels multiclass.cpp) -target_include_directories(find_labels PRIVATE ${LLVM_INCLUDE_DIRS}) -target_link_libraries(find_labels PRIVATE +add_executable(multiclass multiclass.cpp) +target_include_directories(multiclass PRIVATE ${LLVM_INCLUDE_DIRS}) +target_link_libraries(multiclass PRIVATE clangFrontend clangSerialization clangDriver @@ -30,5 +30,5 @@ target_link_libraries(find_labels PRIVATE clangBasic clangASTMatchers ${llvm_libs}) -set_target_properties(find_labels PROPERTIES COMPILE_FLAGS -fno-rtti) -target_compile_options(find_labels PRIVATE -g) +set_target_properties(multiclass PROPERTIES COMPILE_FLAGS -fno-rtti) +target_compile_options(multiclass PRIVATE -g) diff --git a/refactor_multiclass/multiclass.cpp b/refactor_multiclass/multiclass.cpp index ccf1df4..74e91cd 100644 --- a/refactor_multiclass/multiclass.cpp +++ b/refactor_multiclass/multiclass.cpp @@ -7,6 +7,11 @@ // Declares llvm::cl::extrahelp. #include "clang/AST/Stmt.h" #include "llvm/Support/CommandLine.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "llvm/Support/raw_ostream.h" +#include "clang/Frontend/CompilerInstance.h" + + #include using namespace clang::tooling; using namespace llvm; @@ -17,26 +22,132 @@ using namespace clang::ast_matchers; // only ones displayed. static llvm::cl::OptionCategory MyToolCategory("my-tool options"); -// CommonOptionsParser declares HelpMessage with a description of the common -// command-line options related to the compilation database and input files. -// It's nice to have this help message in all tools. + static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); -// A help message for this specific tool can be added afterwards. -auto LabelMatcher = cxxRecordDecl(isDerivedFrom(hasName("MulticlassMachine"))).bind("multiclass"); +auto constructorParameter = cxxConstructorDecl( + hasAnyParameter(hasType(asString("std::shared_ptr"))), + ofClass(isDerivedFrom("MulticlassMachine")) + ).bind("constructor"); + +auto method_mathcher = memberExpr(member(hasName("m_labels")), + hasAncestor(cxxMethodDecl(ofClass(isDerivedFrom("MulticlassMachine"))).bind("method"))).bind("labels"); std::set func_names; class labels_matcher : public MatchFinder::MatchCallback { public: - void run(const MatchFinder::MatchResult &Result) + labels_matcher(Rewriter& rewriter) : m_rewriter(rewriter) {} + void run(const MatchFinder::MatchResult &Result) override { ASTContext *Context = Result.Context; - const CXXRecordDecl *FS = Result.Nodes.getNodeAs("multiclass"); + const CXXMethodDecl *FS = Result.Nodes.getNodeAs("method"); + const MemberExpr* expr = Result.Nodes.getNodeAs("labels"); + auto SM = Result.SourceManager; + std::string func_name = FS->getNameAsString(); + std::string record_name = FS->getParent()->getNameAsString(); + bool has_labels = false; + for(auto para = FS->param_begin (); para != FS->param_end(); ++ para){ + llvm::outs()<getName ()<<"\n"; + if((*para)->getTypeSourceInfo ()->getType ().getAsString()== "std::shared_ptr"){ + has_labels = true; + } + } + m_rewriter.ReplaceText (expr->getMemberLoc(), 8, "labs"); + if(!has_labels && func_names.find(func_name) == func_names.end()){ + func_names.insert(func_name); + auto loc = FS ->getTypeSourceInfo ()->getTypeLoc ().getAs(); + StringRef to_be_inserted; + if(FS->param_size () ==0){ + to_be_inserted = "const std::shared_ptr& labs"; + } + else + { + to_be_inserted = ", const std::shared_ptr& labs"; + } + m_rewriter.InsertTextAfter(loc.getLocalSourceRange ().getEnd(), to_be_inserted); + //llvm::outs()<("constructor"); + const auto &SM = Result.SourceManager; - llvm::outs() << FS->getName () ; + + + if(FS->param_size() == 1 && FS->getParamDecl(0)->getType() + .getAsString()== "std::shared_ptr") + { + m_rewriter.RemoveText(FS->getSourceRange()); + } + else + { + for(auto parm = FS->param_begin(); parm != FS->param_end(); ++parm) + { + if((*parm)->getType().getAsString() == "std::shared_ptr") + { + SourceRange loc ((*parm)->getSourceRange()); + m_rewriter.RemoveText(loc.getBegin(), m_rewriter.getRangeSize(loc) + 1); + } + } + } + } + +private: + Rewriter& m_rewriter; +}; +class MyASTConsumer : public ASTConsumer { +public: + MyASTConsumer(Rewriter &R) : HandlerForConstructor(R), HandlerForlabels(R) { + Matcher.addMatcher(method_mathcher, &HandlerForlabels); + Matcher.addMatcher(constructorParameter, &HandlerForConstructor); + + } + void HandleTranslationUnit(ASTContext &Context) override { + // Run the matchers when we have the whole TU parsed. + Matcher.matchAST(Context); + } + +private: + labels_matcher HandlerForlabels; + RemoveConstructorParameter HandlerForConstructor; + MatchFinder Matcher; +}; + + +class MyFrontendAction : public ASTFrontendAction { +public: + MyFrontendAction() {} + void EndSourceFileAction() override { + std::error_code error_code; + auto fEntry = TheRewriter.getSourceMgr().getFileEntryForID(TheRewriter.getSourceMgr() + .getMainFileID()); + llvm::raw_fd_ostream outFile(fEntry->getName(), error_code, llvm::sys::fs::F_None); + TheRewriter.getEditBuffer(TheRewriter.getSourceMgr().getMainFileID()) + .write(outFile); + outFile.close(); + } + + std::unique_ptr CreateASTConsumer(CompilerInstance &CI, + StringRef file) override { + TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts()); + return llvm::make_unique(TheRewriter); + } + +private: + Rewriter TheRewriter; }; int main(int argc, const char **argv) @@ -45,9 +156,5 @@ int main(int argc, const char **argv) ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList()); - labels_matcher Printer; - MatchFinder Finder; - Finder.addMatcher(LabelMatcher, &Printer); - - return Tool.run(newFrontendActionFactory(&Finder).get()); + return Tool.run(newFrontendActionFactory().get()); } From 7754b4c9723edcc4ba7bda3730550ee78271b6d4 Mon Sep 17 00:00:00 2001 From: LiuYuHui Date: Mon, 20 Jul 2020 19:28:09 +0800 Subject: [PATCH 3/5] use clang-tidy --- .../RefectormulticlassCheck.cpp | 88 +++++++++++++++++++ refactor_multiclass/RefectormulticlassCheck.h | 36 ++++++++ 2 files changed, 124 insertions(+) create mode 100644 refactor_multiclass/RefectormulticlassCheck.cpp create mode 100644 refactor_multiclass/RefectormulticlassCheck.h diff --git a/refactor_multiclass/RefectormulticlassCheck.cpp b/refactor_multiclass/RefectormulticlassCheck.cpp new file mode 100644 index 0000000..16516c4 --- /dev/null +++ b/refactor_multiclass/RefectormulticlassCheck.cpp @@ -0,0 +1,88 @@ +//===--- RefectormulticlassCheck.cpp - clang-tidy -------------------------===// +// +// 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 "RefectormulticlassCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +void RefectormulticlassCheck::traverseAllParentFunction(const CXXMethodDecl* method){ + if(method->getParent()->getName()=="MulticlassMachine"){ + return ; + } + for(auto methods = method->begin_overridden_methods (); + methods != method->end_overridden_methods (); ++methods){ + llvm::outs()<<(*methods)-> getParent()->getName()<< "::" + <<(*methods)->getName()<<"\n"; + traverseAllParentFunction(*methods); + } +} +void RefectormulticlassCheck::registerMatchers(MatchFinder *Finder) { + auto labels = memberExpr(member(hasName("m_labels")), + hasAncestor(cxxRecordDecl(isSameOrDerivedFrom("MulticlassMachine")))); + + auto methods = cxxMethodDecl(hasDescendant(labels), + ofClass(isSameOrDerivedFrom("MulticlassMachine")), + unless(hasAnyParameter(parmVarDecl(hasType(asString("std::shared_ptr"))))) + ); + + auto call_methods = cxxMemberCallExpr(callee(methods)); + Finder->addMatcher(labels.bind("addLabels"), this); + Finder->addMatcher(methods.bind("addLabels"), this); + Finder->addMatcher(call_methods.bind("addLabels"), this); +} + +void RefectormulticlassCheck::check(const MatchFinder::MatchResult &Result) { + if(const auto *MatchedDecl = Result.Nodes.getNodeAs("addLabels")){ + auto removeRange = CharSourceRange::getCharRange( + MatchedDecl->getEndLoc(), MatchedDecl->getEndLoc().getLocWithOffset(sizeof("m_labels") - 1)); + diag(MatchedDecl->getBeginLoc(), "memberExpr %0 will be changed") + << MatchedDecl->getBase(); + diag(MatchedDecl->getExprLoc(), "rename m_labels", DiagnosticIDs::Note) + <("addLabels")){ + auto loc = MatchedDecl ->getTypeSourceInfo ()->getTypeLoc ().getAs(); + llvm::outs()<size_overridden_methods ()<<"\n"; + for(auto methods = MatchedDecl->begin_overridden_methods (); + methods != MatchedDecl->end_overridden_methods (); ++methods){ + llvm::outs()<<(*methods)-> getParent()->getName()<<"\n"; + traverseAllParentFunction(*methods); + } + diag(MatchedDecl->getBeginLoc(), "function %0 should add argument") + << MatchedDecl->getName(); + diag(MatchedDecl->getEndLoc(), "add labs argument", DiagnosticIDs::Note) + <& labs"); + + } + if(const auto *MatchedDecl = Result.Nodes.getNodeAs("addLabels")){ + auto parm_size = MatchedDecl->getMethodDecl () ->param_size (); + auto paramRange = MatchedDecl->getEndLoc(); + diag(MatchedDecl->getEndLoc(), "callExpr %0 will be changed") + << MatchedDecl->getMethodDecl()->getName(); + StringRef inserted_context; + if(parm_size > 0){ + inserted_context = ", labs" ; + } + else{ + inserted_context = "labs" ; + } + diag(MatchedDecl->getEndLoc(), "add labs argument", DiagnosticIDs::Note) + < Date: Tue, 21 Jul 2020 21:49:15 +0800 Subject: [PATCH 4/5] refine script --- .../RefectormulticlassCheck.cpp | 235 +++++++++++++----- refactor_multiclass/RefectormulticlassCheck.h | 51 ++-- refactor_multiclass/multiclass.cpp | 160 ------------ 3 files changed, 199 insertions(+), 247 deletions(-) delete mode 100644 refactor_multiclass/multiclass.cpp diff --git a/refactor_multiclass/RefectormulticlassCheck.cpp b/refactor_multiclass/RefectormulticlassCheck.cpp index 16516c4..924e7cd 100644 --- a/refactor_multiclass/RefectormulticlassCheck.cpp +++ b/refactor_multiclass/RefectormulticlassCheck.cpp @@ -12,77 +12,178 @@ using namespace clang::ast_matchers; -namespace clang { -namespace tidy { -namespace misc { +namespace clang +{ + namespace tidy + { + namespace misc + { -void RefectormulticlassCheck::traverseAllParentFunction(const CXXMethodDecl* method){ - if(method->getParent()->getName()=="MulticlassMachine"){ - return ; - } - for(auto methods = method->begin_overridden_methods (); - methods != method->end_overridden_methods (); ++methods){ - llvm::outs()<<(*methods)-> getParent()->getName()<< "::" - <<(*methods)->getName()<<"\n"; + void RefectormulticlassCheck::changeAllSharedPtrToConst( + const CXXMethodDecl *method) + { + for (auto parm = method->param_begin(); parm != method->param_end(); ++parm) + { + if (StringRef((*parm)->getType().getAsString()) + .startswith("std::shared_ptr<")) + { + diag((*parm)->getEndLoc(), "add const reference") + << (*parm)->getNameAsString(); + diag((*parm)->getBeginLoc(), "remove labs argument", DiagnosticIDs::Note) + << FixItHint::CreateInsertion((*parm)->getBeginLoc(), "const ") + << FixItHint::CreateInsertion((*parm)->getEndLoc(), "&"); + } + } + } + std::string + RefectormulticlassCheck::getFunctionName(const CXXMethodDecl *method) + { + std::string func_name = method->getNameAsString(); + std::string record_name = method->getParent()->getNameAsString(); + return record_name + "::" + func_name; + } + void RefectormulticlassCheck::traverseAllParentFunction( + const CXXMethodDecl *method) + { + if (method->getParent()->getNameAsString() == "Machine") + { + return; + } + changeAllSharedPtrToConst(method); + std::string funcName = getFunctionName(method); + if (funcRefactored.find(funcName) == funcRefactored.end()) + { + funcRefactored.insert(funcName); + auto loc = + method->getTypeSourceInfo()->getTypeLoc().getAs(); + diag(method->getBeginLoc(), "function %0 should add argument") + << method->getNameAsString(); + diag(method->getEndLoc(), "add labs argument", DiagnosticIDs::Note) + << FixItHint::CreateInsertion(loc.getLocalSourceRange().getEnd(), + ", const std::shared_ptr& labs"); + } + for (auto methods = method->begin_overridden_methods(); + methods != method->end_overridden_methods(); ++methods) + { + // llvm::outs() << (*methods)->getParent()->getNameAsString() + // << "::" << (*methods)->getNameAsString() << "\n"; + traverseAllParentFunction(*methods); + } + } + void RefectormulticlassCheck::registerMatchers(MatchFinder *Finder) + { + auto labels = memberExpr(member(hasName("m_labels")), + hasAncestor(cxxMethodDecl(ofClass( + isSameOrDerivedFrom("MulticlassMachine"))))); + // cxxConstructorDecl(hasAnyParameter(parmVarDecl(hasType(asString("std::shared_ptr"))))) + auto methods = cxxMethodDecl( + hasDescendant(labels), ofClass(isSameOrDerivedFrom("MulticlassMachine")), + unless(hasAnyParameter( + parmVarDecl(hasType(asString("std::shared_ptr")))))); + auto constructor = + cxxConstructorDecl(hasAnyParameter(parmVarDecl( + hasType(asString("std::shared_ptr")))), + ofClass(isSameOrDerivedFrom("MulticlassMachine"))); + + auto call_methods = cxxMemberCallExpr(callee(methods)); + Finder->addMatcher(labels.bind("addLabels"), this); + Finder->addMatcher(constructor.bind("removeLabels"), this); + Finder->addMatcher(methods.bind("addLabels"), this); + Finder->addMatcher(call_methods.bind("addLabels"), this); + } + + void RefectormulticlassCheck::check(const MatchFinder::MatchResult &Result) + { + if (const auto *MatchedDecl = + Result.Nodes.getNodeAs("addLabels")) + { + auto removeRange = CharSourceRange::getCharRange( + MatchedDecl->getEndLoc(), + MatchedDecl->getEndLoc().getLocWithOffset(sizeof("m_labels") - 1)); + diag(MatchedDecl->getBeginLoc(), "memberExpr %0 will be changed") + << MatchedDecl->getBase(); + diag(MatchedDecl->getExprLoc(), "rename m_labels", DiagnosticIDs::Note) + << FixItHint::CreateReplacement(removeRange, "labs"); + } + if (const auto *MatchedDecl = + Result.Nodes.getNodeAs("addLabels")) + { + changeAllSharedPtrToConst(MatchedDecl); + auto loc = + MatchedDecl->getTypeSourceInfo()->getTypeLoc().getAs(); + // llvm::outs()<size_overridden_methods ()<<"\n"; + for (auto methods = MatchedDecl->begin_overridden_methods(); + methods != MatchedDecl->end_overridden_methods(); ++methods) + { + // llvm::outs() << (*methods)->getParent()->getNameAsString() << "\n"; traverseAllParentFunction(*methods); - } -} -void RefectormulticlassCheck::registerMatchers(MatchFinder *Finder) { - auto labels = memberExpr(member(hasName("m_labels")), - hasAncestor(cxxRecordDecl(isSameOrDerivedFrom("MulticlassMachine")))); + } + std::string funcName = getFunctionName(MatchedDecl); + if (funcRefactored.find(funcName) == funcRefactored.end()) + { + funcRefactored.insert(funcName); + diag(MatchedDecl->getBeginLoc(), "function %0 should add argument") + << MatchedDecl->getNameAsString(); + diag(MatchedDecl->getEndLoc(), "add labs argument", DiagnosticIDs::Note) + << FixItHint::CreateInsertion( + loc.getLocalSourceRange().getEnd(), + ", const std::shared_ptr& labs"); + } + } + if (const auto *MatchedDecl = + Result.Nodes.getNodeAs("addLabels")) + { + auto parm_size = MatchedDecl->getMethodDecl()->param_size(); + auto paramRange = MatchedDecl->getEndLoc(); - auto methods = cxxMethodDecl(hasDescendant(labels), - ofClass(isSameOrDerivedFrom("MulticlassMachine")), - unless(hasAnyParameter(parmVarDecl(hasType(asString("std::shared_ptr"))))) - ); + diag(MatchedDecl->getEndLoc(), "callExpr %0 will be changed") + << MatchedDecl->getMethodDecl()->getNameAsString(); + std::string inserted_context; + if (parm_size > 0) + { + inserted_context = ", labs"; + } + else + { + inserted_context = "labs"; + } + diag(MatchedDecl->getEndLoc(), "add labs argument", DiagnosticIDs::Note) + << FixItHint::CreateInsertion(paramRange, inserted_context); + } - auto call_methods = cxxMemberCallExpr(callee(methods)); - Finder->addMatcher(labels.bind("addLabels"), this); - Finder->addMatcher(methods.bind("addLabels"), this); - Finder->addMatcher(call_methods.bind("addLabels"), this); -} + if (const auto *MatchedDecl = + Result.Nodes.getNodeAs("removeLabels")) + { -void RefectormulticlassCheck::check(const MatchFinder::MatchResult &Result) { - if(const auto *MatchedDecl = Result.Nodes.getNodeAs("addLabels")){ - auto removeRange = CharSourceRange::getCharRange( - MatchedDecl->getEndLoc(), MatchedDecl->getEndLoc().getLocWithOffset(sizeof("m_labels") - 1)); - diag(MatchedDecl->getBeginLoc(), "memberExpr %0 will be changed") - << MatchedDecl->getBase(); - diag(MatchedDecl->getExprLoc(), "rename m_labels", DiagnosticIDs::Note) - <("addLabels")){ - auto loc = MatchedDecl ->getTypeSourceInfo ()->getTypeLoc ().getAs(); - llvm::outs()<size_overridden_methods ()<<"\n"; - for(auto methods = MatchedDecl->begin_overridden_methods (); - methods != MatchedDecl->end_overridden_methods (); ++methods){ - llvm::outs()<<(*methods)-> getParent()->getName()<<"\n"; - traverseAllParentFunction(*methods); - } - diag(MatchedDecl->getBeginLoc(), "function %0 should add argument") - << MatchedDecl->getName(); - diag(MatchedDecl->getEndLoc(), "add labs argument", DiagnosticIDs::Note) - <& labs"); - - } - if(const auto *MatchedDecl = Result.Nodes.getNodeAs("addLabels")){ - auto parm_size = MatchedDecl->getMethodDecl () ->param_size (); - auto paramRange = MatchedDecl->getEndLoc(); - diag(MatchedDecl->getEndLoc(), "callExpr %0 will be changed") - << MatchedDecl->getMethodDecl()->getName(); - StringRef inserted_context; - if(parm_size > 0){ - inserted_context = ", labs" ; - } - else{ - inserted_context = "labs" ; - } - diag(MatchedDecl->getEndLoc(), "add labs argument", DiagnosticIDs::Note) - <param_size() == 1 && + MatchedDecl->getParamDecl(0)->getType().getAsString() == + "std::shared_ptr") + { + diag(MatchedDecl->getEndLoc(), "should remove argument") + << MatchedDecl->getNameAsString(); + diag(MatchedDecl->getEndLoc(), "should remove argument", + DiagnosticIDs::Note) + << FixItHint::CreateRemoval(MatchedDecl->getSourceRange()); + } + else + { + for (auto parm = MatchedDecl->param_begin(); + parm != MatchedDecl->param_end(); ++parm) + { + if ((*parm)->getType().getAsString() == "std::shared_ptr") + { + SourceRange loc((*parm)->getSourceRange()); + diag(MatchedDecl->getEndLoc(), "should remove argument") + << MatchedDecl->getNameAsString(); + diag(MatchedDecl->getEndLoc(), "remove labs argument", + DiagnosticIDs::Note) + << FixItHint::CreateRemoval(loc); + } + } + } + } + } -} // namespace misc -} // namespace tidy + } // namespace misc + } // namespace tidy } // namespace clang diff --git a/refactor_multiclass/RefectormulticlassCheck.h b/refactor_multiclass/RefectormulticlassCheck.h index c515ec4..14e5ca0 100644 --- a/refactor_multiclass/RefectormulticlassCheck.h +++ b/refactor_multiclass/RefectormulticlassCheck.h @@ -10,27 +10,38 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_REFECTORMULTICLASSCHECK_H #include "../ClangTidyCheck.h" +#include +#include +namespace clang +{ + namespace tidy + { + namespace misc + { -namespace clang { -namespace tidy { -namespace misc { - -/// FIXME: Write a short description. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/misc-RefectorMulticlass.html -class RefectormulticlassCheck : public ClangTidyCheck { -public: - RefectormulticlassCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -private: - void traverseAllParentFunction(const CXXMethodDecl* method); -}; - -} // namespace misc -} // namespace tidy + /// FIXME: Write a short description. + /// + /// For the user-facing documentation see: + /// http://clang.llvm.org/extra/clang-tidy/checks/misc-RefectorMulticlass.html + class RefectormulticlassCheck : public ClangTidyCheck + { + public: + RefectormulticlassCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + + private: + void traverseAllParentFunction(const CXXMethodDecl *method); + + std::string getFunctionName(const CXXMethodDecl *method); + + void changeAllSharedPtrToConst(const CXXMethodDecl *method); + std::unordered_set funcRefactored; + }; + + } // namespace misc + } // namespace tidy } // namespace clang #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_REFECTORMULTICLASSCHECK_H diff --git a/refactor_multiclass/multiclass.cpp b/refactor_multiclass/multiclass.cpp deleted file mode 100644 index 74e91cd..0000000 --- a/refactor_multiclass/multiclass.cpp +++ /dev/null @@ -1,160 +0,0 @@ -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/ASTMatchers/ASTMatchers.h" -// Declares clang::SyntaxOnlyAction. -#include "clang/Frontend/FrontendActions.h" -#include "clang/Tooling/CommonOptionsParser.h" -#include "clang/Tooling/Tooling.h" -// Declares llvm::cl::extrahelp. -#include "clang/AST/Stmt.h" -#include "llvm/Support/CommandLine.h" -#include "clang/Rewrite/Core/Rewriter.h" -#include "llvm/Support/raw_ostream.h" -#include "clang/Frontend/CompilerInstance.h" - - -#include -using namespace clang::tooling; -using namespace llvm; -using namespace clang; -using namespace clang::ast_matchers; - -// Apply a custom category to all command-line options so that they are the -// only ones displayed. -static llvm::cl::OptionCategory MyToolCategory("my-tool options"); - - -static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); - - -auto constructorParameter = cxxConstructorDecl( - hasAnyParameter(hasType(asString("std::shared_ptr"))), - ofClass(isDerivedFrom("MulticlassMachine")) - ).bind("constructor"); - -auto method_mathcher = memberExpr(member(hasName("m_labels")), - hasAncestor(cxxMethodDecl(ofClass(isDerivedFrom("MulticlassMachine"))).bind("method"))).bind("labels"); - -std::set func_names; -class labels_matcher : public MatchFinder::MatchCallback -{ -public: - labels_matcher(Rewriter& rewriter) : m_rewriter(rewriter) {} - void run(const MatchFinder::MatchResult &Result) override - { - ASTContext *Context = Result.Context; - const CXXMethodDecl *FS = Result.Nodes.getNodeAs("method"); - const MemberExpr* expr = Result.Nodes.getNodeAs("labels"); - auto SM = Result.SourceManager; - std::string func_name = FS->getNameAsString(); - std::string record_name = FS->getParent()->getNameAsString(); - bool has_labels = false; - for(auto para = FS->param_begin (); para != FS->param_end(); ++ para){ - llvm::outs()<getName ()<<"\n"; - if((*para)->getTypeSourceInfo ()->getType ().getAsString()== "std::shared_ptr"){ - has_labels = true; - } - } - m_rewriter.ReplaceText (expr->getMemberLoc(), 8, "labs"); - if(!has_labels && func_names.find(func_name) == func_names.end()){ - func_names.insert(func_name); - auto loc = FS ->getTypeSourceInfo ()->getTypeLoc ().getAs(); - StringRef to_be_inserted; - if(FS->param_size () ==0){ - to_be_inserted = "const std::shared_ptr& labs"; - } - else - { - to_be_inserted = ", const std::shared_ptr& labs"; - } - m_rewriter.InsertTextAfter(loc.getLocalSourceRange ().getEnd(), to_be_inserted); - //llvm::outs()<("constructor"); - - const auto &SM = Result.SourceManager; - - - if(FS->param_size() == 1 && FS->getParamDecl(0)->getType() - .getAsString()== "std::shared_ptr") - { - m_rewriter.RemoveText(FS->getSourceRange()); - } - else - { - for(auto parm = FS->param_begin(); parm != FS->param_end(); ++parm) - { - if((*parm)->getType().getAsString() == "std::shared_ptr") - { - SourceRange loc ((*parm)->getSourceRange()); - m_rewriter.RemoveText(loc.getBegin(), m_rewriter.getRangeSize(loc) + 1); - } - } - } - - } - -private: - Rewriter& m_rewriter; -}; -class MyASTConsumer : public ASTConsumer { -public: - MyASTConsumer(Rewriter &R) : HandlerForConstructor(R), HandlerForlabels(R) { - Matcher.addMatcher(method_mathcher, &HandlerForlabels); - Matcher.addMatcher(constructorParameter, &HandlerForConstructor); - - } - void HandleTranslationUnit(ASTContext &Context) override { - // Run the matchers when we have the whole TU parsed. - Matcher.matchAST(Context); - } - -private: - labels_matcher HandlerForlabels; - RemoveConstructorParameter HandlerForConstructor; - MatchFinder Matcher; -}; - - -class MyFrontendAction : public ASTFrontendAction { -public: - MyFrontendAction() {} - void EndSourceFileAction() override { - std::error_code error_code; - auto fEntry = TheRewriter.getSourceMgr().getFileEntryForID(TheRewriter.getSourceMgr() - .getMainFileID()); - llvm::raw_fd_ostream outFile(fEntry->getName(), error_code, llvm::sys::fs::F_None); - TheRewriter.getEditBuffer(TheRewriter.getSourceMgr().getMainFileID()) - .write(outFile); - outFile.close(); - } - - std::unique_ptr CreateASTConsumer(CompilerInstance &CI, - StringRef file) override { - TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts()); - return llvm::make_unique(TheRewriter); - } - -private: - Rewriter TheRewriter; -}; - -int main(int argc, const char **argv) -{ - CommonOptionsParser OptionsParser(argc, argv, MyToolCategory); - ClangTool Tool(OptionsParser.getCompilations(), - OptionsParser.getSourcePathList()); - - return Tool.run(newFrontendActionFactory().get()); -} From eb7d793d6f76bb8acd99772b8001363c3a2381ca Mon Sep 17 00:00:00 2001 From: LiuYuHui Date: Thu, 23 Jul 2020 17:10:51 +0800 Subject: [PATCH 5/5] add support to cxxCtorInitializer --- .../RefectormulticlassCheck.cpp | 85 +++++++++++++++++-- refactor_multiclass/RefectormulticlassCheck.h | 3 + 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/refactor_multiclass/RefectormulticlassCheck.cpp b/refactor_multiclass/RefectormulticlassCheck.cpp index 924e7cd..8e5277d 100644 --- a/refactor_multiclass/RefectormulticlassCheck.cpp +++ b/refactor_multiclass/RefectormulticlassCheck.cpp @@ -9,7 +9,7 @@ #include "RefectormulticlassCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" - +#include "clang/Basic/SourceLocation.h" using namespace clang::ast_matchers; namespace clang @@ -19,6 +19,21 @@ namespace clang namespace misc { + void RefectormulticlassCheck::changeCorrespondMethod( + const CXXMethodDecl *method, const SourceManager &SM) + { + + auto MatchedDecl = + method->getCorrespondingMethodDeclaredInClass(method->getParent()); + auto loc = + MatchedDecl->getTypeSourceInfo()->getTypeLoc().getAs(); + // MatchedDecl->getBeginLoc().dump(SM); + diag(MatchedDecl->getBeginLoc(), "function %0 should add argument") + << MatchedDecl->getNameAsString(); + diag(MatchedDecl->getEndLoc(), "add labs argument", DiagnosticIDs::Note) + << FixItHint::CreateInsertion(loc.getLocalSourceRange().getEnd(), + ", const std::shared_ptr& labs"); + } void RefectormulticlassCheck::changeAllSharedPtrToConst( const CXXMethodDecl *method) { @@ -27,11 +42,25 @@ namespace clang if (StringRef((*parm)->getType().getAsString()) .startswith("std::shared_ptr<")) { + auto parmEndLoc = (*parm)->getEndLoc(); + if ((*parm)->hasDefaultArg()) + { + + auto range = (*parm)->getDefaultArgRange(); + auto typeRange = + (*parm)->getTypeSourceInfo()->getTypeLoc().getSourceRange(); + diag(range.getBegin(), "remove %0 default argument") + << (*parm)->getNameAsString(); + diag(range.getBegin(), "remove default argument", DiagnosticIDs::Note) + << FixItHint::CreateRemoval(SourceRange( + typeRange.getEnd().getLocWithOffset(1), range.getEnd())); + parmEndLoc = typeRange.getEnd().getLocWithOffset(1); + } diag((*parm)->getEndLoc(), "add const reference") << (*parm)->getNameAsString(); diag((*parm)->getBeginLoc(), "remove labs argument", DiagnosticIDs::Note) << FixItHint::CreateInsertion((*parm)->getBeginLoc(), "const ") - << FixItHint::CreateInsertion((*parm)->getEndLoc(), "&"); + << FixItHint::CreateInsertion(parmEndLoc, "&"); } } } @@ -86,10 +115,16 @@ namespace clang ofClass(isSameOrDerivedFrom("MulticlassMachine"))); auto call_methods = cxxMemberCallExpr(callee(methods)); + + auto Initializer = cxxConstructorDecl( + hasAnyConstructorInitializer( + cxxCtorInitializer(isBaseInitializer()).bind("init")), + ofClass(isDerivedFrom("MulticlassMachine"))); Finder->addMatcher(labels.bind("addLabels"), this); Finder->addMatcher(constructor.bind("removeLabels"), this); Finder->addMatcher(methods.bind("addLabels"), this); Finder->addMatcher(call_methods.bind("addLabels"), this); + Finder->addMatcher(Initializer, this); } void RefectormulticlassCheck::check(const MatchFinder::MatchResult &Result) @@ -109,6 +144,7 @@ namespace clang Result.Nodes.getNodeAs("addLabels")) { changeAllSharedPtrToConst(MatchedDecl); + const auto &SM = *(Result.SourceManager); auto loc = MatchedDecl->getTypeSourceInfo()->getTypeLoc().getAs(); // llvm::outs()<size_overridden_methods ()<<"\n"; @@ -118,6 +154,15 @@ namespace clang // llvm::outs() << (*methods)->getParent()->getNameAsString() << "\n"; traverseAllParentFunction(*methods); } + if (auto redecl = MatchedDecl->getPreviousDecl()) + { + if (auto res = cast_or_null(redecl)) + { + changeCorrespondMethod(res, SM); + changeAllSharedPtrToConst(res); + } + } + std::string funcName = getFunctionName(MatchedDecl); if (funcRefactored.find(funcName) == funcRefactored.end()) { @@ -167,12 +212,13 @@ namespace clang } else { - for (auto parm = MatchedDecl->param_begin(); - parm != MatchedDecl->param_end(); ++parm) + for (auto parm : MatchedDecl->parameters()) { - if ((*parm)->getType().getAsString() == "std::shared_ptr") + if (parm->getType().getAsString() == "std::shared_ptr") { - SourceRange loc((*parm)->getSourceRange()); + auto loc = SourceRange(parm->getBeginLoc(), parm->getEndLoc()); + const auto &SM = *(Result.SourceManager); + loc.dump(SM); diag(MatchedDecl->getEndLoc(), "should remove argument") << MatchedDecl->getNameAsString(); diag(MatchedDecl->getEndLoc(), "remove labs argument", @@ -182,7 +228,32 @@ namespace clang } } } - } + if (const auto *MatchedDecl = + Result.Nodes.getNodeAs("init")) + { + if (auto res = dyn_cast(MatchedDecl->getInit())) + { + for (auto child : res->children()) + { + if (auto expr = dyn_cast(child)) + { + for (auto e : expr->arguments()) + { + if (e->getType().getAsString() == "std::shared_ptr") + { + auto loc = e->getSourceRange(); + + diag(loc.getBegin(), "should remove argument"); + diag(loc.getBegin(), "remove labs argument", DiagnosticIDs::Note) + << FixItHint::CreateRemoval(loc); + } + } + } + } + } + } + + } // namespace misc } // namespace misc } // namespace tidy diff --git a/refactor_multiclass/RefectormulticlassCheck.h b/refactor_multiclass/RefectormulticlassCheck.h index 14e5ca0..f5efbf3 100644 --- a/refactor_multiclass/RefectormulticlassCheck.h +++ b/refactor_multiclass/RefectormulticlassCheck.h @@ -37,6 +37,9 @@ namespace clang std::string getFunctionName(const CXXMethodDecl *method); void changeAllSharedPtrToConst(const CXXMethodDecl *method); + + void changeCorrespondMethod(const CXXMethodDecl *method, + const SourceManager &SM); std::unordered_set funcRefactored; };