unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const { assert(!IsDefinitionLengthCached); IsDefinitionLengthCached = true; if (ReplacementTokens.empty()) return (DefinitionLength = 0); const Token &firstToken = ReplacementTokens.front(); const Token &lastToken = ReplacementTokens.back(); SourceLocation macroStart = firstToken.getLocation(); SourceLocation macroEnd = lastToken.getLocation(); assert(macroStart.isValid() && macroEnd.isValid()); assert((macroStart.isFileID() || firstToken.is(tok::comment)) && "Macro defined in macro?"); assert((macroEnd.isFileID() || lastToken.is(tok::comment)) && "Macro defined in macro?"); std::pair<FileID, unsigned> startInfo = SM.getDecomposedExpansionLoc(macroStart); std::pair<FileID, unsigned> endInfo = SM.getDecomposedExpansionLoc(macroEnd); assert(startInfo.first == endInfo.first && "Macro definition spanning multiple FileIDs ?"); assert(startInfo.second <= endInfo.second); DefinitionLength = endInfo.second - startInfo.second; DefinitionLength += lastToken.getLength(); return DefinitionLength; }
static std::string buildFixItInsertionLine(unsigned LineNo, const SourceColumnMap &map, ArrayRef<FixItHint> Hints, const SourceManager &SM, const DiagnosticOptions *DiagOpts) { std::string FixItInsertionLine; if (Hints.empty() || !DiagOpts->ShowFixits) return FixItInsertionLine; unsigned PrevHintEndCol = 0; for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); I != E; ++I) { if (!I->CodeToInsert.empty()) { // We have an insertion hint. Determine whether the inserted // code contains no newlines and is on the same line as the caret. std::pair<FileID, unsigned> HintLocInfo = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin()); if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) && StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) { // Insert the new code into the line just below the code // that the user wrote. // Note: When modifying this function, be very careful about what is a // "column" (printed width, platform-dependent) and what is a // "byte offset" (SourceManager "column"). unsigned HintByteOffset = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1; // The hint must start inside the source or right at the end assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1); unsigned HintCol = map.byteToContainingColumn(HintByteOffset); // If we inserted a long previous hint, push this one forwards, and add // an extra space to show that this is not part of the previous // completion. This is sort of the best we can do when two hints appear // to overlap. // // Note that if this hint is located immediately after the previous // hint, no space will be added, since the location is more important. if (HintCol < PrevHintEndCol) HintCol = PrevHintEndCol + 1; // FIXME: This function handles multibyte characters in the source, but // not in the fixits. This assertion is intended to catch unintended // use of multibyte characters in fixits. If we decide to do this, we'll // have to track separate byte widths for the source and fixit lines. assert((size_t)llvm::sys::locale::columnWidth(I->CodeToInsert) == I->CodeToInsert.size()); // This relies on one byte per column in our fixit hints. // This should NOT use HintByteOffset, because the source might have // Unicode characters in earlier columns. unsigned LastColumnModified = HintCol + I->CodeToInsert.size(); if (LastColumnModified > FixItInsertionLine.size()) FixItInsertionLine.resize(LastColumnModified, ' '); std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(), FixItInsertionLine.begin() + HintCol); PrevHintEndCol = LastColumnModified; } else { FixItInsertionLine.clear(); break; } } } expandTabs(FixItInsertionLine, DiagOpts->TabStop); return FixItInsertionLine; }
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 }