forked from OSchip/llvm-project
[clangd] findNearbyIdentifier(): guaranteed to give up after 2^N lines
As @kadircet mentions in D84912#2184144, `findNearbyIdentifier()` traverses the whole file if there is no identifier for the word. This patch ensures give up after 2^N lines in any case. Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D87891
This commit is contained in:
parent
2159ed811f
commit
d8ba6b4ab3
|
@ -562,19 +562,34 @@ const syntax::Token *findNearbyIdentifier(const SpelledWord &Word,
|
|||
auto Cost = [&](SourceLocation Loc) -> unsigned {
|
||||
assert(SM.getFileID(Loc) == File && "spelled token in wrong file?");
|
||||
unsigned Line = SM.getSpellingLineNumber(Loc);
|
||||
if (Line > WordLine)
|
||||
return 1 + llvm::Log2_64(Line - WordLine);
|
||||
if (Line < WordLine)
|
||||
return 2 + llvm::Log2_64(WordLine - Line);
|
||||
return 0;
|
||||
return Line >= WordLine ? Line - WordLine : 2 * (WordLine - Line);
|
||||
};
|
||||
const syntax::Token *BestTok = nullptr;
|
||||
// Search bounds are based on word length: 2^N lines forward.
|
||||
unsigned BestCost = Word.Text.size() + 1;
|
||||
unsigned BestCost = -1;
|
||||
// Search bounds are based on word length:
|
||||
// - forward: 2^N lines
|
||||
// - backward: 2^(N-1) lines.
|
||||
unsigned MaxDistance =
|
||||
1U << std::min<unsigned>(Word.Text.size(),
|
||||
std::numeric_limits<unsigned>::digits - 1);
|
||||
// Line number for SM.translateLineCol() should be one-based, also
|
||||
// SM.translateLineCol() can handle line number greater than
|
||||
// number of lines in the file.
|
||||
// - LineMin = max(1, WordLine + 1 - 2^(N-1))
|
||||
// - LineMax = WordLine + 1 + 2^N
|
||||
unsigned LineMin =
|
||||
WordLine + 1 <= MaxDistance / 2 ? 1 : WordLine + 1 - MaxDistance / 2;
|
||||
unsigned LineMax = WordLine + 1 + MaxDistance;
|
||||
SourceLocation LocMin = SM.translateLineCol(File, LineMin, 1);
|
||||
assert(LocMin.isValid());
|
||||
SourceLocation LocMax = SM.translateLineCol(File, LineMax, 1);
|
||||
assert(LocMax.isValid());
|
||||
|
||||
// Updates BestTok and BestCost if Tok is a good candidate.
|
||||
// May return true if the cost is too high for this token.
|
||||
auto Consider = [&](const syntax::Token &Tok) {
|
||||
if (Tok.location() < LocMin || Tok.location() > LocMax)
|
||||
return true; // we are too far from the word, break the outer loop.
|
||||
if (!(Tok.kind() == tok::identifier && Tok.text(SM) == Word.Text))
|
||||
return false;
|
||||
// No point guessing the same location we started with.
|
||||
|
|
|
@ -1428,6 +1428,11 @@ TEST(LocateSymbol, NearbyIdentifier) {
|
|||
|
||||
|
||||
// h^i
|
||||
|
||||
|
||||
|
||||
|
||||
int x = hi;
|
||||
)cpp",
|
||||
R"cpp(
|
||||
// prefer nearest occurrence even if several matched tokens
|
||||
|
|
Loading…
Reference in New Issue