================
@@ -0,0 +1,178 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "TrailingCommaCheck.h"
+#include "../utils/LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy {
+
+template <>
+struct OptionEnumMapping<readability::TrailingCommaCheck::CommaPolicyKind> {
+  static llvm::ArrayRef<
+      std::pair<readability::TrailingCommaCheck::CommaPolicyKind, StringRef>>
+  getEnumMapping() {
+    static constexpr 
std::pair<readability::TrailingCommaCheck::CommaPolicyKind,
+                               StringRef>
+        Mapping[] = {
+            {readability::TrailingCommaCheck::CommaPolicyKind::Append,
+             "Append"},
+            {readability::TrailingCommaCheck::CommaPolicyKind::Remove,
+             "Remove"},
+            {readability::TrailingCommaCheck::CommaPolicyKind::Ignore,
+             "Ignore"},
+        };
+    return {Mapping};
+  }
+};
+
+} // namespace clang::tidy
+
+namespace clang::tidy::readability {
+
+static bool isSingleLine(SourceLocation Begin, SourceLocation End,
+                         const SourceManager &SM) {
+  return SM.getExpansionLineNumber(Begin) == SM.getExpansionLineNumber(End);
+}
+
+namespace {
+
+AST_POLYMORPHIC_MATCHER(isMacro,
+                        AST_POLYMORPHIC_SUPPORTED_TYPES(EnumDecl,
+                                                        InitListExpr)) {
+  return Node.getBeginLoc().isMacroID() || Node.getEndLoc().isMacroID();
+}
+
+AST_MATCHER(EnumDecl, isEmptyEnum) { return Node.enumerators().empty(); }
+
+AST_MATCHER(InitListExpr, isEmptyInitList) { return Node.getNumInits() == 0; }
+
+} // namespace
+
+TrailingCommaCheck::TrailingCommaCheck(StringRef Name,
+                                       ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      SingleLineCommaPolicy(
+          Options.get("SingleLineCommaPolicy", CommaPolicyKind::Remove)),
+      MultiLineCommaPolicy(
+          Options.get("MultiLineCommaPolicy", CommaPolicyKind::Append)) {}
+
+void TrailingCommaCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "SingleLineCommaPolicy", SingleLineCommaPolicy);
+  Options.store(Opts, "MultiLineCommaPolicy", MultiLineCommaPolicy);
+}
+
+void TrailingCommaCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      enumDecl(isDefinition(), unless(isEmptyEnum()), unless(isMacro()))
+          .bind("enum"),
+      this);
+
+  Finder->addMatcher(initListExpr(unless(isEmptyInitList()), unless(isMacro()))
+                         .bind("initlist"),
+                     this);
+}
+
+void TrailingCommaCheck::check(const MatchFinder::MatchResult &Result) {
+  if (const auto *Enum = Result.Nodes.getNodeAs<EnumDecl>("enum"))
+    checkEnumDecl(Enum, Result);
+  else if (const auto *InitList =
+               Result.Nodes.getNodeAs<InitListExpr>("initlist"))
+    checkInitListExpr(InitList, Result);
+  else
+    llvm_unreachable("No matches found");
+}
+
+void TrailingCommaCheck::checkEnumDecl(const EnumDecl *Enum,
+                                       const MatchFinder::MatchResult &Result) 
{
+  const bool IsSingleLine = isSingleLine(Enum->getBeginLoc(), 
Enum->getEndLoc(),
+                                         *Result.SourceManager);
+  const CommaPolicyKind Policy =
+      IsSingleLine ? SingleLineCommaPolicy : MultiLineCommaPolicy;
+
+  if (Policy == CommaPolicyKind::Ignore)
+    return;
+
+  const EnumConstantDecl *LastEnumerator = nullptr;
+  for (const EnumConstantDecl *ECD : Enum->enumerators())
+    LastEnumerator = ECD;
----------------
localspook wrote:

To elaborate, I'm proposing something like
```cpp
SourceLocation LastEnumLoc = 
lexer::utils::getPreviousToken(Enum->getBraceRange().getEnd()/*.getLocWithOffset(-1)?*/,
 *Result.SourceManager, getLangOpts()).getLocation();
```
I believe this gives the same result as the existing code, but without walking 
the enumerators, and without the extra logic to handle cases where the last 
enumerator has an initializer or an attribute.

https://github.com/llvm/llvm-project/pull/173669
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to