Skip to content

Commit 5f1adf0

Browse files
authored
[clangd] Fix crash with null check for Token at Loc (#94528)
Fixes #94599
1 parent 4f320e6 commit 5f1adf0

File tree

10 files changed

+55
-26
lines changed

10 files changed

+55
-26
lines changed

Diff for: clang-tools-extra/clangd/FindSymbols.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ class DocumentOutline {
454454
if (!MacroName.isValid() || !MacroName.isFileID())
455455
continue;
456456
// All conditions satisfied, add the macro.
457-
if (auto *Tok = AST.getTokens().spelledTokenAt(MacroName))
457+
if (auto *Tok = AST.getTokens().spelledTokenContaining(MacroName))
458458
CurParent = &CurParent->inMacro(
459459
*Tok, SM, AST.getTokens().expansionStartingAt(Tok));
460460
}

Diff for: clang-tools-extra/clangd/IncludeCleaner.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ collectMacroReferences(ParsedAST &AST) {
303303
for (const auto &[_, Refs] : AST.getMacros().MacroRefs) {
304304
for (const auto &Ref : Refs) {
305305
auto Loc = SM.getComposedLoc(SM.getMainFileID(), Ref.StartOffset);
306-
const auto *Tok = AST.getTokens().spelledTokenAt(Loc);
306+
const auto *Tok = AST.getTokens().spelledTokenContaining(Loc);
307307
if (!Tok)
308308
continue;
309309
auto Macro = locateMacroAt(*Tok, PP);

Diff for: clang-tools-extra/clangd/SemanticHighlighting.cpp

+5-6
Original file line numberDiff line numberDiff line change
@@ -447,11 +447,10 @@ class HighlightingsBuilder {
447447
if (!RLoc.isValid())
448448
return;
449449

450-
const auto *RTok = TB.spelledTokenAt(RLoc);
451-
// Handle `>>`. RLoc is always pointing at the right location, just change
452-
// the end to be offset by 1.
453-
// We'll either point at the beginning of `>>`, hence get a proper spelled
454-
// or point in the middle of `>>` hence get no spelled tok.
450+
const auto *RTok = TB.spelledTokenContaining(RLoc);
451+
// Handle `>>`. RLoc is either part of `>>` or a spelled token on its own
452+
// `>`. If it's the former, slice to have length of 1, if latter use the
453+
// token as-is.
455454
if (!RTok || RTok->kind() == tok::greatergreater) {
456455
Position Begin = sourceLocToPosition(SourceMgr, RLoc);
457456
Position End = sourceLocToPosition(SourceMgr, RLoc.getLocWithOffset(1));
@@ -577,7 +576,7 @@ class HighlightingsBuilder {
577576
return std::nullopt;
578577
// We might have offsets in the main file that don't correspond to any
579578
// spelled tokens.
580-
const auto *Tok = TB.spelledTokenAt(Loc);
579+
const auto *Tok = TB.spelledTokenContaining(Loc);
581580
if (!Tok)
582581
return std::nullopt;
583582
return halfOpenToRange(SourceMgr,

Diff for: clang-tools-extra/clangd/XRefs.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,7 @@ std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {
844844
if (Inc.Resolved.empty())
845845
continue;
846846
auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
847-
const auto *HashTok = AST.getTokens().spelledTokenAt(HashLoc);
847+
const auto *HashTok = AST.getTokens().spelledTokenContaining(HashLoc);
848848
assert(HashTok && "got inclusion at wrong offset");
849849
const auto *IncludeTok = std::next(HashTok);
850850
const auto *FileTok = std::next(IncludeTok);
@@ -938,7 +938,7 @@ class ReferenceFinder : public index::IndexDataConsumer {
938938
CollectorOpts.CollectMainFileSymbols = true;
939939
for (SourceLocation L : Locs) {
940940
L = SM.getFileLoc(L);
941-
if (const auto *Tok = TB.spelledTokenAt(L))
941+
if (const auto *Tok = TB.spelledTokenContaining(L))
942942
References.push_back(
943943
{*Tok, Roles,
944944
SymbolCollector::getRefContainer(ASTNode.Parent, CollectorOpts)});
@@ -1216,7 +1216,7 @@ DocumentHighlight toHighlight(const ReferenceFinder::Reference &Ref,
12161216
std::optional<DocumentHighlight> toHighlight(SourceLocation Loc,
12171217
const syntax::TokenBuffer &TB) {
12181218
Loc = TB.sourceManager().getFileLoc(Loc);
1219-
if (const auto *Tok = TB.spelledTokenAt(Loc)) {
1219+
if (const auto *Tok = TB.spelledTokenContaining(Loc)) {
12201220
DocumentHighlight Result;
12211221
Result.range = halfOpenToRange(
12221222
TB.sourceManager(),
@@ -1353,7 +1353,8 @@ maybeFindIncludeReferences(ParsedAST &AST, Position Pos,
13531353
Loc = SM.getIncludeLoc(SM.getFileID(Loc));
13541354

13551355
ReferencesResult::Reference Result;
1356-
const auto *Token = AST.getTokens().spelledTokenAt(Loc);
1356+
const auto *Token = AST.getTokens().spelledTokenContaining(Loc);
1357+
assert(Token && "references expected token here");
13571358
Result.Loc.range = Range{sourceLocToPosition(SM, Token->location()),
13581359
sourceLocToPosition(SM, Token->endLocation())};
13591360
Result.Loc.uri = URIMainFile;

Diff for: clang-tools-extra/clangd/refactor/Rename.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@ std::vector<SymbolRange> collectRenameIdentifierRanges(
748748
clangd::Range tokenRangeForLoc(ParsedAST &AST, SourceLocation TokLoc,
749749
const SourceManager &SM,
750750
const LangOptions &LangOpts) {
751-
const auto *Token = AST.getTokens().spelledTokenAt(TokLoc);
751+
const auto *Token = AST.getTokens().spelledTokenContaining(TokLoc);
752752
assert(Token && "rename expects spelled tokens");
753753
clangd::Range Result;
754754
Result.start = sourceLocToPosition(SM, Token->location());

Diff for: clang-tools-extra/clangd/unittests/PreambleTests.cpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ TEST(PreamblePatchTest, LocateMacroAtWorks) {
417417
ASSERT_TRUE(AST);
418418

419419
const auto &SM = AST->getSourceManager();
420-
auto *MacroTok = AST->getTokens().spelledTokenAt(
420+
auto *MacroTok = AST->getTokens().spelledTokenContaining(
421421
SM.getComposedLoc(SM.getMainFileID(), Modified.point("use")));
422422
ASSERT_TRUE(MacroTok);
423423

@@ -441,7 +441,7 @@ TEST(PreamblePatchTest, LocateMacroAtDeletion) {
441441
ASSERT_TRUE(AST);
442442

443443
const auto &SM = AST->getSourceManager();
444-
auto *MacroTok = AST->getTokens().spelledTokenAt(
444+
auto *MacroTok = AST->getTokens().spelledTokenContaining(
445445
SM.getComposedLoc(SM.getMainFileID(), Modified.point()));
446446
ASSERT_TRUE(MacroTok);
447447

@@ -512,9 +512,10 @@ TEST(PreamblePatchTest, RefsToMacros) {
512512
ExpectedLocations.push_back(referenceRangeIs(R));
513513

514514
for (const auto &P : Modified.points()) {
515-
auto *MacroTok = AST->getTokens().spelledTokenAt(SM.getComposedLoc(
516-
SM.getMainFileID(),
517-
llvm::cantFail(positionToOffset(Modified.code(), P))));
515+
auto *MacroTok =
516+
AST->getTokens().spelledTokenContaining(SM.getComposedLoc(
517+
SM.getMainFileID(),
518+
llvm::cantFail(positionToOffset(Modified.code(), P))));
518519
ASSERT_TRUE(MacroTok);
519520
EXPECT_THAT(findReferences(*AST, P, 0).References,
520521
testing::ElementsAreArray(ExpectedLocations));

Diff for: clang-tools-extra/clangd/unittests/XRefsTests.cpp

+15-1
Original file line numberDiff line numberDiff line change
@@ -2173,6 +2173,11 @@ TEST(FindReferences, WithinAST) {
21732173
using $def[[MyTypeD^ef]] = int;
21742174
enum MyEnum : $(MyEnum)[[MyTy^peDef]] { };
21752175
)cpp",
2176+
// UDL
2177+
R"cpp(
2178+
bool $decl[[operator]]"" _u^dl(unsigned long long value);
2179+
bool x = $(x)[[1_udl]];
2180+
)cpp",
21762181
};
21772182
for (const char *Test : Tests)
21782183
checkFindRefs(Test);
@@ -2358,7 +2363,13 @@ TEST(FindReferences, UsedSymbolsFromInclude) {
23582363

23592364
R"cpp([[#in^clude <vector>]]
23602365
std::[[vector]]<int> vec;
2361-
)cpp"};
2366+
)cpp",
2367+
2368+
R"cpp(
2369+
[[#include ^"udl_header.h"]]
2370+
auto x = [[1_b]];
2371+
)cpp",
2372+
};
23622373
for (const char *Test : Tests) {
23632374
Annotations T(Test);
23642375
auto TU = TestTU::withCode(T.code());
@@ -2375,6 +2386,9 @@ TEST(FindReferences, UsedSymbolsFromInclude) {
23752386
class vector{};
23762387
}
23772388
)cpp");
2389+
TU.AdditionalFiles["udl_header.h"] = guard(R"cpp(
2390+
bool operator"" _b(unsigned long long value);
2391+
)cpp");
23782392
TU.ExtraArgs.push_back("-isystem" + testPath("system"));
23792393

23802394
auto AST = TU.build();

Diff for: clang/include/clang/Tooling/Syntax/Tokens.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -292,9 +292,9 @@ class TokenBuffer {
292292
/// "DECL", "(", "a", ")", ";"}
293293
llvm::ArrayRef<syntax::Token> spelledTokens(FileID FID) const;
294294

295-
/// Returns the spelled Token starting at Loc, if there are no such tokens
295+
/// Returns the spelled Token containing the Loc, if there are no such tokens
296296
/// returns nullptr.
297-
const syntax::Token *spelledTokenAt(SourceLocation Loc) const;
297+
const syntax::Token *spelledTokenContaining(SourceLocation Loc) const;
298298

299299
/// Get all tokens that expand a macro in \p FID. For the following input
300300
/// #define FOO B

Diff for: clang/lib/Tooling/Syntax/Tokens.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -383,12 +383,13 @@ llvm::ArrayRef<syntax::Token> TokenBuffer::spelledTokens(FileID FID) const {
383383
return It->second.SpelledTokens;
384384
}
385385

386-
const syntax::Token *TokenBuffer::spelledTokenAt(SourceLocation Loc) const {
386+
const syntax::Token *
387+
TokenBuffer::spelledTokenContaining(SourceLocation Loc) const {
387388
assert(Loc.isFileID());
388389
const auto *Tok = llvm::partition_point(
389390
spelledTokens(SourceMgr->getFileID(Loc)),
390-
[&](const syntax::Token &Tok) { return Tok.location() < Loc; });
391-
if (!Tok || Tok->location() != Loc)
391+
[&](const syntax::Token &Tok) { return Tok.endLocation() <= Loc; });
392+
if (!Tok || Loc < Tok->location())
392393
return nullptr;
393394
return Tok;
394395
}

Diff for: clang/unittests/Tooling/Syntax/TokensTest.cpp

+15-2
Original file line numberDiff line numberDiff line change
@@ -374,11 +374,24 @@ TEST_F(TokenCollectorTest, Locations) {
374374

375375
auto StartLoc = SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID());
376376
for (auto &R : Code.ranges()) {
377-
EXPECT_THAT(Buffer.spelledTokenAt(StartLoc.getLocWithOffset(R.Begin)),
378-
Pointee(RangeIs(R)));
377+
EXPECT_THAT(
378+
Buffer.spelledTokenContaining(StartLoc.getLocWithOffset(R.Begin)),
379+
Pointee(RangeIs(R)));
379380
}
380381
}
381382

383+
TEST_F(TokenCollectorTest, LocationInMiddleOfSpelledToken) {
384+
llvm::Annotations Code(R"cpp(
385+
int foo = [[baa^aar]];
386+
)cpp");
387+
recordTokens(Code.code());
388+
// Check spelled tokens.
389+
auto StartLoc = SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID());
390+
EXPECT_THAT(
391+
Buffer.spelledTokenContaining(StartLoc.getLocWithOffset(Code.point())),
392+
Pointee(RangeIs(Code.range())));
393+
}
394+
382395
TEST_F(TokenCollectorTest, MacroDirectives) {
383396
// Macro directives are not stored anywhere at the moment.
384397
std::string Code = R"cpp(

0 commit comments

Comments
 (0)