[clang-tools-extra] [clang-tidy] Update google todo checker with style guide changes. (PR #165565)
Quentin Khan via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 31 08:46:13 PDT 2025
https://github.com/qukhan updated https://github.com/llvm/llvm-project/pull/165565
>From 5de2f88c0bf82f10e6e56a2284ed9b97a82df737 Mon Sep 17 00:00:00 2001
From: Quentin Khan <qkhan at google.com>
Date: Thu, 23 Oct 2025 15:10:55 +0200
Subject: [PATCH] [clang-tidy] Update google todo checker with style guide
changes.
The [Google style guide] now allows (and recommends) writing TODOs with
the following format:
```cpp
// TODO: bug reference - details about what needs to be done.
```
With this change the checker accepts the new style and suggests in in the
fix-it hint. The previous style is still accepted.
A new configuration option, `google-readability-todo.Style` is available
to switch between the `Parentheses` (legacy) style and the `Hyphen`
style.
[Google style guide]: https://google.github.io/styleguide/cppguide.html#TODO_Comments
---
.../clang-tidy/google/TodoCommentCheck.cpp | 83 ++++++++++++++++---
.../clang-tidy/google/TodoCommentCheck.h | 2 +
clang-tools-extra/docs/ReleaseNotes.rst | 4 +
.../checks/google/readability-todo.rst | 11 +++
.../google/readability-todo-hyphen.cpp | 40 +++++++++
...o.cpp => readability-todo-parentheses.cpp} | 16 +++-
6 files changed, 145 insertions(+), 11 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/google/readability-todo-hyphen.cpp
rename clang-tools-extra/test/clang-tidy/checkers/google/{readability-todo.cpp => readability-todo-parentheses.cpp} (54%)
diff --git a/clang-tools-extra/clang-tidy/google/TodoCommentCheck.cpp b/clang-tools-extra/clang-tidy/google/TodoCommentCheck.cpp
index 8554870287c81..dd80fe31047c4 100644
--- a/clang-tools-extra/clang-tidy/google/TodoCommentCheck.cpp
+++ b/clang-tools-extra/clang-tidy/google/TodoCommentCheck.cpp
@@ -11,41 +11,100 @@
#include "clang/Lex/Preprocessor.h"
#include <optional>
-namespace clang::tidy::google::readability {
+namespace clang::tidy {
+
+namespace google::readability {
+
+enum class StyleKind { Parentheses, Hyphen };
+
+} // namespace google::readability
+
+template <> struct OptionEnumMapping<google::readability::StyleKind> {
+ static ArrayRef<std::pair<google::readability::StyleKind, StringRef>>
+ getEnumMapping() {
+ static constexpr std::pair<google::readability::StyleKind, StringRef>
+ Mapping[] = {
+ {google::readability::StyleKind::Hyphen, "Hyphen"},
+ {google::readability::StyleKind::Parentheses, "Parentheses"},
+ };
+ return {Mapping};
+ }
+};
+
+} // namespace clang::tidy
+namespace clang::tidy::google::readability {
class TodoCommentCheck::TodoCommentHandler : public CommentHandler {
public:
TodoCommentHandler(TodoCommentCheck &Check, std::optional<std::string> User)
: Check(Check), User(User ? *User : "unknown"),
- TodoMatch("^// *TODO *(\\(.*\\))?:?( )?(.*)$") {}
+ TodoMatch(R"(^// *TODO *((\((.*)\))?:?( )?|: *(.*) *- *)?(.*)$)") {
+ llvm::StringRef TodoStyleString = Check.Options.get("Style", "Hyphen");
+ for (auto [Value, Name] : OptionEnumMapping<StyleKind>::getEnumMapping()) {
+ if (Name == TodoStyleString) {
+ TodoStyle = Value;
+ return;
+ }
+ }
+ Check.configurationDiag(
+ "invalid value '%0' for "
+ "google-readability-todo.Style; valid values are "
+ "'Parentheses' and 'Hyphen'. Defaulting to 'Hyphen'")
+ << TodoStyleString;
+ }
bool HandleComment(Preprocessor &PP, SourceRange Range) override {
StringRef Text =
Lexer::getSourceText(CharSourceRange::getCharRange(Range),
PP.getSourceManager(), PP.getLangOpts());
- SmallVector<StringRef, 4> Matches;
+ SmallVector<StringRef, 7> Matches;
if (!TodoMatch.match(Text, &Matches))
return false;
- StringRef Username = Matches[1];
- StringRef Comment = Matches[3];
+ const StyleKind ParsedStyle =
+ !Matches[3].empty() ? StyleKind::Parentheses : StyleKind::Hyphen;
+ const StringRef Username =
+ ParsedStyle == StyleKind::Parentheses ? Matches[3] : Matches[5];
+ const StringRef Comment = Matches[6];
- if (!Username.empty())
+ if (!Username.empty() &&
+ (ParsedStyle == StyleKind::Parentheses || !Comment.empty())) {
return false;
+ }
- std::string NewText = ("// TODO(" + Twine(User) + "): " + Comment).str();
+ if (Username.empty()) {
+ Check.diag(Range.getBegin(), "missing username/bug in TODO")
+ << FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(Range),
+ createReplacementString(Username, Comment));
+ }
+
+ if (Comment.empty())
+ Check.diag(Range.getBegin(), "missing details in TODO");
- Check.diag(Range.getBegin(), "missing username/bug in TODO")
- << FixItHint::CreateReplacement(CharSourceRange::getCharRange(Range),
- NewText);
return false;
}
+ std::string createReplacementString(const StringRef Username,
+ const StringRef Comment) const {
+ if (TodoStyle == StyleKind::Parentheses) {
+ return ("// TODO(" + Twine(User) +
+ "): " + (Comment.empty() ? "some details" : Comment))
+ .str();
+ }
+ return ("// TODO: " + Twine(User) + " - " +
+ (Comment.empty() ? "some details" : Comment))
+ .str();
+ }
+
+ StyleKind getTodoStyle() const { return TodoStyle; }
+
private:
TodoCommentCheck &Check;
std::string User;
llvm::Regex TodoMatch;
+ StyleKind TodoStyle = StyleKind::Hyphen;
};
TodoCommentCheck::TodoCommentCheck(StringRef Name, ClangTidyContext *Context)
@@ -61,4 +120,8 @@ void TodoCommentCheck::registerPPCallbacks(const SourceManager &SM,
PP->addCommentHandler(Handler.get());
}
+void TodoCommentCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "Style", Handler->getTodoStyle());
+}
+
} // namespace clang::tidy::google::readability
diff --git a/clang-tools-extra/clang-tidy/google/TodoCommentCheck.h b/clang-tools-extra/clang-tidy/google/TodoCommentCheck.h
index 05f9cc6618eb1..854b9cea673c2 100644
--- a/clang-tools-extra/clang-tidy/google/TodoCommentCheck.h
+++ b/clang-tools-extra/clang-tidy/google/TodoCommentCheck.h
@@ -27,6 +27,8 @@ class TodoCommentCheck : public ClangTidyCheck {
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
Preprocessor *ModuleExpanderPP) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
private:
class TodoCommentHandler;
std::unique_ptr<TodoCommentHandler> Handler;
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 8a0151f567c24..68e2cf3a4656f 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -329,6 +329,10 @@ Changes in existing checks
adding an option to allow pointer arithmetic via prefix/postfix increment or
decrement operators.
+- Improved :doc:`google-readability-todo
+ <clang-tidy/checks/google/readability-todo>` check to accept the new todo
+ format from the Google Style Guide.
+
- Improved :doc:`llvm-prefer-isa-or-dyn-cast-in-conditionals
<clang-tidy/checks/llvm/prefer-isa-or-dyn-cast-in-conditionals>` check:
diff --git a/clang-tools-extra/docs/clang-tidy/checks/google/readability-todo.rst b/clang-tools-extra/docs/clang-tidy/checks/google/readability-todo.rst
index 159d2b4adccac..fccfa81166436 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/google/readability-todo.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/google/readability-todo.rst
@@ -9,3 +9,14 @@ The relevant style guide section is
https://google.github.io/styleguide/cppguide.html#TODO_Comments.
Corresponding cpplint.py check: `readability/todo`
+
+Options
+-------
+
+.. option:: Style
+
+ A string specifying the TODO style for fix-it hints. Accepted values are
+ `Hyphen` and `Parentheses`. Default is `Hyphen`.
+
+ * `Hyphen` will format the fix-it as: ``// TODO: username - details``.
+ * `Parentheses` will format the fix-it as: ``// TODO(username): details``.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/google/readability-todo-hyphen.cpp b/clang-tools-extra/test/clang-tidy/checkers/google/readability-todo-hyphen.cpp
new file mode 100644
index 0000000000000..5701b30bef395
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/google/readability-todo-hyphen.cpp
@@ -0,0 +1,40 @@
+// RUN: %check_clang_tidy %s google-readability-todo %t -- -config="{User: 'some user'}" --
+
+// TODOfix this1
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
+// CHECK-FIXES: // TODO: some user - fix this1
+
+// TODO fix this2
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
+// CHECK-FIXES: // TODO: some user - fix this2
+
+// TODO fix this3
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
+// CHECK-FIXES: // TODO: some user - fix this3
+
+// TODO: fix this4
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
+// CHECK-FIXES: // TODO: some user - fix this4
+
+// TODO: bug 12345 -
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing details in TODO
+
+// TODO: a message without a reference
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
+// CHECK-FIXES: // TODO: some user - a message without a reference
+
+// TODO(clang)fix this5
+
+// TODO: foo - shave yaks
+// TODO:foo - no space bewteen semicolon and username
+// TODO: foo- no space bewteen username and dash
+// TODO: foo - extra spaces between semicolon and username
+// TODO: foo - extra spaces between username and dash
+// TODO: b/12345 - use a b/ prefix
+// TODO: bug 12345 - use a space in username/bug reference
+// TODO(foo):shave yaks
+// TODO(bar):
+// TODO(foo): paint bikeshed
+// TODO(b/12345): find the holy grail
+// TODO (b/12345): allow spaces before parentheses
+// TODO(asdf) allow missing semicolon
diff --git a/clang-tools-extra/test/clang-tidy/checkers/google/readability-todo.cpp b/clang-tools-extra/test/clang-tidy/checkers/google/readability-todo-parentheses.cpp
similarity index 54%
rename from clang-tools-extra/test/clang-tidy/checkers/google/readability-todo.cpp
rename to clang-tools-extra/test/clang-tidy/checkers/google/readability-todo-parentheses.cpp
index 6b900aa92150e..f97e395d8bf48 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/google/readability-todo.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/google/readability-todo-parentheses.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s google-readability-todo %t -- -config="{User: 'some user'}" --
+// RUN: %check_clang_tidy %s google-readability-todo %t -- -config="{User: 'some user', CheckOptions: {google-readability-todo.Style: 'Parentheses'}}" --
// TODOfix this1
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
@@ -16,8 +16,22 @@
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
// CHECK-FIXES: // TODO(some user): fix this4
+// TODO: bug 12345 -
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing details in TODO
+
+// TODO: a message without a reference
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
+// CHECK-FIXES: // TODO(some user): a message without a reference
+
// TODO(clang)fix this5
+// TODO: foo - shave yaks
+// TODO:foo - no space bewteen semicolon and username
+// TODO: foo- no space bewteen username and dash
+// TODO: foo - extra spaces between semicolon and username
+// TODO: foo - extra spaces between username and dash
+// TODO: b/12345 - use a b/ prefix
+// TODO: bug 12345 - use a space in username/bug reference
// TODO(foo):shave yaks
// TODO(bar):
// TODO(foo): paint bikeshed
More information about the cfe-commits
mailing list