[clang-tools-extra] [clang-tidy][NFC] Convert Lexer utils to use std::optional<Token> (PR #174809)
Baranov Victor via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 7 09:25:16 PST 2026
https://github.com/vbvictor created https://github.com/llvm/llvm-project/pull/174809
None
>From 691f1fe7b5aaa9ec474969a39412525824ae43ab Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Thu, 8 Jan 2026 01:22:51 +0800
Subject: [PATCH] [clang-tidy][NFC] Convert Lexer utils to use
std::optional<Token>
---
.../bugprone/ArgumentCommentCheck.cpp | 8 +++----
.../bugprone/OptionalValueConversionCheck.cpp | 9 ++++----
.../bugprone/SuspiciousSemicolonCheck.cpp | 9 ++++----
.../ProTypeMemberInitCheck.cpp | 22 ++++++++++---------
.../modernize/UseConstraintsCheck.cpp | 4 ++--
.../readability/DeleteNullPointerCheck.cpp | 14 +++++++-----
.../readability/IsolateDeclarationCheck.cpp | 4 ++--
.../readability/RedundantMemberInitCheck.cpp | 10 ++++-----
.../clang-tidy/utils/FixItHintUtils.cpp | 17 +++++++-------
.../clang-tidy/utils/LexerUtils.cpp | 12 +++++-----
.../clang-tidy/utils/LexerUtils.h | 11 ++++++----
11 files changed, 64 insertions(+), 56 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp
index 16a0fb1b037bf..2e963cd995f74 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp
@@ -127,16 +127,16 @@ static std::vector<std::pair<SourceLocation, StringRef>>
getCommentsBeforeLoc(ASTContext *Ctx, SourceLocation Loc) {
std::vector<std::pair<SourceLocation, StringRef>> Comments;
while (Loc.isValid()) {
- const clang::Token Tok = utils::lexer::getPreviousToken(
+ const std::optional<Token> Tok = utils::lexer::getPreviousToken(
Loc, Ctx->getSourceManager(), Ctx->getLangOpts(),
/*SkipComments=*/false);
- if (Tok.isNot(tok::comment))
+ if (!Tok || Tok->isNot(tok::comment))
break;
- Loc = Tok.getLocation();
+ Loc = Tok->getLocation();
Comments.emplace_back(
Loc,
Lexer::getSourceText(CharSourceRange::getCharRange(
- Loc, Loc.getLocWithOffset(Tok.getLength())),
+ Loc, Loc.getLocWithOffset(Tok->getLength())),
Ctx->getSourceManager(), Ctx->getLangOpts()));
}
return Comments;
diff --git a/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp
index 19b4fc1c044df..c532d873a5e4c 100644
--- a/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp
@@ -139,10 +139,11 @@ void OptionalValueConversionCheck::check(
}
if (const auto *CallExpr =
Result.Nodes.getNodeAs<CXXMemberCallExpr>("member-call")) {
- const SourceLocation Begin =
- utils::lexer::getPreviousToken(CallExpr->getExprLoc(),
- *Result.SourceManager, getLangOpts())
- .getLocation();
+ const std::optional<Token> Tok = utils::lexer::getPreviousToken(
+ CallExpr->getExprLoc(), *Result.SourceManager, getLangOpts());
+ if (!Tok)
+ return;
+ const SourceLocation Begin = Tok->getLocation();
auto Diag =
diag(CallExpr->getExprLoc(),
"remove call to %0 to silence this warning", DiagnosticIDs::Note);
diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousSemicolonCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousSemicolonCheck.cpp
index 9d37fc1e8728e..bef4359ec2e43 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousSemicolonCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousSemicolonCheck.cpp
@@ -37,16 +37,16 @@ void SuspiciousSemicolonCheck::check(const MatchFinder::MatchResult &Result) {
return;
ASTContext &Ctxt = *Result.Context;
- auto Token = utils::lexer::getPreviousToken(LocStart, Ctxt.getSourceManager(),
- Ctxt.getLangOpts());
- auto &SM = *Result.SourceManager;
+ const auto &SM = *Result.SourceManager;
const unsigned SemicolonLine = SM.getSpellingLineNumber(LocStart);
const auto *Statement = Result.Nodes.getNodeAs<Stmt>("stmt");
const bool IsIfStmt = isa<IfStmt>(Statement);
+ const std::optional<Token> PrevTok = utils::lexer::getPreviousToken(
+ LocStart, Ctxt.getSourceManager(), Ctxt.getLangOpts());
if (!IsIfStmt &&
- SM.getSpellingLineNumber(Token.getLocation()) != SemicolonLine)
+ SM.getSpellingLineNumber(PrevTok->getLocation()) != SemicolonLine)
return;
const SourceLocation LocEnd = Semicolon->getEndLoc();
@@ -55,6 +55,7 @@ void SuspiciousSemicolonCheck::check(const MatchFinder::MatchResult &Result) {
Lexer Lexer(SM.getLocForStartOfFile(FID), Ctxt.getLangOpts(),
Buffer.getBufferStart(), SM.getCharacterData(LocEnd) + 1,
Buffer.getBufferEnd());
+ Token Token;
if (Lexer.LexFromRawLexer(Token))
return;
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
index 5306690e22eeb..ab068417b869e 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
@@ -149,18 +149,20 @@ struct InitializerInsertion {
"insertion represents a new initializer list.");
SourceLocation Location;
switch (Placement) {
- case InitializerPlacement::New:
- Location = utils::lexer::getPreviousToken(
- Constructor.getBody()->getBeginLoc(),
- Context.getSourceManager(), Context.getLangOpts())
- .getLocation();
+ case InitializerPlacement::New: {
+ const std::optional<Token> Tok = utils::lexer::getPreviousToken(
+ Constructor.getBody()->getBeginLoc(), Context.getSourceManager(),
+ Context.getLangOpts());
+ Location = Tok.has_value() ? Tok->getLocation() : SourceLocation{};
break;
- case InitializerPlacement::Before:
- Location = utils::lexer::getPreviousToken(
- Where->getSourceRange().getBegin(),
- Context.getSourceManager(), Context.getLangOpts())
- .getLocation();
+ }
+ case InitializerPlacement::Before: {
+ const std::optional<Token> Tok = utils::lexer::getPreviousToken(
+ Where->getSourceRange().getBegin(), Context.getSourceManager(),
+ Context.getLangOpts());
+ Location = Tok.has_value() ? Tok->getLocation() : SourceLocation{};
break;
+ }
case InitializerPlacement::After:
Location = Where->getRParenLoc();
break;
diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp
index 3e9c0e85fe96c..518be5c5d9812 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp
@@ -318,11 +318,11 @@ static std::optional<std::string> getConditionText(const Expr *ConditionExpr,
return std::nullopt;
const bool SkipComments = false;
- Token PrevToken;
+ std::optional<Token> PrevToken;
std::tie(PrevToken, PrevTokenLoc) = utils::lexer::getPreviousTokenAndStart(
PrevTokenLoc, SM, LangOpts, SkipComments);
const bool EndsWithDoubleSlash =
- PrevToken.is(tok::comment) &&
+ PrevToken && PrevToken->is(tok::comment) &&
Lexer::getSourceText(CharSourceRange::getCharRange(
PrevTokenLoc, PrevTokenLoc.getLocWithOffset(2)),
SM, LangOpts) == "//";
diff --git a/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp
index e96bfe7fe7271..b7e0d9c236973 100644
--- a/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp
@@ -52,16 +52,18 @@ void DeleteNullPointerCheck::check(const MatchFinder::MatchResult &Result) {
auto Diag = diag(
IfWithDelete->getBeginLoc(),
"'if' statement is unnecessary; deleting null pointer has no effect");
- if (IfWithDelete->getElse())
+ if (IfWithDelete->hasElseStorage())
return;
// FIXME: generate fixit for this case.
+ const std::optional<Token> PrevTok = utils::lexer::getPreviousToken(
+ IfWithDelete->getThen()->getBeginLoc(), *Result.SourceManager,
+ Result.Context->getLangOpts());
+ if (!PrevTok)
+ return;
+
Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
- IfWithDelete->getBeginLoc(),
- utils::lexer::getPreviousToken(IfWithDelete->getThen()->getBeginLoc(),
- *Result.SourceManager,
- Result.Context->getLangOpts())
- .getLocation()));
+ IfWithDelete->getBeginLoc(), PrevTok->getLocation()));
if (Compound) {
Diag << FixItHint::CreateRemoval(
diff --git a/clang-tools-extra/clang-tidy/readability/IsolateDeclarationCheck.cpp b/clang-tools-extra/clang-tidy/readability/IsolateDeclarationCheck.cpp
index fa5a0b7cd3647..5e3f3f6777279 100644
--- a/clang-tools-extra/clang-tidy/readability/IsolateDeclarationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/IsolateDeclarationCheck.cpp
@@ -157,8 +157,8 @@ declRanges(const DeclStmt *DS, const SourceManager &SM,
if (Start.isInvalid() || Start.isMacroID())
break;
- const Token T = getPreviousToken(Start, SM, LangOpts);
- if (T.is(tok::l_paren)) {
+ const std::optional<Token> T = getPreviousToken(Start, SM, LangOpts);
+ if (T && T->is(tok::l_paren)) {
Start = findPreviousTokenStart(Start, SM, LangOpts);
continue;
}
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
index 1bbb9c86fee14..f891c954b19ea 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
@@ -21,16 +21,16 @@ namespace clang::tidy::readability {
static SourceRange
getFullInitRangeInclWhitespaces(SourceRange Range, const SourceManager &SM,
const LangOptions &LangOpts) {
- const Token PrevToken =
+ const std::optional<Token> PrevToken =
utils::lexer::getPreviousToken(Range.getBegin(), SM, LangOpts, false);
- if (PrevToken.is(tok::unknown))
+ if (!PrevToken)
return Range;
- if (PrevToken.isNot(tok::equal))
- return {PrevToken.getEndLoc(), Range.getEnd()};
+ if (PrevToken->isNot(tok::equal))
+ return {PrevToken->getEndLoc(), Range.getEnd()};
return getFullInitRangeInclWhitespaces(
- {PrevToken.getLocation(), Range.getEnd()}, SM, LangOpts);
+ {PrevToken->getLocation(), Range.getEnd()}, SM, LangOpts);
}
void RedundantMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
diff --git a/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp b/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp
index 5fcf5ed30fb81..9eca12fe19bf1 100644
--- a/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp
+++ b/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp
@@ -19,15 +19,15 @@ namespace clang::tidy::utils::fixit {
FixItHint changeVarDeclToReference(const VarDecl &Var, ASTContext &Context) {
SourceLocation AmpLocation = Var.getLocation();
- auto Token = utils::lexer::getPreviousToken(
+ const std::optional<Token> Token = utils::lexer::getPreviousToken(
AmpLocation, Context.getSourceManager(), Context.getLangOpts());
// For parameter packs the '&' must go before the '...' token
- if (Token.is(tok::ellipsis))
- return FixItHint::CreateInsertion(Token.getLocation(), "&");
+ if (Token && Token->is(tok::ellipsis))
+ return FixItHint::CreateInsertion(Token->getLocation(), "&");
- if (!Token.is(tok::unknown))
- AmpLocation = Lexer::getLocForEndOfToken(Token.getLocation(), 0,
+ if (Token)
+ AmpLocation = Lexer::getLocForEndOfToken(Token->getLocation(), 0,
Context.getSourceManager(),
Context.getLangOpts());
return FixItHint::CreateInsertion(AmpLocation, "&");
@@ -53,10 +53,9 @@ skipLParensBackwards(SourceLocation Start, const ASTContext &Context) {
return std::nullopt;
auto PreviousTokenLParen = [&Start, &Context]() {
- Token T;
- T = lexer::getPreviousToken(Start, Context.getSourceManager(),
- Context.getLangOpts());
- return T.is(tok::l_paren);
+ const std::optional<Token> T = lexer::getPreviousToken(
+ Start, Context.getSourceManager(), Context.getLangOpts());
+ return T && T->is(tok::l_paren);
};
while (Start.isValid() && PreviousTokenLParen())
diff --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
index e759c0b8b9fdc..b77d985b76d77 100644
--- a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
+++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
@@ -13,7 +13,7 @@
namespace clang::tidy::utils::lexer {
-std::pair<Token, SourceLocation>
+std::pair<std::optional<Token>, SourceLocation>
getPreviousTokenAndStart(SourceLocation Location, const SourceManager &SM,
const LangOptions &LangOpts, bool SkipComments) {
const std::optional<Token> Tok =
@@ -22,13 +22,13 @@ getPreviousTokenAndStart(SourceLocation Location, const SourceManager &SM,
if (Tok.has_value())
return {*Tok, Lexer::GetBeginningOfToken(Tok->getLocation(), SM, LangOpts)};
- Token Token;
- Token.setKind(tok::unknown);
- return {Token, SourceLocation()};
+ return {std::nullopt, SourceLocation()};
}
-Token getPreviousToken(SourceLocation Location, const SourceManager &SM,
- const LangOptions &LangOpts, bool SkipComments) {
+std::optional<Token> getPreviousToken(SourceLocation Location,
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ bool SkipComments) {
auto [Token, Start] =
getPreviousTokenAndStart(Location, SM, LangOpts, SkipComments);
return Token;
diff --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.h b/clang-tools-extra/clang-tidy/utils/LexerUtils.h
index e698ef68441ce..94d26ec8f07d7 100644
--- a/clang-tools-extra/clang-tidy/utils/LexerUtils.h
+++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.h
@@ -21,10 +21,13 @@ class Stmt;
namespace tidy::utils::lexer {
-/// Returns previous token or ``tok::unknown`` if not found.
-Token getPreviousToken(SourceLocation Location, const SourceManager &SM,
- const LangOptions &LangOpts, bool SkipComments = true);
-std::pair<Token, SourceLocation>
+/// Returns previous token.
+std::optional<Token> getPreviousToken(SourceLocation Location,
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ bool SkipComments = true);
+
+std::pair<std::optional<Token>, SourceLocation>
getPreviousTokenAndStart(SourceLocation Location, const SourceManager &SM,
const LangOptions &LangOpts, bool SkipComments = true);
More information about the cfe-commits
mailing list