================ @@ -0,0 +1,171 @@ +//===----------------------------------------------------------------------===// +// +// 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)) { + if (SingleLineCommaPolicy == CommaPolicyKind::Ignore && + MultiLineCommaPolicy == CommaPolicyKind::Ignore) + configurationDiag("The check '%0' will not perform any analysis because " + "'SingleLineCommaPolicy' and 'MultiLineCommaPolicy' are " + "both set to 'Ignore'.") + << Name; +} + +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 std::optional<Token> LastTok = + Lexer::findPreviousToken(Enum->getBraceRange().getEnd(), + *Result.SourceManager, getLangOpts(), false); + + emitDiag(LastTok->getLocation(), LastTok, DiagKind::Enum, Result, Policy); +} + +void TrailingCommaCheck::checkInitListExpr( + const InitListExpr *InitList, const MatchFinder::MatchResult &Result) { + // We need to use non-empty syntactic form for correct source locations. + if (const InitListExpr *SynInitInitList = InitList->getSyntacticForm(); + SynInitInitList && SynInitInitList->getNumInits() > 0) + InitList = SynInitInitList; + + const bool IsSingleLine = isSingleLine( + InitList->getBeginLoc(), InitList->getEndLoc(), *Result.SourceManager); + const CommaPolicyKind Policy = + IsSingleLine ? SingleLineCommaPolicy : MultiLineCommaPolicy; + + if (Policy == CommaPolicyKind::Ignore) + return; + + const Expr *LastInit = LastInit = InitList->inits().back(); ---------------- zeyi2 wrote:
Seems like a duplicate assignment? ```suggestion const Expr *LastInit = InitList->inits().back(); ``` https://github.com/llvm/llvm-project/pull/173669 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
