LCOV - code coverage report
Current view: top level - home/vmiklos/git/libreoffice/dev-tools/clang - rename.cxx (source / functions) Hit Total Coverage
Test: clang.info Lines: 220 227 96.9 %
Date: 2016-01-31 12:01:00 Functions: 24 24 100.0 %

          Line data    Source code
       1             : #include <fstream>
       2             : #include <iostream>
       3             : #include <set>
       4             : #include <sstream>
       5             : 
       6             : #include <clang/AST/ASTConsumer.h>
       7             : #include <clang/AST/ASTContext.h>
       8             : #include <clang/AST/RecursiveASTVisitor.h>
       9             : #include <clang/Rewrite/Core/Rewriter.h>
      10             : #include <clang/Tooling/CommonOptionsParser.h>
      11             : #include <clang/Tooling/Tooling.h>
      12             : 
      13          12 : class RenameRewriter : public clang::Rewriter
      14             : {
      15             :     /// Old names -> new names map.
      16             :     std::map<std::string, std::string> maNameMap;
      17             :     bool mbDump;
      18             : 
      19             : public:
      20          12 :     RenameRewriter(const std::map<std::string, std::string>& rNameMap, bool bDump)
      21          12 :         : maNameMap(rNameMap),
      22          12 :           mbDump(bDump)
      23          12 :     {
      24          12 :     }
      25             : 
      26             :     const std::map<std::string, std::string>& getNameMap()
      27             :     {
      28         132 :         return maNameMap;
      29             :     }
      30             : 
      31             :     bool getDump()
      32             :     {
      33          12 :         return mbDump;
      34             :     }
      35             : };
      36             : 
      37          12 : class RenameVisitor : public clang::RecursiveASTVisitor<RenameVisitor>
      38             : {
      39             :     RenameRewriter& mrRewriter;
      40             :     // A set of handled locations, so in case a location would be handled
      41             :     // multiple times due to macro usage, we only do the rewrite once.
      42             :     // Otherwise an A -> BA replacement would be done twice.
      43             :     std::set<clang::SourceLocation> maHandledLocations;
      44             : 
      45             : public:
      46          12 :     explicit RenameVisitor(RenameRewriter& rRewriter)
      47          12 :         : mrRewriter(rRewriter)
      48          12 :     {
      49          12 :     }
      50             : 
      51             :     // Data member names.
      52             : 
      53             :     /*
      54             :      * class C
      55             :      * {
      56             :      * public:
      57             :      *     int nX; <- Handles this declaration.
      58             :      * };
      59             :      */
      60             :     bool VisitFieldDecl(clang::FieldDecl* pDecl)
      61             :     {
      62             :         // Qualified name includes "C::" as a prefix, normal name does not.
      63           6 :         std::string aName = pDecl->getQualifiedNameAsString();
      64          18 :         const std::map<std::string, std::string>::const_iterator it = mrRewriter.getNameMap().find(aName);
      65          18 :         if (it != mrRewriter.getNameMap().end())
      66          36 :             mrRewriter.ReplaceText(pDecl->getLocation(), pDecl->getNameAsString().length(), it->second);
      67             :         return true;
      68           6 :     }
      69             : 
      70             :     /*
      71             :      * class C
      72             :      * {
      73             :      * public:
      74             :      *     static const int aS[]; <- Handles e.g. this declaration;
      75             :      * };
      76             :      */
      77             :     bool VisitVarDecl(clang::VarDecl* pDecl)
      78             :     {
      79             :         {
      80          11 :             std::string aName = pDecl->getQualifiedNameAsString();
      81          33 :             const std::map<std::string, std::string>::const_iterator it = mrRewriter.getNameMap().find(aName);
      82          33 :             if (it != mrRewriter.getNameMap().end())
      83          12 :                 mrRewriter.ReplaceText(pDecl->getLocation(), pDecl->getNameAsString().length(), it->second);
      84          11 :         }
      85             : 
      86             :         /*
      87             :          * C* pC = 0;
      88             :          * ^ Handles this.
      89             :          */
      90          11 :         clang::QualType pType = pDecl->getType();
      91          11 :         const clang::RecordDecl* pRecordDecl = pType->getPointeeCXXRecordDecl();
      92          11 :         if (pRecordDecl)
      93             :         {
      94           3 :             std::string aName = pRecordDecl->getNameAsString();
      95           9 :             const std::map<std::string, std::string>::const_iterator it = mrRewriter.getNameMap().find(aName);
      96           9 :             if (it != mrRewriter.getNameMap().end())
      97             :             {
      98           6 :                 clang::SourceLocation aLocation = pDecl->getTypeSpecStartLoc();
      99           9 :                 if (maHandledLocations.find(aLocation) == maHandledLocations.end())
     100             :                 {
     101          15 :                     mrRewriter.ReplaceText(aLocation, pRecordDecl->getNameAsString().length(), it->second);
     102           6 :                     maHandledLocations.insert(aLocation);
     103           3 :                 }
     104           3 :             }
     105           3 :         }
     106          11 :         return true;
     107           0 :     }
     108             : 
     109             :     /*
     110             :      * C::C()
     111             :      *     : nX(0) <- Handles this initializer.
     112             :      * {
     113             :      * }
     114             :      */
     115             :     bool VisitCXXConstructorDecl(clang::CXXConstructorDecl* pDecl)
     116             :     {
     117          12 :         for (clang::CXXConstructorDecl::init_const_iterator itInit = pDecl->init_begin(); itInit != pDecl->init_end(); ++itInit)
     118             :         {
     119           2 :             const clang::CXXCtorInitializer* pInitializer = *itInit;
     120             : 
     121             :             // Ignore implicit initializers.
     122           2 :             if (pInitializer->getSourceOrder() == -1)
     123           1 :                 continue;
     124             : 
     125           1 :             if (const clang::FieldDecl* pFieldDecl = pInitializer->getAnyMember())
     126             :             {
     127           1 :                 std::string aName = pFieldDecl->getQualifiedNameAsString();
     128           3 :                 const std::map<std::string, std::string>::const_iterator it = mrRewriter.getNameMap().find(aName);
     129           3 :                 if (it != mrRewriter.getNameMap().end())
     130           6 :                     mrRewriter.ReplaceText(pInitializer->getSourceLocation(), pFieldDecl->getNameAsString().length(), it->second);
     131           1 :             }
     132           1 :         }
     133             : 
     134           4 :         std::string aName = pDecl->getNameAsString();
     135          12 :         const std::map<std::string, std::string>::const_iterator it = mrRewriter.getNameMap().find(aName);
     136          12 :         if (it != mrRewriter.getNameMap().end())
     137             :         {
     138             :             /*
     139             :              * Foo::Foo(...) {}
     140             :              * ^~~ Handles this.
     141             :              */
     142             :             {
     143           2 :                 clang::SourceLocation aLocation = pDecl->getLocStart();
     144           6 :                 if (maHandledLocations.find(aLocation) == maHandledLocations.end())
     145             :                 {
     146          10 :                     mrRewriter.ReplaceText(aLocation, pDecl->getNameAsString().length(), it->second);
     147           4 :                     maHandledLocations.insert(aLocation);
     148           2 :                 }
     149             :             }
     150             : 
     151             :             /*
     152             :              * Foo::Foo(...) {}
     153             :              *      ^~~ Handles this.
     154             :              */
     155             :             {
     156           4 :                 clang::SourceLocation aLocation = pDecl->getLocation();
     157           6 :                 if (maHandledLocations.find(aLocation) == maHandledLocations.end())
     158             :                 {
     159           5 :                     mrRewriter.ReplaceText(aLocation, pDecl->getNameAsString().length(), it->second);
     160           2 :                     maHandledLocations.insert(aLocation);
     161           1 :                 }
     162             :             }
     163           2 :         }
     164             : 
     165             :         return true;
     166           4 :     }
     167             : 
     168             :     /*
     169             :      * C aC;
     170             :      * aC.nX = 1; <- Handles e.g. this...
     171             :      * int y = aC.nX; <- ...and this.
     172             :      */
     173             :     bool VisitMemberExpr(clang::MemberExpr* pExpr)
     174             :     {
     175           6 :         if (clang::ValueDecl* pDecl = pExpr->getMemberDecl())
     176             :         {
     177           6 :             std::string aName = pDecl->getQualifiedNameAsString();
     178          18 :             const std::map<std::string, std::string>::const_iterator it = mrRewriter.getNameMap().find(aName);
     179          18 :             if (it != mrRewriter.getNameMap().end())
     180             :             {
     181           8 :                 clang::SourceLocation aLocation = pExpr->getMemberLoc();
     182          12 :                 if (pExpr->getMemberLoc().isMacroID())
     183             :                     /*
     184             :                      * int foo(int x);
     185             :                      * #define FOO(a) foo(a)
     186             :                      * FOO(aC.nX); <- Handles this.
     187             :                      */
     188           3 :                     aLocation = mrRewriter.getSourceMgr().getSpellingLoc(aLocation);
     189          12 :                 if (maHandledLocations.find(aLocation) == maHandledLocations.end())
     190             :                 {
     191          20 :                     mrRewriter.ReplaceText(aLocation, pDecl->getNameAsString().length(), it->second);
     192           8 :                     maHandledLocations.insert(aLocation);
     193           4 :                 }
     194           4 :             }
     195           6 :         }
     196           6 :         return true;
     197           0 :     }
     198             : 
     199             :     /*
     200             :      * class C
     201             :      * {
     202             :      * public:
     203             :      *     static const int aS[];
     204             :      *     static const int* getS() { return aS; } <- Handles this.
     205             :      * };
     206             :      */
     207             :     bool VisitDeclRefExpr(clang::DeclRefExpr* pExpr)
     208             :     {
     209           9 :         if (clang::ValueDecl* pDecl = pExpr->getDecl())
     210             :         {
     211           9 :             std::string aName = pDecl->getQualifiedNameAsString();
     212          27 :             const std::map<std::string, std::string>::const_iterator it = mrRewriter.getNameMap().find(aName);
     213          27 :             if (it != mrRewriter.getNameMap().end())
     214             :             {
     215           4 :                 clang::SourceLocation aLocation = pExpr->getLocation();
     216           4 :                 if (aLocation.isMacroID())
     217             :                     /*
     218             :                      * int foo(int x);
     219             :                      * #define FOO(a) foo(a)
     220             :                      * FOO(aC.nX); <- Handles this.
     221             :                      */
     222           3 :                     aLocation = mrRewriter.getSourceMgr().getSpellingLoc(aLocation);
     223           6 :                 if (maHandledLocations.find(aLocation) == maHandledLocations.end())
     224             :                 {
     225          10 :                     mrRewriter.ReplaceText(aLocation, pDecl->getNameAsString().length(), it->second);
     226           4 :                     maHandledLocations.insert(aLocation);
     227           2 :                 }
     228           2 :             }
     229           9 :         }
     230           9 :         return true;
     231           0 :     }
     232             : 
     233             :     // Member function names.
     234             : 
     235             :     /*
     236             :      * class C
     237             :      * {
     238             :      * public:
     239             :      *     foo(); <- Handles this.
     240             :      * };
     241             :      *
     242             :      * C::foo() <- And this.
     243             :      * {
     244             :      * }
     245             :      *
     246             :      * ...
     247             :      *
     248             :      * aC.foo(); <- And this.
     249             :      */
     250             :     bool VisitCXXMethodDecl(const clang::CXXMethodDecl* pDecl)
     251             :     {
     252           8 :         std::string aName = pDecl->getQualifiedNameAsString();
     253          24 :         const std::map<std::string, std::string>::const_iterator it = mrRewriter.getNameMap().find(aName);
     254          24 :         if (it != mrRewriter.getNameMap().end())
     255             :         {
     256           4 :             clang::SourceLocation aLocation = pDecl->getLocation();
     257           6 :             if (maHandledLocations.find(aLocation) == maHandledLocations.end())
     258             :             {
     259          10 :                 mrRewriter.ReplaceText(aLocation, pDecl->getNameAsString().length(), it->second);
     260           4 :                 maHandledLocations.insert(aLocation);
     261           2 :             }
     262           2 :         }
     263             :         return true;
     264           8 :     }
     265             : 
     266             :     // Class names.
     267             : 
     268             :     /*
     269             :      * class C <- Handles this.
     270             :      * {
     271             :      * };
     272             :      */
     273             :     bool VisitCXXRecordDecl(const clang::CXXRecordDecl* pDecl)
     274             :     {
     275          13 :         std::string aName = pDecl->getQualifiedNameAsString();
     276          39 :         const std::map<std::string, std::string>::const_iterator it = mrRewriter.getNameMap().find(aName);
     277          39 :         if (it != mrRewriter.getNameMap().end())
     278             :         {
     279           8 :             clang::SourceLocation aLocation = pDecl->getLocation();
     280          12 :             if (maHandledLocations.find(aLocation) == maHandledLocations.end())
     281             :             {
     282          20 :                 mrRewriter.ReplaceText(aLocation, pDecl->getNameAsString().length(), it->second);
     283           8 :                 maHandledLocations.insert(aLocation);
     284           4 :             }
     285           4 :         }
     286             :         return true;
     287          13 :     }
     288             : 
     289             :     /*
     290             :      * ... new C(...); <- Handles this.
     291             :      */
     292             :     bool VisitCXXConstructExpr(const clang::CXXConstructExpr* pExpr)
     293             :     {
     294           3 :         if (const clang::CXXConstructorDecl* pDecl = pExpr->getConstructor())
     295             :         {
     296           3 :             std::string aName = pDecl->getNameAsString();
     297           9 :             const std::map<std::string, std::string>::const_iterator it = mrRewriter.getNameMap().find(aName);
     298           9 :             if (it != mrRewriter.getNameMap().end())
     299             :             {
     300           2 :                 clang::SourceLocation aLocation = pExpr->getLocation();
     301           3 :                 if (maHandledLocations.find(aLocation) == maHandledLocations.end())
     302             :                 {
     303           5 :                     mrRewriter.ReplaceText(aLocation, pDecl->getNameAsString().length(), it->second);
     304           2 :                     maHandledLocations.insert(aLocation);
     305           1 :                 }
     306           1 :             }
     307           3 :         }
     308           3 :         return true;
     309           0 :     }
     310             : 
     311             :     /*
     312             :      * ... static_cast<const C*>(...) ...;
     313             :      *                       ^ Handles this...
     314             :      *
     315             :      * ... static_cast<const C&>(...) ...;
     316             :      *                       ^ ... and this.
     317             :      */
     318             :     bool VisitCXXStaticCastExpr(clang::CXXStaticCastExpr* pExpr)
     319             :     {
     320           2 :         clang::QualType pType = pExpr->getType();
     321           2 :         const clang::RecordDecl* pDecl = pType->getPointeeCXXRecordDecl();
     322           2 :         if (!pDecl)
     323           1 :             pDecl = pType->getAsCXXRecordDecl();
     324           2 :         if (pDecl)
     325             :         {
     326           2 :             std::string aName = pDecl->getNameAsString();
     327           6 :             const std::map<std::string, std::string>::const_iterator it = mrRewriter.getNameMap().find(aName);
     328           6 :             if (it != mrRewriter.getNameMap().end())
     329             :             {
     330           8 :                 clang::SourceLocation aLocation = pExpr->getTypeInfoAsWritten()->getTypeLoc().getBeginLoc();
     331           6 :                 if (maHandledLocations.find(aLocation) == maHandledLocations.end())
     332             :                 {
     333          10 :                     mrRewriter.ReplaceText(aLocation, pDecl->getNameAsString().length(), it->second);
     334           4 :                     maHandledLocations.insert(aLocation);
     335           2 :                 }
     336           2 :             }
     337           2 :         }
     338           2 :         return true;
     339           0 :     }
     340             : };
     341             : 
     342          24 : class RenameASTConsumer : public clang::ASTConsumer
     343             : {
     344             :     RenameRewriter& mrRewriter;
     345             : 
     346             :     std::string getNewName(const clang::FileEntry& rEntry)
     347             :     {
     348          11 :         std::stringstream ss;
     349          22 :         ss << rEntry.getName();
     350          11 :         ss << ".new-rename";
     351          11 :         return ss.str();
     352          11 :     }
     353             : 
     354             : public:
     355          12 :     RenameASTConsumer(RenameRewriter& rRewriter)
     356          12 :         : mrRewriter(rRewriter)
     357          24 :     {
     358          12 :     }
     359             : 
     360             :     virtual void HandleTranslationUnit(clang::ASTContext& rContext)
     361             :     {
     362          12 :         if (rContext.getDiagnostics().hasErrorOccurred())
     363           0 :             return;
     364             : 
     365          12 :         RenameVisitor aVisitor(mrRewriter);
     366          36 :         mrRewriter.setSourceMgr(rContext.getSourceManager(), rContext.getLangOpts());
     367          24 :         aVisitor.TraverseDecl(rContext.getTranslationUnitDecl());
     368             : 
     369         120 :         for (clang::Rewriter::buffer_iterator it = mrRewriter.buffer_begin(); it != mrRewriter.buffer_end(); ++it)
     370             :         {
     371          24 :             if (mrRewriter.getDump())
     372           4 :                 it->second.write(llvm::errs());
     373             :             else
     374             :             {
     375          44 :                 const clang::FileEntry* pEntry = rContext.getSourceManager().getFileEntryForID(it->first);
     376          11 :                 if (!pEntry)
     377           0 :                     continue;
     378          11 :                 std::string aNewName = getNewName(*pEntry);
     379             : #if (__clang_major__ == 3 && __clang_minor__ >= 6) || __clang_major__ > 3
     380          11 :                 std::error_code aError;
     381          44 :                 std::unique_ptr<llvm::raw_fd_ostream> pStream(new llvm::raw_fd_ostream(aNewName, aError, llvm::sys::fs::F_None));
     382          11 :                 if (!aError)
     383             : #else
     384             :                 std::string aError;
     385             :                 std::unique_ptr<llvm::raw_fd_ostream> pStream(new llvm::raw_fd_ostream(aNewName.c_str(), aError, llvm::sys::fs::F_None));
     386             :                 if (aError.empty())
     387             : #endif
     388          44 :                     it->second.write(*pStream);
     389          11 :             }
     390          12 :         }
     391          24 :     }
     392             : };
     393             : 
     394             : class RenameFrontendAction
     395             : {
     396             :     RenameRewriter& mrRewriter;
     397             : 
     398             : public:
     399             :     RenameFrontendAction(RenameRewriter& rRewriter)
     400          12 :         : mrRewriter(rRewriter)
     401             :     {
     402          12 :     }
     403             : 
     404             : #if (__clang_major__ == 3 && __clang_minor__ >= 6) || __clang_major__ > 3
     405             :     std::unique_ptr<clang::ASTConsumer> newASTConsumer()
     406             :     {
     407          12 :         return llvm::make_unique<RenameASTConsumer>(mrRewriter);
     408             :     }
     409             : #else
     410             :     clang::ASTConsumer* newASTConsumer()
     411             :     {
     412             :         return new RenameASTConsumer(mrRewriter);
     413             :     }
     414             : #endif
     415             : };
     416             : 
     417             : /// Parses rCsv and puts the first two column of it into rNameMap.
     418             : static bool parseCsv(const std::string& rCsv, std::map<std::string, std::string>& rNameMap)
     419             : {
     420           6 :     std::ifstream aStream(rCsv);
     421          12 :     if (!aStream.is_open())
     422             :     {
     423           3 :         std::cerr << "parseCsv: failed to open " << rCsv << std::endl;
     424           1 :         return false;
     425             :     }
     426             : 
     427           5 :     std::string aLine;
     428          36 :     while (std::getline(aStream, aLine))
     429             :     {
     430          12 :         std::stringstream ss(aLine);
     431           6 :         std::string aOldName;
     432           6 :         std::getline(ss, aOldName, ',');
     433           6 :         if (aOldName.empty())
     434             :         {
     435           4 :             std::cerr << "parseCsv: first column is empty for line '" << aLine << "'" << std::endl;
     436           1 :             return false;
     437             :         }
     438           5 :         std::string aNewName;
     439           5 :         std::getline(ss, aNewName, ',');
     440           5 :         if (aNewName.empty())
     441             :         {
     442           4 :             std::cerr << "parseCsv: second column is empty for line '" << aLine << "'" << std::endl;
     443           1 :             return false;
     444             :         }
     445           8 :         rNameMap[aOldName] = aNewName;
     446          15 :     }
     447             : 
     448           3 :     aStream.close();
     449           3 :     return true;
     450          11 : }
     451             : 
     452             : int main(int argc, const char** argv)
     453             : {
     454          16 :     llvm::cl::OptionCategory aCategory("rename options");
     455          16 :     llvm::cl::opt<std::string> aOldName("old-name",
     456          16 :                                         llvm::cl::desc("Old, qualified name (Class::member)."),
     457          16 :                                         llvm::cl::cat(aCategory));
     458          16 :     llvm::cl::opt<std::string> aNewName("new-name",
     459          16 :                                         llvm::cl::desc("New, non-qualified name (without Class::)."),
     460          16 :                                         llvm::cl::cat(aCategory));
     461          16 :     llvm::cl::opt<std::string> aCsv("csv",
     462          16 :                                     llvm::cl::desc("Path to a CSV file, containing multiple renames -- seprator must be a comma (,)."),
     463          16 :                                     llvm::cl::cat(aCategory));
     464          16 :     llvm::cl::opt<bool> bDump("dump",
     465          16 :                               llvm::cl::desc("Dump output on the console instead of writing to .new files."),
     466          16 :                               llvm::cl::cat(aCategory));
     467          16 :     clang::tooling::CommonOptionsParser aParser(argc, argv, aCategory);
     468             : 
     469          16 :     std::map<std::string, std::string> aNameMap;
     470          25 :     if (!aOldName.empty() && !aNewName.empty())
     471          27 :         aNameMap[aOldName] = aNewName;
     472           7 :     else if (!aCsv.empty())
     473             :     {
     474          12 :         if (!parseCsv(aCsv, aNameMap))
     475           3 :             return 1;
     476           3 :     }
     477             :     else
     478             :     {
     479           2 :         std::cerr << "either -old-name + -new-name or -csv is required." << std::endl;
     480           1 :         return 1;
     481             :     }
     482             : 
     483          72 :     clang::tooling::ClangTool aTool(aParser.getCompilations(), aParser.getSourcePathList());
     484             : 
     485          24 :     RenameRewriter aRewriter(aNameMap, bDump);
     486          12 :     RenameFrontendAction aAction(aRewriter);
     487          12 :     std::unique_ptr<clang::tooling::FrontendActionFactory> pFactory = clang::tooling::newFrontendActionFactory(&aAction);
     488          24 :     return aTool.run(pFactory.get());
     489          28 : }
     490             : 
     491             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11