std::string TextDiagnostic::buildFixItInsertionLine( unsigned LineNo, const SourceColumnMap &map, ArrayRef<FixItHint> Hints) { std::string FixItInsertionLine; if (Hints.empty() || !DiagOpts.ShowFixits) return FixItInsertionLine; 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 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)) { // Insert the new code into the line just below the code // that the user wrote. unsigned HintColNo = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1; // hint must start inside the source or right at the end assert(HintColNo<static_cast<unsigned>(map.bytes())+1); HintColNo = map.byteToColumn(HintColNo); // FIXME: if the fixit includes tabs or other characters that do not // take up a single column per byte when displayed then // I->CodeToInsert.size() is not a column number and we're mixing // units (columns + bytes). We should get printable versions // of each fixit before using them. unsigned LastColumnModified = HintColNo + I->CodeToInsert.size(); if (LastColumnModified > static_cast<unsigned>(map.bytes())) { unsigned LastExistingColumn = map.byteToColumn(map.bytes()); unsigned AddedColumns = LastColumnModified-LastExistingColumn; LastColumnModified = LastExistingColumn + AddedColumns; } else { LastColumnModified = map.byteToColumn(LastColumnModified); } if (LastColumnModified > FixItInsertionLine.size()) FixItInsertionLine.resize(LastColumnModified, ' '); assert(HintColNo+I->CodeToInsert.size() <= FixItInsertionLine.size()); std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(), FixItInsertionLine.begin() + HintColNo); } else { FixItInsertionLine.clear(); break; } } } expandTabs(FixItInsertionLine, DiagOpts.TabStop); return FixItInsertionLine; }
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; }