[clang-tools-extra] [clang-tidy] Replace /* ... */ single-line comments with // ... comments (PR #124319)

via cfe-commits cfe-commits at lists.llvm.org
Sun Feb 2 08:16:08 PST 2025


================
@@ -0,0 +1,162 @@
+//===--- UseCppStyleCommentsCheck.cpp - clang-tidy-------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseCppStyleCommentsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include <sstream>
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+class UseCppStyleCommentsCheck::CStyleCommentHandler : public CommentHandler {
+public:
+  CStyleCommentHandler(UseCppStyleCommentsCheck &Check, bool ExcludeDoxygen)
+      : Check(Check), ExcludeDoxygen(ExcludeDoxygen),
+        CStyleCommentMatch(
+            "^[ \t]*/\\*+[ \t\r\n]*(.*[ \t\r\n]*)*[ \t\r\n]*\\*+/[ \t\r\n]*$") {
+  }
+
+  void setExcludeDoxygen(bool Exclude) { ExcludeDoxygen = Exclude; }
+
+  bool isExcludeDoxygen() const { return ExcludeDoxygen; }
+
+  std::string convertToCppStyleComment(const SourceManager &SM,
+                                       const SourceRange &Range) {
+    const StringRef CommentText = Lexer::getSourceText(
+        CharSourceRange::getTokenRange(Range), SM, LangOptions());
+
+    std::string InnerText = CommentText.str();
+    InnerText.erase(0, 2);
+    InnerText.erase(InnerText.size() - 2, 2);
+
+    std::string Result;
+    std::istringstream Stream(InnerText);
+    std::string Line;
+
+    if (std::getline(Stream, Line)) {
+      const size_t StartPos = Line.find_first_not_of(" \t");
+      if (StartPos != std::string::npos) {
+        Line = Line.substr(StartPos);
+      } else {
+        Line.clear();
+      }
+      Result += "// " + Line;
+    }
+
+    while (std::getline(Stream, Line)) {
+      const size_t StartPos = Line.find_first_not_of(" \t");
+      if (StartPos != std::string::npos) {
+        Line = Line.substr(StartPos);
+      } else {
+        Line.clear();
+      }
+      Result += "\n// " + Line;
+    }
+    return Result;
+  }
+
+  bool isDoxygenStyleComment(const StringRef &Text) {
+    StringRef Trimmed = Text.ltrim();
+    return Trimmed.starts_with("/**") || Trimmed.starts_with("/*!") ||
+           Trimmed.starts_with("///") || Trimmed.starts_with("//!") ||
+           (Trimmed.starts_with("/*") &&
+            Trimmed.drop_front(2).starts_with("*"));
+  }
+
+  bool CheckForInlineComments(Preprocessor &PP, SourceRange Range) {
+    const SourceManager &SM = PP.getSourceManager();
+    const SourceLocation CommentStart = Range.getBegin();
+    const SourceLocation CommentEnd = Range.getEnd();
+
+    unsigned StartLine = SM.getSpellingLineNumber(CommentStart);
+    unsigned EndLine = SM.getSpellingLineNumber(CommentEnd);
+
+    const StringRef Text = Lexer::getSourceText(
+        CharSourceRange::getCharRange(Range), SM, PP.getLangOpts());
+
+    if (StartLine == EndLine) {
+      const SourceLocation LineBegin =
+          SM.translateLineCol(SM.getFileID(CommentStart), StartLine, 1);
+      const SourceLocation LineEnd =
+          SM.translateLineCol(SM.getFileID(CommentEnd), EndLine,
+                              std::numeric_limits<unsigned>::max());
+      const StringRef LineContent = Lexer::getSourceText(
+          CharSourceRange::getCharRange(LineBegin, LineEnd), SM,
+          PP.getLangOpts());
+      const size_t CommentStartOffset =
+          SM.getSpellingColumnNumber(CommentStart) - 1;
+      const StringRef AfterComment =
+          LineContent.drop_front(CommentStartOffset + Text.size());
+
+      if (!AfterComment.trim().empty()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  bool HandleComment(Preprocessor &PP, SourceRange Range) override {
+    const SourceManager &SM = PP.getSourceManager();
+
+    if (Range.getBegin().isMacroID() || SM.isInSystemHeader(Range.getBegin())) {
+      return false;
+    }
+
+    const StringRef Text = Lexer::getSourceText(
+        CharSourceRange::getCharRange(Range), SM, PP.getLangOpts());
+
+    if (ExcludeDoxygen && isDoxygenStyleComment(Text)) {
+      return false;
+    }
+
+    SmallVector<StringRef> Matches;
+    if (!CStyleCommentMatch.match(Text, &Matches)) {
+      return false;
+    }
+
+    if (CheckForInlineComments(PP, Range)) {
+      return false;
+    }
+
+    Check.diag(
+        Range.getBegin(),
+        "use C++ style comments '//' instead of C style comments '/*...*/'")
+        << clang::FixItHint::CreateReplacement(
+               Range, convertToCppStyleComment(SM, Range));
+
+    return false;
+  }
+
+private:
+  UseCppStyleCommentsCheck &Check;
+  bool ExcludeDoxygen;
+  llvm::Regex CStyleCommentMatch;
+};
+
+UseCppStyleCommentsCheck::UseCppStyleCommentsCheck(StringRef Name,
+                                                   ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      Handler(std::make_unique<CStyleCommentHandler>(
+          *this, Options.get("ExcludeDoxygenStyleComments", false))) {}
+
+void UseCppStyleCommentsCheck::registerPPCallbacks(
+    const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
+  PP->addCommentHandler(Handler.get());
+}
+
+void UseCppStyleCommentsCheck::check(const MatchFinder::MatchResult &Result) {}
+
+void UseCppStyleCommentsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "ExcludeDoxygenStyleComments",
+                Handler->isExcludeDoxygen());
+}
+
+UseCppStyleCommentsCheck::~UseCppStyleCommentsCheck() = default;
+} // namespace clang::tidy::readability
----------------
4m4n-x-B4w4ne wrote:

Done Thanks.

https://github.com/llvm/llvm-project/pull/124319


More information about the cfe-commits mailing list