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: */
|