unsigned SourceManager::getCol(const LREntry &range, const SourceLocation &loc, unsigned line) { if (!line) { if ((line = getLine(range, loc)) == 0) return 0; } SourceFile *file = range.getFile(); // Cached and returned lines are + 1, but the line cache starts at 0. line = line - 1; assert(line < file->lineCache()->length()); uint32_t pos = loc.offset() - range.id; uint32_t line_start = file->lineCache()->at(line); #if !defined(NDEBUG) uint32_t line_end = (line < file->lineCache()->length() - 1) ? file->lineCache()->at(line + 1) : file->length() + 1; assert(pos >= line_start && pos < line_end); #endif return pos - line_start + 1; }
unsigned SourceManager::getLine(const LREntry &range, const SourceLocation &loc) { SourceFile *file = range.getFile(); // Note: we don't OOM check this, since we don't oom check anything. if (!file->lineCache()) file->computeLineCache(); uint32_t pos = loc.offset() - range.id; assert(pos <= file->length()); // If the position is at end-of-file, return the last line number. LineExtents *lines = file->lineCache(); if (pos == file->length()) return lines->length(); uint32_t lower = 0; uint32_t upper = lines->length(); while (lower < upper) { uint32_t index = (lower + upper) / 2; uint32_t line_start = lines->at(index); if (pos < line_start) { upper = index; continue; } // The range should be (start, end]. uint32_t line_end = (index < lines->length() - 1) ? lines->at(index + 1) : file->length(); if (pos >= line_end) { lower = index + 1; continue; } // Either the id is the first character of a line, or before the first // character of the next line, or it should be the terminal offset. assert(pos >= line_start && pos < line_end); return index + 1; } assert(false); return 0; }