/// getRangeSize - Return the size in bytes of the specified range if they /// are in the same file. If not, this returns -1. int Rewriter::getRangeSize(const CharSourceRange &Range, RewriteOptions opts) const { if (!isRewritable(Range.getBegin()) || !isRewritable(Range.getEnd())) return -1; FileID StartFileID, EndFileID; unsigned StartOff, EndOff; StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); if (StartFileID != EndFileID) return -1; // If edits have been made to this buffer, the delta between the range may // have changed. std::map<FileID, RewriteBuffer>::const_iterator I = RewriteBuffers.find(StartFileID); if (I != RewriteBuffers.end()) { const RewriteBuffer &RB = I->second; EndOff = RB.getMappedOffset(EndOff, opts.IncludeInsertsAtEndOfRange); StartOff = RB.getMappedOffset(StartOff, !opts.IncludeInsertsAtBeginOfRange); } // Adjust the end offset to the end of the last token, instead of being the // start of the last token if this is a token range. if (Range.isTokenRange()) EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); return EndOff-StartOff; }
static void EmitRange(raw_ostream& o, const SourceManager &SM, const LangOptions &LangOpts, CharSourceRange R, const FIDMap &FM, unsigned indent) { Indent(o, indent) << "<array>\n"; EmitLocation(o, SM, LangOpts, R.getBegin(), FM, indent+1); EmitLocation(o, SM, LangOpts, R.getEnd(), FM, indent+1, R.isTokenRange()); Indent(o, indent) << "</array>\n"; }
void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range, RecordDataImpl &Record, const SourceManager &SM) { AddLocToRecord(Range.getBegin(), Record, &SM); unsigned TokSize = 0; if (Range.isTokenRange()) TokSize = Lexer::MeasureTokenLength(Range.getEnd(), SM, *LangOpts); AddLocToRecord(Range.getEnd(), Record, &SM, TokSize); }
// FIXME: This should go into the Lexer, but we need to figure out how // to handle ranges for refactoring in general first - there is no obvious // good way how to integrate this into the Lexer yet. static int getRangeSize(SourceManager &Sources, const CharSourceRange &Range) { SourceLocation SpellingBegin = Sources.getSpellingLoc(Range.getBegin()); SourceLocation SpellingEnd = Sources.getSpellingLoc(Range.getEnd()); std::pair<FileID, unsigned> Start = Sources.getDecomposedLoc(SpellingBegin); std::pair<FileID, unsigned> End = Sources.getDecomposedLoc(SpellingEnd); if (Start.first != End.first) return -1; if (Range.isTokenRange()) End.second += Lexer::MeasureTokenLength(SpellingEnd, Sources, LangOptions()); return End.second - Start.second; }
bool Commit::insertWrap(StringRef before, CharSourceRange range, StringRef after) { bool commitableBefore = insert(range.getBegin(), before, /*afterToken=*/false, /*beforePreviousInsertions=*/true); bool commitableAfter; if (range.isTokenRange()) commitableAfter = insertAfterToken(range.getEnd(), after); else commitableAfter = insert(range.getEnd(), after); return commitableBefore && commitableAfter; }
static void printSourceRange(CharSourceRange range, ASTContext &Ctx, raw_ostream &OS) { SourceManager &SM = Ctx.getSourceManager(); const LangOptions &langOpts = Ctx.getLangOpts(); PresumedLoc PL = SM.getPresumedLoc(range.getBegin()); OS << llvm::sys::path::filename(PL.getFilename()); OS << " [" << PL.getLine() << ":" << PL.getColumn(); OS << " - "; SourceLocation end = range.getEnd(); PL = SM.getPresumedLoc(end); unsigned endCol = PL.getColumn() - 1; if (!range.isTokenRange()) endCol += Lexer::MeasureTokenLength(end, SM, langOpts); OS << PL.getLine() << ":" << endCol << "]"; }
/// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo. static void highlightRange(const CharSourceRange &R, unsigned LineNo, FileID FID, const SourceColumnMap &map, std::string &CaretLine, const SourceManager &SM, const LangOptions &LangOpts) { if (!R.isValid()) return; SourceLocation Begin = R.getBegin(); SourceLocation End = R.getEnd(); unsigned StartLineNo = SM.getExpansionLineNumber(Begin); if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) return; // No intersection. unsigned EndLineNo = SM.getExpansionLineNumber(End); if (EndLineNo < LineNo || SM.getFileID(End) != FID) return; // No intersection. // Compute the column number of the start. unsigned StartColNo = 0; if (StartLineNo == LineNo) { StartColNo = SM.getExpansionColumnNumber(Begin); if (StartColNo) --StartColNo; // Zero base the col #. } // Compute the column number of the end. unsigned EndColNo = map.getSourceLine().size(); if (EndLineNo == LineNo) { EndColNo = SM.getExpansionColumnNumber(End); if (EndColNo) { --EndColNo; // Zero base the col #. // Add in the length of the token, so that we cover multi-char tokens if // this is a token range. if (R.isTokenRange()) EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts); } else { EndColNo = CaretLine.size(); } } assert(StartColNo <= EndColNo && "Invalid range!"); // Check that a token range does not highlight only whitespace. if (R.isTokenRange()) { // Pick the first non-whitespace column. while (StartColNo < map.getSourceLine().size() && (map.getSourceLine()[StartColNo] == ' ' || map.getSourceLine()[StartColNo] == '\t')) StartColNo = map.startOfNextColumn(StartColNo); // Pick the last non-whitespace column. if (EndColNo > map.getSourceLine().size()) EndColNo = map.getSourceLine().size(); while (EndColNo-1 && (map.getSourceLine()[EndColNo-1] == ' ' || map.getSourceLine()[EndColNo-1] == '\t')) EndColNo = map.startOfPreviousColumn(EndColNo); // If the start/end passed each other, then we are trying to highlight a // range that just exists in whitespace, which must be some sort of other // bug. assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); } assert(StartColNo <= map.getSourceLine().size() && "Invalid range!"); assert(EndColNo <= map.getSourceLine().size() && "Invalid range!"); // Fill the range with ~'s. StartColNo = map.byteToContainingColumn(StartColNo); EndColNo = map.byteToContainingColumn(EndColNo); assert(StartColNo <= EndColNo && "Invalid range!"); if (CaretLine.size() < EndColNo) CaretLine.resize(EndColNo,' '); std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~'); }
/// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo. void TextDiagnostic::highlightRange(const CharSourceRange &R, unsigned LineNo, FileID FID, const SourceColumnMap &map, std::string &CaretLine) { if (!R.isValid()) return; SourceLocation Begin = SM.getExpansionLoc(R.getBegin()); SourceLocation End = SM.getExpansionLoc(R.getEnd()); // If the End location and the start location are the same and are a macro // location, then the range was something that came from a macro expansion // or _Pragma. If this is an object-like macro, the best we can do is to // highlight the range. If this is a function-like macro, we'd also like to // highlight the arguments. if (Begin == End && R.getEnd().isMacroID()) End = SM.getExpansionRange(R.getEnd()).second; unsigned StartLineNo = SM.getExpansionLineNumber(Begin); if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) return; // No intersection. unsigned EndLineNo = SM.getExpansionLineNumber(End); if (EndLineNo < LineNo || SM.getFileID(End) != FID) return; // No intersection. // Compute the column number of the start. unsigned StartColNo = 0; if (StartLineNo == LineNo) { StartColNo = SM.getExpansionColumnNumber(Begin); if (StartColNo) --StartColNo; // Zero base the col #. } // Compute the column number of the end. unsigned EndColNo = map.getSourceLine().size(); if (EndLineNo == LineNo) { EndColNo = SM.getExpansionColumnNumber(End); if (EndColNo) { --EndColNo; // Zero base the col #. // Add in the length of the token, so that we cover multi-char tokens if // this is a token range. if (R.isTokenRange()) EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts); } else { EndColNo = CaretLine.size(); } } assert(StartColNo <= EndColNo && "Invalid range!"); // Check that a token range does not highlight only whitespace. if (R.isTokenRange()) { // Pick the first non-whitespace column. while (StartColNo < map.getSourceLine().size() && (map.getSourceLine()[StartColNo] == ' ' || map.getSourceLine()[StartColNo] == '\t')) ++StartColNo; // Pick the last non-whitespace column. if (EndColNo > map.getSourceLine().size()) EndColNo = map.getSourceLine().size(); while (EndColNo-1 && (map.getSourceLine()[EndColNo-1] == ' ' || map.getSourceLine()[EndColNo-1] == '\t')) --EndColNo; // If the start/end passed each other, then we are trying to highlight a // range that just exists in whitespace, which must be some sort of other // bug. assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); } assert(StartColNo <= map.getSourceLine().size() && "Invalid range!"); assert(EndColNo <= map.getSourceLine().size() && "Invalid range!"); // Fill the range with ~'s. StartColNo = map.byteToColumn(StartColNo); EndColNo = map.byteToColumn(EndColNo); assert(StartColNo <= EndColNo && "Invalid range!"); if (CaretLine.size() < EndColNo) CaretLine.resize(EndColNo,' '); std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~'); }
/// Print out the file/line/column information and include trace. /// /// This method handlen the emission of the diagnostic location information. /// This includes extracting as much location information as is present for /// the diagnostic and printing it, as well as any include stack or source /// ranges necessary. void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, ArrayRef<CharSourceRange> Ranges) { if (PLoc.isInvalid()) { // At least print the file name if available: FileID FID = Loc.getFileID(); if (FID.isValid()) { const FileEntry *FE = Loc.getFileEntry(); if (FE && FE->isValid()) { emitFilename(FE->getName(), Loc.getManager()); if (FE->isInPCH()) OS << " (in PCH)"; OS << ": "; } } return; } unsigned LineNo = PLoc.getLine(); if (!DiagOpts->ShowLocation) return; if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); emitFilename(PLoc.getFilename(), Loc.getManager()); switch (DiagOpts->getFormat()) { case DiagnosticOptions::Clang: OS << ':' << LineNo; break; case DiagnosticOptions::MSVC: OS << '(' << LineNo; break; case DiagnosticOptions::Vi: OS << " +" << LineNo; break; } if (DiagOpts->ShowColumn) // Compute the column number. if (unsigned ColNo = PLoc.getColumn()) { if (DiagOpts->getFormat() == DiagnosticOptions::MSVC) { OS << ','; // Visual Studio 2010 or earlier expects column number to be off by one if (LangOpts.MSCompatibilityVersion && !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2012)) ColNo--; } else OS << ':'; OS << ColNo; } switch (DiagOpts->getFormat()) { case DiagnosticOptions::Clang: case DiagnosticOptions::Vi: OS << ':'; break; case DiagnosticOptions::MSVC: // MSVC2013 and before print 'file(4) : error'. MSVC2015 gets rid of the // space and prints 'file(4): error'. OS << ')'; if (LangOpts.MSCompatibilityVersion && !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015)) OS << ' '; OS << ": "; break; } if (DiagOpts->ShowSourceRanges && !Ranges.empty()) { FileID CaretFileID = Loc.getExpansionLoc().getFileID(); bool PrintedRange = false; for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(), RE = Ranges.end(); RI != RE; ++RI) { // Ignore invalid ranges. if (!RI->isValid()) continue; auto &SM = Loc.getManager(); SourceLocation B = SM.getExpansionLoc(RI->getBegin()); CharSourceRange ERange = SM.getExpansionRange(RI->getEnd()); SourceLocation E = ERange.getEnd(); bool IsTokenRange = ERange.isTokenRange(); std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); // If the start or end of the range is in another file, just discard // it. if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) continue; // Add in the length of the token, so that we cover multi-char // tokens. unsigned TokSize = 0; if (IsTokenRange) TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts); FullSourceLoc BF(B, SM), EF(E, SM); OS << '{' << BF.getLineNumber() << ':' << BF.getColumnNumber() << '-' << EF.getLineNumber() << ':' << (EF.getColumnNumber() + TokSize) << '}'; PrintedRange = true; } if (PrintedRange) OS << ':'; } OS << ' '; }
/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s) /// any characters in LineNo that intersect the SourceRange. void TextDiagnosticPrinter::HighlightRange(const CharSourceRange &R, const SourceManager &SM, unsigned LineNo, FileID FID, std::string &CaretLine, const std::string &SourceLine) { assert(CaretLine.size() == SourceLine.size() && "Expect a correspondence between source and caret line!"); if (!R.isValid()) return; SourceLocation Begin = SM.getInstantiationLoc(R.getBegin()); SourceLocation End = SM.getInstantiationLoc(R.getEnd()); // If the End location and the start location are the same and are a macro // location, then the range was something that came from a macro expansion // or _Pragma. If this is an object-like macro, the best we can do is to // highlight the range. If this is a function-like macro, we'd also like to // highlight the arguments. if (Begin == End && R.getEnd().isMacroID()) End = SM.getInstantiationRange(R.getEnd()).second; unsigned StartLineNo = SM.getInstantiationLineNumber(Begin); if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) return; // No intersection. unsigned EndLineNo = SM.getInstantiationLineNumber(End); if (EndLineNo < LineNo || SM.getFileID(End) != FID) return; // No intersection. // Compute the column number of the start. unsigned StartColNo = 0; if (StartLineNo == LineNo) { StartColNo = SM.getInstantiationColumnNumber(Begin); if (StartColNo) --StartColNo; // Zero base the col #. } // Compute the column number of the end. unsigned EndColNo = CaretLine.size(); if (EndLineNo == LineNo) { EndColNo = SM.getInstantiationColumnNumber(End); if (EndColNo) { --EndColNo; // Zero base the col #. // Add in the length of the token, so that we cover multi-char tokens if // this is a token range. if (R.isTokenRange()) EndColNo += Lexer::MeasureTokenLength(End, SM, *LangOpts); } else { EndColNo = CaretLine.size(); } } assert(StartColNo <= EndColNo && "Invalid range!"); // Check that a token range does not highlight only whitespace. if (R.isTokenRange()) { // Pick the first non-whitespace column. while (StartColNo < SourceLine.size() && (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) ++StartColNo; // Pick the last non-whitespace column. if (EndColNo > SourceLine.size()) EndColNo = SourceLine.size(); while (EndColNo-1 && (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) --EndColNo; // If the start/end passed each other, then we are trying to highlight a range // that just exists in whitespace, which must be some sort of other bug. assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); } // Fill the range with ~'s. for (unsigned i = StartColNo; i < EndColNo; ++i) CaretLine[i] = '~'; }