std::string location(clang::SourceLocation const& l, clang::SourceManager const& sm) { if(l.isValid()) { if(l.isFileID()) { // if (sm.isLoadedFileID (sm.getFileID(l))) return "PRELOADED MODULE"; if(sm.isLoadedSourceLocation(l)) { return "PRELOADED MODULE"; } return l.printToString(sm); } if(l.isMacroID()) { // FIXME: what do we do here? somehow clang fails /* std::cout << "SLoc isMacroID\n"; auto sl = sm.getSpellingLoc(l); if (sm.isLoadedSourceLocation(sl) ) { return "PRELOADED MODULE"; } if(sl.isValid()) { return sl.printToString(sm); } PresumedLoc pl = sm.getPresumedLoc(l); if (pl.isValid()){ return string(pl.getFilename()); } */ } return string("UNKNOWN FILE"); } return string("INVALID LOC"); }
void NamedDeclMatcher::renameLocation(clang::SourceLocation L, std::string& N) { if (L.isValid()) { if (L.isMacroID()) { // TODO: emit error using diagnostics clang::SourceManager &SM = ci->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 clang::SourceManager &SM = ci->getSourceManager(); auto SL = SM.getSpellingLoc(L); clang::FullSourceLoc FSL(SL, SM); const clang::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 (!canChangeLocation(L)) { return; } clang::Preprocessor &P = ci->getPreprocessor(); auto LE = P.getLocForEndOfToken(L); if (LE.isValid()) { // getLocWithOffset returns the location *past* the token, hence -1 auto E = LE.getLocWithOffset(-1); // TODO: Determine if it's a writable file // TODO: Determine if the location has already been touched or // needs skipping (such as in refactoring API user's code, then // the API headers need no changing since later the new API will be // in place) Replacer::instance().replace(clang::SourceRange(L, E), N, ci->getSourceManager()); } } }
void EditTracker::Add(const clang::SourceManager& source_manager, clang::SourceLocation location, llvm::StringRef original_text, llvm::StringRef new_text) { llvm::StringRef filename; for (int i = 0; i < 10; i++) { filename = source_manager.getFilename(location); if (!filename.empty() || !location.isMacroID()) break; // Otherwise, no filename and the SourceLocation is a macro ID. Look one // level up the stack... location = source_manager.getImmediateMacroCallerLoc(location); } assert(!filename.empty() && "Can't track edit with no filename!"); auto result = tracked_edits_.try_emplace(original_text); if (result.second) { result.first->getValue().new_text = new_text; } result.first->getValue().filenames.try_emplace(filename); }