virtual bool VisitStmt(Stmt *st) { if (ReturnStmt *ret = dyn_cast<ReturnStmt>(st)) { rewriter.ReplaceText(ret->getRetValue()->getLocStart(), 6, "val"); errs() << "** Rewrote ReturnStmt\n"; } if (CallExpr *call = dyn_cast<CallExpr>(st)) { rewriter.ReplaceText(call->getLocStart(), 7, "add5"); errs() << "** Rewrote function call\n"; } return true; }
virtual bool VisitFunctionDecl(FunctionDecl *func) { numFunctions++; string funcName = func->getNameInfo().getName().getAsString(); if (funcName == "do_math") { rewriter.ReplaceText(func->getLocation(), funcName.length(), "add5"); errs() << "** Rewrote function def: " << funcName << "\n"; } return true; }
void SynthesizeRemovalConsumer::renameLocation(SourceLocation L, std::string& N) { if (L.isMacroID()) { // TODO: emit error using diagnostics SourceManager &SM = astContext->getSourceManager(); if (SM.isMacroArgExpansion(L) || SM.isInSystemMacro(L)) { // see if it's the macro expansion we can handle // e.g. // #define call(x) x // call(y()); // if we want to rename y() L = SM.getSpellingLoc(L); // this falls through to the rename routine below } else { // if the spelling location is from an actual file that we can // touch, then do the replacement, but show a warning SourceManager &SM = astContext->getSourceManager(); auto SL = SM.getSpellingLoc(L); FullSourceLoc FSL(SL, SM); const FileEntry *FE = SM.getFileEntryForID(FSL.getFileID()); if (FE) { llvm::errs() << "Warning: Rename attempted as a result of macro " << "expansion may break things, at: " << loc(L) << "\n"; L = SL; // this falls through to the rename routine below } else { // cannot handle this case llvm::errs() << "Error: Token is resulted from macro expansion" " and is therefore not renamed, at: " << loc(L) << "\n"; return; } } } if (shouldIgnore(L)) { return; } auto LE = preprocessor->getLocForEndOfToken(L); if (LE.isValid()) { // getLocWithOffset returns the location *past* the token, hence -1 auto E = LE.getLocWithOffset(-1); rewriter.ReplaceText(SourceRange(L, E), N); } }
bool Replacement::apply(Rewriter &Rewrite) const { SourceManager &SM = Rewrite.getSourceMgr(); const FileEntry *Entry = SM.getFileManager().getFile(FilePath); if (Entry == NULL) return false; FileID ID; // FIXME: Use SM.translateFile directly. SourceLocation Location = SM.translateFileLineCol(Entry, 1, 1); ID = Location.isValid() ? SM.getFileID(Location) : SM.createFileID(Entry, SourceLocation(), SrcMgr::C_User); // FIXME: We cannot check whether Offset + Length is in the file, as // the remapping API is not public in the RewriteBuffer. const SourceLocation Start = SM.getLocForStartOfFile(ID). getLocWithOffset(Offset); // ReplaceText returns false on success. // ReplaceText only fails if the source location is not a file location, in // which case we already returned false earlier. bool RewriteSucceeded = !Rewrite.ReplaceText(Start, Length, ReplacementText); assert(RewriteSucceeded); return RewriteSucceeded; }
void C2Builder::rewriterTest(SourceManager& SM, LangOptions& LangOpts) { #if 0 // FOR TESTING rename global test.aa -> bb const std::string modName = "test"; const std::string oldName = "aa"; const std::string newName = "bb"; // Step 1a: find Module const Module* M = 0; const Module* mod = findModule(modName); assert(M && "unknown module"); assert(!M->isExternal() && "cannot replace symbol in external module"); // Step 1b: find Decl Decl* D = M->findSymbol(oldName); assert(D && "unknown decl"); // Step 2a: replace Decl itself Rewriter rewriter; rewriter.setSourceMgr(SM, LangOpts); rewriter.ReplaceText(D->getLocation(), oldName.size(), newName); // Step 2b: replace all references // TODO only in mainComponent const ModuleList& mods = mainComponent->getModules(); for (unsigned m=0; m<mods.size(); m++) { const AstList& files = mods[m]->getFiles(); for (unsigned a=0; a<files.size(); a++) { AST* ast = files[a]; RefFinder finder(*ast, D); unsigned count = finder.find(); if (count) printf("replaced %d references in %s\n", count, files[i]->getFileName().c_str()); for (unsigned i=0; i<count; i++) { std::string temp = finder.locs[i].printToString(SM); printf("loc %d -> %s\n", finder.locs[i].getRawEncoding(), temp.c_str()); PresumedLoc loc = SM.getPresumedLoc(finder.locs[i]); assert(!loc.isInvalid() && "Invalid location"); printf(" -> %s:%d:%d\n", loc.getFilename(), loc.getLine(), loc.getColumn()); std::pair<FileID, unsigned> Off = SM.getDecomposedExpansionLoc(finder.locs[i]); printf("-> offset %d\n", Off.second); rewriter.ReplaceText(finder.locs[i], oldName.size(), newName); } } } // Step 3: reparse and check // TODO // print output for (unsigned m=0; m<mods.size(); m++) { const AstList& files = mods[m]->getFiles(); for (unsigned a=0; a<files.size(); a++) { AST* ast = files[a]; const RewriteBuffer *RewriteBuf = rewriter.getRewriteBufferFor(ast->fileID); if (RewriteBuf) { printf("====== %s ======\n", ast->getFileName().c_str()); llvm::outs() << std::string(RewriteBuf->begin(), RewriteBuf->end()); } } } // also works! //bool err = rewriter.overwriteChangedFiles(); //printf("errors = %d\n", err); #endif }