[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-02-04 Thread Bhuminjay Soni via cfe-commits


@@ -0,0 +1,188 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+namespace {
+
+// Ignore if statements that are inside macros.
+AST_MATCHER(IfStmt, isIfInMacro) {
+  return Node.getIfLoc().isMacroID() || Node.getEndLoc().isMacroID();
+}
+
+} // namespace
+
+static const llvm::StringRef AlgorithmHeader("");
+
+static bool minCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  return false;
+}
+
+static bool maxCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  return false;
+}
+
+QualType getNonTemplateAlias(QualType QT) {
+  while (true) {
+// cast to a TypedefType
+if (const TypedefType *TT = dyn_cast(QT)) {
+  // check if the typedef is a template and if it is dependent
+  if (!TT->getDecl()->getDescribedTemplate() &&
+  !TT->getDecl()->getDeclContext()->isDependentContext())
+return QT;
+  QT = TT->getDecl()->getUnderlyingType();
+}
+// cast to elaborated type
+else if (const ElaboratedType *ET = dyn_cast(QT)) {
+  QT = ET->getNamedType();
+} else {
+  break;
+}
+  }
+  return QT;
+}
+
+static std::string createReplacement(const Expr *CondLhs, const Expr *CondRhs,
+ const Expr *AssignLhs,
+ const SourceManager ,
+ const LangOptions ,
+ StringRef FunctionName,
+ const BinaryOperator *BO) {
+  const llvm::StringRef CondLhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(CondLhs->getSourceRange()), Source, LO);
+  const llvm::StringRef CondRhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(CondRhs->getSourceRange()), Source, LO);
+  const llvm::StringRef AssignLhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(AssignLhs->getSourceRange()), Source, LO);
+
+  clang::QualType GlobalImplicitCastType;
+  clang::QualType LhsType = CondLhs->getType()
+.getCanonicalType()
+.getNonReferenceType()
+.getUnqualifiedType();
+  clang::QualType RhsType = CondRhs->getType()
+.getCanonicalType()
+.getNonReferenceType()
+.getUnqualifiedType();
+  if (LhsType != RhsType) {
+GlobalImplicitCastType = getNonTemplateAlias(BO->getLHS()->getType());
+  }
+
+  return (AssignLhsStr + " = " + FunctionName +
+  (!GlobalImplicitCastType.isNull()
+   ? "<" + GlobalImplicitCastType.getAsString() + ">("
+   : "(") +
+  CondLhsStr + ", " + CondRhsStr + ");")
+  .str();
+}
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+}
+
+void UseStdMinMaxCheck::registerMatchers(MatchFinder *Finder) {
+  auto 

[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-02-04 Thread Bhuminjay Soni via cfe-commits


@@ -0,0 +1,188 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+namespace {
+
+// Ignore if statements that are inside macros.
+AST_MATCHER(IfStmt, isIfInMacro) {
+  return Node.getIfLoc().isMacroID() || Node.getEndLoc().isMacroID();
+}
+
+} // namespace
+
+static const llvm::StringRef AlgorithmHeader("");
+
+static bool minCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  return false;
+}
+
+static bool maxCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  return false;
+}
+
+QualType getNonTemplateAlias(QualType QT) {
+  while (true) {
+// cast to a TypedefType
+if (const TypedefType *TT = dyn_cast(QT)) {
+  // check if the typedef is a template and if it is dependent
+  if (!TT->getDecl()->getDescribedTemplate() &&
+  !TT->getDecl()->getDeclContext()->isDependentContext())
+return QT;
+  QT = TT->getDecl()->getUnderlyingType();
+}
+// cast to elaborated type
+else if (const ElaboratedType *ET = dyn_cast(QT)) {
+  QT = ET->getNamedType();
+} else {
+  break;
+}
+  }
+  return QT;
+}
+
+static std::string createReplacement(const Expr *CondLhs, const Expr *CondRhs,
+ const Expr *AssignLhs,
+ const SourceManager ,
+ const LangOptions ,
+ StringRef FunctionName,
+ const BinaryOperator *BO) {
+  const llvm::StringRef CondLhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(CondLhs->getSourceRange()), Source, LO);
+  const llvm::StringRef CondRhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(CondRhs->getSourceRange()), Source, LO);
+  const llvm::StringRef AssignLhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(AssignLhs->getSourceRange()), Source, LO);
+
+  clang::QualType GlobalImplicitCastType;
+  clang::QualType LhsType = CondLhs->getType()
+.getCanonicalType()
+.getNonReferenceType()
+.getUnqualifiedType();
+  clang::QualType RhsType = CondRhs->getType()
+.getCanonicalType()
+.getNonReferenceType()
+.getUnqualifiedType();
+  if (LhsType != RhsType) {
+GlobalImplicitCastType = getNonTemplateAlias(BO->getLHS()->getType());
+  }
+
+  return (AssignLhsStr + " = " + FunctionName +
+  (!GlobalImplicitCastType.isNull()
+   ? "<" + GlobalImplicitCastType.getAsString() + ">("
+   : "(") +
+  CondLhsStr + ", " + CondRhsStr + ");")
+  .str();
+}
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+}
+
+void UseStdMinMaxCheck::registerMatchers(MatchFinder *Finder) {
+  auto 

[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-02-04 Thread via cfe-commits


@@ -0,0 +1,41 @@
+//===--- UseStdMinMaxCheck.h - clang-tidy ---*- C++ 
-*-===//
+//
+// 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
+//
+//===--===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_USESTDMINMAXCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_USESTDMINMAXCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "../utils/IncludeInserter.h"
+namespace clang::tidy::readability {

EugeneZelenko wrote:

Please separate with newline.

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-02-04 Thread Julian Schmidt via cfe-commits


@@ -0,0 +1,188 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+namespace {
+
+// Ignore if statements that are inside macros.
+AST_MATCHER(IfStmt, isIfInMacro) {
+  return Node.getIfLoc().isMacroID() || Node.getEndLoc().isMacroID();
+}
+
+} // namespace
+
+static const llvm::StringRef AlgorithmHeader("");
+
+static bool minCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  return false;
+}
+
+static bool maxCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  return false;
+}
+
+QualType getNonTemplateAlias(QualType QT) {
+  while (true) {
+// cast to a TypedefType
+if (const TypedefType *TT = dyn_cast(QT)) {
+  // check if the typedef is a template and if it is dependent
+  if (!TT->getDecl()->getDescribedTemplate() &&
+  !TT->getDecl()->getDeclContext()->isDependentContext())
+return QT;
+  QT = TT->getDecl()->getUnderlyingType();
+}
+// cast to elaborated type
+else if (const ElaboratedType *ET = dyn_cast(QT)) {
+  QT = ET->getNamedType();
+} else {
+  break;
+}
+  }
+  return QT;
+}
+
+static std::string createReplacement(const Expr *CondLhs, const Expr *CondRhs,
+ const Expr *AssignLhs,
+ const SourceManager ,
+ const LangOptions ,
+ StringRef FunctionName,
+ const BinaryOperator *BO) {
+  const llvm::StringRef CondLhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(CondLhs->getSourceRange()), Source, LO);
+  const llvm::StringRef CondRhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(CondRhs->getSourceRange()), Source, LO);
+  const llvm::StringRef AssignLhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(AssignLhs->getSourceRange()), Source, LO);
+
+  clang::QualType GlobalImplicitCastType;
+  clang::QualType LhsType = CondLhs->getType()
+.getCanonicalType()
+.getNonReferenceType()
+.getUnqualifiedType();
+  clang::QualType RhsType = CondRhs->getType()
+.getCanonicalType()
+.getNonReferenceType()
+.getUnqualifiedType();
+  if (LhsType != RhsType) {
+GlobalImplicitCastType = getNonTemplateAlias(BO->getLHS()->getType());
+  }
+
+  return (AssignLhsStr + " = " + FunctionName +
+  (!GlobalImplicitCastType.isNull()
+   ? "<" + GlobalImplicitCastType.getAsString() + ">("
+   : "(") +
+  CondLhsStr + ", " + CondRhsStr + ");")
+  .str();
+}
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+}
+
+void UseStdMinMaxCheck::registerMatchers(MatchFinder *Finder) {
+  auto 

[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-02-04 Thread Bhuminjay Soni via cfe-commits


@@ -0,0 +1,188 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+namespace {
+
+// Ignore if statements that are inside macros.
+AST_MATCHER(IfStmt, isIfInMacro) {
+  return Node.getIfLoc().isMacroID() || Node.getEndLoc().isMacroID();
+}
+
+} // namespace
+
+static const llvm::StringRef AlgorithmHeader("");
+
+static bool minCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  return false;
+}
+
+static bool maxCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  return false;
+}
+
+QualType getNonTemplateAlias(QualType QT) {
+  while (true) {
+// cast to a TypedefType
+if (const TypedefType *TT = dyn_cast(QT)) {
+  // check if the typedef is a template and if it is dependent
+  if (!TT->getDecl()->getDescribedTemplate() &&
+  !TT->getDecl()->getDeclContext()->isDependentContext())
+return QT;
+  QT = TT->getDecl()->getUnderlyingType();
+}
+// cast to elaborated type
+else if (const ElaboratedType *ET = dyn_cast(QT)) {
+  QT = ET->getNamedType();
+} else {
+  break;
+}
+  }
+  return QT;
+}
+
+static std::string createReplacement(const Expr *CondLhs, const Expr *CondRhs,
+ const Expr *AssignLhs,
+ const SourceManager ,
+ const LangOptions ,
+ StringRef FunctionName,
+ const BinaryOperator *BO) {
+  const llvm::StringRef CondLhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(CondLhs->getSourceRange()), Source, LO);
+  const llvm::StringRef CondRhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(CondRhs->getSourceRange()), Source, LO);
+  const llvm::StringRef AssignLhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(AssignLhs->getSourceRange()), Source, LO);
+
+  clang::QualType GlobalImplicitCastType;
+  clang::QualType LhsType = CondLhs->getType()
+.getCanonicalType()
+.getNonReferenceType()
+.getUnqualifiedType();
+  clang::QualType RhsType = CondRhs->getType()
+.getCanonicalType()
+.getNonReferenceType()
+.getUnqualifiedType();
+  if (LhsType != RhsType) {
+GlobalImplicitCastType = getNonTemplateAlias(BO->getLHS()->getType());
+  }
+
+  return (AssignLhsStr + " = " + FunctionName +
+  (!GlobalImplicitCastType.isNull()
+   ? "<" + GlobalImplicitCastType.getAsString() + ">("
+   : "(") +
+  CondLhsStr + ", " + CondRhsStr + ");")
+  .str();
+}
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+}
+
+void UseStdMinMaxCheck::registerMatchers(MatchFinder *Finder) {
+  auto 

[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-02-04 Thread Piotr Zegar via cfe-commits

https://github.com/PiotrZSL approved this pull request.

LGTM.
The only thing that I'm still thinking is if std is needed in name, and maybe 
it should be like just use-min-max.

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-28 Thread Piotr Zegar via cfe-commits


@@ -0,0 +1,168 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+static const llvm::StringRef AlgorithmHeader("");
+
+static bool minCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  return false;
+}
+
+static bool maxCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  return false;
+}
+
+static std::string createReplacement(const Expr *CondLhs, const Expr *CondRhs,
+ const Expr *AssignLhs,
+ const SourceManager ,
+ const LangOptions ,
+ StringRef FunctionName,
+ const BinaryOperator *BO) {
+  const llvm::StringRef CondLhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(CondLhs->getSourceRange()), Source, LO);
+  const llvm::StringRef CondRhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(CondRhs->getSourceRange()), Source, LO);
+  const llvm::StringRef AssignLhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(AssignLhs->getSourceRange()), Source, LO);
+
+  clang::QualType GlobalImplicitCastType;
+  if (CondLhs->getType()
+  .getCanonicalType()
+  .getNonReferenceType()
+  .getUnqualifiedType() != CondRhs->getType()
+   .getCanonicalType()
+   .getNonReferenceType()
+   .getUnqualifiedType()) {

PiotrZSL wrote:

assign those 2 binary operator types to local variables, to make this shorter.

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-28 Thread Piotr Zegar via cfe-commits


@@ -0,0 +1,230 @@
+// RUN: %check_clang_tidy %s readability-use-std-min-max %t

PiotrZSL wrote:

Add `-- -- -fno-delayed-template-parsing` this is why windows tests is falling.
Additionally explicitly set c++ standard with `-std=c++11-or-later` like in 
other checks

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-28 Thread Piotr Zegar via cfe-commits


@@ -0,0 +1,240 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+static bool isImplicitCastType(const clang::CastKind castKind) {
+  switch (castKind) {
+  case clang::CK_CPointerToObjCPointerCast:
+  case clang::CK_BlockPointerToObjCPointerCast:
+  case clang::CK_BitCast:
+  case clang::CK_AnyPointerToBlockPointerCast:
+  case clang::CK_NullToMemberPointer:
+  case clang::CK_NullToPointer:
+  case clang::CK_IntegralToPointer:
+  case clang::CK_PointerToIntegral:
+  case clang::CK_IntegralCast:
+  case clang::CK_BooleanToSignedIntegral:
+  case clang::CK_IntegralToFloating:
+  case clang::CK_FloatingToIntegral:
+  case clang::CK_FloatingCast:
+  case clang::CK_ObjCObjectLValueCast:
+  case clang::CK_FloatingRealToComplex:
+  case clang::CK_FloatingComplexToReal:
+  case clang::CK_FloatingComplexCast:
+  case clang::CK_FloatingComplexToIntegralComplex:
+  case clang::CK_IntegralRealToComplex:
+  case clang::CK_IntegralComplexToReal:
+  case clang::CK_IntegralComplexCast:
+  case clang::CK_IntegralComplexToFloatingComplex:
+  case clang::CK_FloatingToFixedPoint:
+  case clang::CK_FixedPointToFloating:
+  case clang::CK_FixedPointCast:
+  case clang::CK_FixedPointToIntegral:
+  case clang::CK_IntegralToFixedPoint:
+  case clang::CK_MatrixCast:
+  case clang::CK_PointerToBoolean:
+  case clang::CK_IntegralToBoolean:
+  case clang::CK_FloatingToBoolean:
+  case clang::CK_MemberPointerToBoolean:
+  case clang::CK_FloatingComplexToBoolean:
+  case clang::CK_IntegralComplexToBoolean:
+  case clang::CK_UserDefinedConversion:
+return true;
+  default:
+return false;
+  }
+}
+
+class ExprVisitor : public clang::RecursiveASTVisitor {
+public:
+  bool visitStmt(const clang::Stmt *S, bool ,
+ clang::QualType ) {
+
+if (isa(S) && !found) {
+  const auto CastKind = cast(S)->getCastKind();
+  if (isImplicitCastType(CastKind)) {
+found = true;
+const clang::ImplicitCastExpr *ImplicitCast =
+cast(S);
+GlobalImplicitCastType = ImplicitCast->getType();
+// Stop visiting children.
+return false;
+  }
+}
+// Continue visiting children.
+for (const clang::Stmt *Child : S->children()) {
+  if (Child) {
+this->visitStmt(Child, found, GlobalImplicitCastType);
+  }
+}
+
+return true; // Continue visiting other nodes.
+  }
+};
+
+static const llvm::StringRef AlgorithmHeader("");
+
+static bool minCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  return false;
+}
+
+static bool maxCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  return false;
+}
+
+static std::string createReplacement(const BinaryOperator::Opcode Op,
+ const Expr *CondLhs, const Expr *CondRhs,
+ const Expr *AssignLhs,
+ const SourceManager ,
+ const LangOptions ,
+ StringRef FunctionName, const IfStmt *If) 
{
+  const llvm::StringRef CondLhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(CondLhs->getSourceRange()), Source, LO);
+  const llvm::StringRef CondRhsStr = 

[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-28 Thread Piotr Zegar via cfe-commits


@@ -0,0 +1,240 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+static bool isImplicitCastType(const clang::CastKind castKind) {
+  switch (castKind) {
+  case clang::CK_CPointerToObjCPointerCast:
+  case clang::CK_BlockPointerToObjCPointerCast:
+  case clang::CK_BitCast:
+  case clang::CK_AnyPointerToBlockPointerCast:
+  case clang::CK_NullToMemberPointer:
+  case clang::CK_NullToPointer:
+  case clang::CK_IntegralToPointer:
+  case clang::CK_PointerToIntegral:
+  case clang::CK_IntegralCast:
+  case clang::CK_BooleanToSignedIntegral:
+  case clang::CK_IntegralToFloating:
+  case clang::CK_FloatingToIntegral:
+  case clang::CK_FloatingCast:
+  case clang::CK_ObjCObjectLValueCast:
+  case clang::CK_FloatingRealToComplex:
+  case clang::CK_FloatingComplexToReal:
+  case clang::CK_FloatingComplexCast:
+  case clang::CK_FloatingComplexToIntegralComplex:
+  case clang::CK_IntegralRealToComplex:
+  case clang::CK_IntegralComplexToReal:
+  case clang::CK_IntegralComplexCast:
+  case clang::CK_IntegralComplexToFloatingComplex:
+  case clang::CK_FloatingToFixedPoint:
+  case clang::CK_FixedPointToFloating:
+  case clang::CK_FixedPointCast:
+  case clang::CK_FixedPointToIntegral:
+  case clang::CK_IntegralToFixedPoint:
+  case clang::CK_MatrixCast:
+  case clang::CK_PointerToBoolean:
+  case clang::CK_IntegralToBoolean:
+  case clang::CK_FloatingToBoolean:
+  case clang::CK_MemberPointerToBoolean:
+  case clang::CK_FloatingComplexToBoolean:
+  case clang::CK_IntegralComplexToBoolean:
+  case clang::CK_UserDefinedConversion:
+return true;
+  default:
+return false;
+  }
+}
+
+class ExprVisitor : public clang::RecursiveASTVisitor {
+public:
+  bool visitStmt(const clang::Stmt *S, bool ,
+ clang::QualType ) {
+
+if (isa(S) && !found) {
+  const auto CastKind = cast(S)->getCastKind();
+  if (isImplicitCastType(CastKind)) {
+found = true;
+const clang::ImplicitCastExpr *ImplicitCast =
+cast(S);
+GlobalImplicitCastType = ImplicitCast->getType();
+// Stop visiting children.
+return false;
+  }
+}
+// Continue visiting children.
+for (const clang::Stmt *Child : S->children()) {
+  if (Child) {
+this->visitStmt(Child, found, GlobalImplicitCastType);
+  }
+}
+
+return true; // Continue visiting other nodes.
+  }
+};
+
+static const llvm::StringRef AlgorithmHeader("");
+
+static bool minCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  return false;
+}
+
+static bool maxCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  return false;
+}
+
+static std::string createReplacement(const BinaryOperator::Opcode Op,
+ const Expr *CondLhs, const Expr *CondRhs,
+ const Expr *AssignLhs,
+ const SourceManager ,
+ const LangOptions ,
+ StringRef FunctionName, const IfStmt *If) 
{
+  const llvm::StringRef CondLhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(CondLhs->getSourceRange()), Source, LO);
+  const llvm::StringRef CondRhsStr = 

[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-28 Thread Piotr Zegar via cfe-commits


@@ -0,0 +1,240 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+static bool isImplicitCastType(const clang::CastKind castKind) {
+  switch (castKind) {
+  case clang::CK_CPointerToObjCPointerCast:
+  case clang::CK_BlockPointerToObjCPointerCast:
+  case clang::CK_BitCast:
+  case clang::CK_AnyPointerToBlockPointerCast:
+  case clang::CK_NullToMemberPointer:
+  case clang::CK_NullToPointer:
+  case clang::CK_IntegralToPointer:
+  case clang::CK_PointerToIntegral:
+  case clang::CK_IntegralCast:
+  case clang::CK_BooleanToSignedIntegral:
+  case clang::CK_IntegralToFloating:
+  case clang::CK_FloatingToIntegral:
+  case clang::CK_FloatingCast:
+  case clang::CK_ObjCObjectLValueCast:
+  case clang::CK_FloatingRealToComplex:
+  case clang::CK_FloatingComplexToReal:
+  case clang::CK_FloatingComplexCast:
+  case clang::CK_FloatingComplexToIntegralComplex:
+  case clang::CK_IntegralRealToComplex:
+  case clang::CK_IntegralComplexToReal:
+  case clang::CK_IntegralComplexCast:
+  case clang::CK_IntegralComplexToFloatingComplex:
+  case clang::CK_FloatingToFixedPoint:
+  case clang::CK_FixedPointToFloating:
+  case clang::CK_FixedPointCast:
+  case clang::CK_FixedPointToIntegral:
+  case clang::CK_IntegralToFixedPoint:
+  case clang::CK_MatrixCast:
+  case clang::CK_PointerToBoolean:
+  case clang::CK_IntegralToBoolean:
+  case clang::CK_FloatingToBoolean:
+  case clang::CK_MemberPointerToBoolean:
+  case clang::CK_FloatingComplexToBoolean:
+  case clang::CK_IntegralComplexToBoolean:
+  case clang::CK_UserDefinedConversion:
+return true;
+  default:
+return false;
+  }
+}
+
+class ExprVisitor : public clang::RecursiveASTVisitor {

PiotrZSL wrote:

This is overengineered and not needed.
There are easier ways to read implicit cast types.

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-28 Thread Piotr Zegar via cfe-commits


@@ -0,0 +1,230 @@
+// RUN: %check_clang_tidy %s readability-use-std-min-max %t
+#define MY_MACRO_MIN(a, b) ((a) < (b) ? (a) : (b))
+
+constexpr int myConstexprMin(int a, int b) {
+  return a < b ? a : b;
+}
+
+constexpr int myConstexprMax(int a, int b) {
+  return a > b ? a : b;
+}
+
+#define MY_IF_MACRO(condition, statement) \
+  if (condition) {\
+statement \
+  }
+
+class MyClass {
+public:
+  int member1;
+  int member2;
+};
+
+template
+
+void foo(T value7) {
+  int value1,value2,value3;
+  short value4;
+  unsigned int value5;
+  unsigned char value6;
+  const int value8 = 5;
+  volatile int value9 = 6;
+  MyClass obj;
+

PiotrZSL wrote:

This isn't C, put variables closer to usage...

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-28 Thread Piotr Zegar via cfe-commits

https://github.com/PiotrZSL requested changes to this pull request.

Too overengineered. There are easier ways, just check comments.
Except that, looks +- fine.

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-27 Thread Félix-Antoine Constantin via cfe-commits


@@ -0,0 +1,238 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+static bool isImplicitCastType(const clang::CastKind castKind) {
+  switch (castKind) {
+  case clang::CK_CPointerToObjCPointerCast:
+  case clang::CK_BlockPointerToObjCPointerCast:
+  case clang::CK_BitCast:
+  case clang::CK_AnyPointerToBlockPointerCast:
+  case clang::CK_NullToMemberPointer:
+  case clang::CK_NullToPointer:
+  case clang::CK_IntegralToPointer:
+  case clang::CK_PointerToIntegral:
+  case clang::CK_IntegralCast:
+  case clang::CK_BooleanToSignedIntegral:
+  case clang::CK_IntegralToFloating:
+  case clang::CK_FloatingToIntegral:
+  case clang::CK_FloatingCast:
+  case clang::CK_ObjCObjectLValueCast:
+  case clang::CK_FloatingRealToComplex:
+  case clang::CK_FloatingComplexToReal:
+  case clang::CK_FloatingComplexCast:
+  case clang::CK_FloatingComplexToIntegralComplex:
+  case clang::CK_IntegralRealToComplex:
+  case clang::CK_IntegralComplexToReal:
+  case clang::CK_IntegralComplexCast:
+  case clang::CK_IntegralComplexToFloatingComplex:
+  case clang::CK_FloatingToFixedPoint:
+  case clang::CK_FixedPointToFloating:
+  case clang::CK_FixedPointCast:
+  case clang::CK_FixedPointToIntegral:
+  case clang::CK_IntegralToFixedPoint:
+  case clang::CK_MatrixCast:
+  case clang::CK_PointerToBoolean:
+  case clang::CK_IntegralToBoolean:
+  case clang::CK_FloatingToBoolean:
+  case clang::CK_MemberPointerToBoolean:
+  case clang::CK_FloatingComplexToBoolean:
+  case clang::CK_IntegralComplexToBoolean:
+return true;
+  default:
+return false;
+  }
+}
+
+class ExprVisitor : public clang::RecursiveASTVisitor {
+public:
+  explicit ExprVisitor(clang::ASTContext *Context) : Context(Context) {}
+  bool visitStmt(const clang::Stmt *S, bool ,
+ clang::QualType ) {
+
+if (isa(S) && !found) {
+  const auto CastKind = cast(S)->getCastKind();
+  if (isImplicitCastType(CastKind)) {
+found = true;
+const clang::ImplicitCastExpr *ImplicitCast =
+cast(S);
+GlobalImplicitCastType = ImplicitCast->getType();
+// Stop visiting children.
+return false;
+  }
+}
+// Continue visiting children.
+for (const clang::Stmt *Child : S->children()) {
+  if (Child) {
+this->visitStmt(Child, found, GlobalImplicitCastType);
+  }
+}
+
+return true; // Continue visiting other nodes.
+  }
+
+private:
+  clang::ASTContext *Context;
+};
+
+static const llvm::StringRef AlgorithmHeader("");
+
+static bool minCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  return false;
+}
+
+static bool maxCondition(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+ const Expr *CondRhs, const Expr *AssignLhs,
+ const Expr *AssignRhs, const ASTContext ) {
+  if ((Op == BO_LT || Op == BO_LE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context)))
+return true;
+
+  if ((Op == BO_GT || Op == BO_GE) &&
+  (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+   tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context)))
+return true;
+
+  return false;
+}
+
+static std::string
+createReplacement(const BinaryOperator::Opcode Op, const Expr *CondLhs,
+  const Expr *CondRhs, const Expr *AssignLhs,
+  const ASTContext , const SourceManager ,
+  const LangOptions , StringRef FunctionName,
+  QualType GlobalImplicitCastType) {
+  const llvm::StringRef CondLhsStr = Lexer::getSourceText(
+  Source.getExpansionRange(CondLhs->getSourceRange()), Source, LO);
+  const llvm::StringRef CondRhsStr = 

[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-26 Thread Bhuminjay Soni via cfe-commits

11happy wrote:

why the test maybe failing on windows build?

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-26 Thread Bhuminjay Soni via cfe-commits


@@ -0,0 +1,195 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+#include 

11happy wrote:

done

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-26 Thread Félix-Antoine Constantin via cfe-commits


@@ -0,0 +1,195 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+#include 

felix642 wrote:

Also, do not include iostream

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-26 Thread Félix-Antoine Constantin via cfe-commits

https://github.com/felix642 requested changes to this pull request.


https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-26 Thread Bhuminjay Soni via cfe-commits


@@ -0,0 +1,189 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+#include 
+using namespace std;
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+class ExprVisitor : public clang::RecursiveASTVisitor {
+public:
+  explicit ExprVisitor(clang::ASTContext *Context) : Context(Context) {}
+  bool visitStmt(const clang::Stmt *S, bool ,
+ clang::QualType ) {
+
+if (isa(S) && !found) {
+  found = true;
+  const clang::ImplicitCastExpr *ImplicitCast =
+  cast(S);
+  GlobalImplicitCastType = ImplicitCast->getType();
+  // Stop visiting children.
+  return false;
+}
+// Continue visiting children.
+for (const clang::Stmt *Child : S->children()) {
+  if (Child) {
+this->visitStmt(Child, found, GlobalImplicitCastType);
+  }
+}
+
+return true; // Continue visiting other nodes.
+  }
+
+private:
+  clang::ASTContext *Context;

11happy wrote:

Not able to remove it , actually its been used, sorry If I misunderstood 
anything can you please explain it.

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-23 Thread Félix-Antoine Constantin via cfe-commits

https://github.com/felix642 edited 
https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-23 Thread Bhuminjay Soni via cfe-commits

11happy wrote:

@felix642, I am not able to reproduce this error on my end. Could you please 
provide steps to reproduce it? Your guidance is highly appreciated. the piece 
of code you mentioned seems to be causing no error when put with current tests.
thank you

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-22 Thread Piotr Zegar via cfe-commits

https://github.com/PiotrZSL edited 
https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-22 Thread Piotr Zegar via cfe-commits


@@ -0,0 +1,29 @@
+.. title:: clang-tidy - readability-use-std-min-max
+
+readability-use-std-min-max
+===
+
+Replaces certain conditional statements with equivalent ``std::min`` or
+``std::max`` expressions. Note: This may impact

PiotrZSL wrote:

put that note to separate line.

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-22 Thread Piotr Zegar via cfe-commits


@@ -0,0 +1,137 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+static const llvm::StringRef AlgorithmHeader("");
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+}
+
+void UseStdMinMaxCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  ifStmt(
+  stmt().bind("if"),
+  hasCondition(binaryOperator(hasAnyOperatorName("<", ">", "<=", ">="),
+  hasLHS(expr().bind("CondLhs")),
+  hasRHS(expr().bind("CondRhs",
+  hasThen(anyOf(stmt(binaryOperator(hasOperatorName("="),
+hasLHS(expr().bind("AssignLhs")),
+hasRHS(expr().bind("AssignRhs",
+compoundStmt(statementCountIs(1),
+ has(binaryOperator(
+ hasOperatorName("="),
+ hasLHS(expr().bind("AssignLhs")),
+ hasRHS(expr().bind("AssignRhs"))),
+  hasParent(stmt(unless(ifStmt(hasElse(
+  equalsBoundNode("if"))), // Ensure `if` has no `else if`
+  this);
+}
+
+void UseStdMinMaxCheck::registerPPCallbacks(const SourceManager ,
+Preprocessor *PP,
+Preprocessor *ModuleExpanderPP) {
+  IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseStdMinMaxCheck::check(const MatchFinder::MatchResult ) {
+  const auto *CondLhs = Result.Nodes.getNodeAs("CondLhs");
+  const auto *CondRhs = Result.Nodes.getNodeAs("CondRhs");
+  const auto *AssignLhs = Result.Nodes.getNodeAs("AssignLhs");
+  const auto *AssignRhs = Result.Nodes.getNodeAs("AssignRhs");
+  const auto *If = Result.Nodes.getNodeAs("if");
+  const auto  = *Result.Context;
+  const auto  = Context.getLangOpts();
+  const SourceManager  = Context.getSourceManager();
+
+  const auto *BinaryOp = dyn_cast(If->getCond());
+  // Ignore `if` statements with `else`
+  if (If->hasElseStorage())
+return;
+
+  const SourceLocation IfLocation = If->getIfLoc();
+  const SourceLocation ThenLocation = If->getEndLoc();
+
+  // Ignore Macros
+  if (IfLocation.isMacroID() || ThenLocation.isMacroID())
+return;
+
+  const auto CreateReplacement = [&](bool UseMax) {
+const auto *FunctionName = UseMax ? "std::max" : "std::min";
+const auto CondLhsStr = Lexer::getSourceText(
+Source.getExpansionRange(CondLhs->getSourceRange()), Source, LO);
+const auto CondRhsStr = Lexer::getSourceText(
+Source.getExpansionRange(CondRhs->getSourceRange()), Source, LO);
+const auto AssignLhsStr = Lexer::getSourceText(
+Source.getExpansionRange(AssignLhs->getSourceRange()), Source, LO);
+if (CondLhs->getType() != CondRhs->getType()) {

PiotrZSL wrote:

single statement if/else does not need {}

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-22 Thread Piotr Zegar via cfe-commits


@@ -0,0 +1,137 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+static const llvm::StringRef AlgorithmHeader("");
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+}
+
+void UseStdMinMaxCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  ifStmt(
+  stmt().bind("if"),
+  hasCondition(binaryOperator(hasAnyOperatorName("<", ">", "<=", ">="),
+  hasLHS(expr().bind("CondLhs")),
+  hasRHS(expr().bind("CondRhs",
+  hasThen(anyOf(stmt(binaryOperator(hasOperatorName("="),
+hasLHS(expr().bind("AssignLhs")),
+hasRHS(expr().bind("AssignRhs",
+compoundStmt(statementCountIs(1),
+ has(binaryOperator(
+ hasOperatorName("="),
+ hasLHS(expr().bind("AssignLhs")),
+ hasRHS(expr().bind("AssignRhs"))),
+  hasParent(stmt(unless(ifStmt(hasElse(
+  equalsBoundNode("if"))), // Ensure `if` has no `else if`
+  this);
+}
+
+void UseStdMinMaxCheck::registerPPCallbacks(const SourceManager ,
+Preprocessor *PP,
+Preprocessor *ModuleExpanderPP) {
+  IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseStdMinMaxCheck::check(const MatchFinder::MatchResult ) {
+  const auto *CondLhs = Result.Nodes.getNodeAs("CondLhs");
+  const auto *CondRhs = Result.Nodes.getNodeAs("CondRhs");
+  const auto *AssignLhs = Result.Nodes.getNodeAs("AssignLhs");
+  const auto *AssignRhs = Result.Nodes.getNodeAs("AssignRhs");
+  const auto *If = Result.Nodes.getNodeAs("if");
+  const auto  = *Result.Context;
+  const auto  = Context.getLangOpts();
+  const SourceManager  = Context.getSourceManager();
+
+  const auto *BinaryOp = dyn_cast(If->getCond());
+  // Ignore `if` statements with `else`
+  if (If->hasElseStorage())
+return;
+
+  const SourceLocation IfLocation = If->getIfLoc();
+  const SourceLocation ThenLocation = If->getEndLoc();
+
+  // Ignore Macros
+  if (IfLocation.isMacroID() || ThenLocation.isMacroID())
+return;
+
+  const auto CreateReplacement = [&](bool UseMax) {
+const auto *FunctionName = UseMax ? "std::max" : "std::min";
+const auto CondLhsStr = Lexer::getSourceText(
+Source.getExpansionRange(CondLhs->getSourceRange()), Source, LO);
+const auto CondRhsStr = Lexer::getSourceText(
+Source.getExpansionRange(CondRhs->getSourceRange()), Source, LO);
+const auto AssignLhsStr = Lexer::getSourceText(
+Source.getExpansionRange(AssignLhs->getSourceRange()), Source, LO);
+if (CondLhs->getType() != CondRhs->getType()) {
+  return (AssignLhsStr + " = " + FunctionName + "<" +
+  AssignLhs->getType().getAsString() + ">(" + CondLhsStr + ", " +
+  CondRhsStr + ");")
+  .str();
+} else {
+  return (AssignLhsStr + " = " + FunctionName + "(" + CondLhsStr + ", " +
+  CondRhsStr + ");")
+  .str();

PiotrZSL wrote:

Note: There is some code duplicate between those 2 returns.

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-20 Thread Julian Schmidt via cfe-commits

https://github.com/5chmidti edited 
https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-20 Thread Julian Schmidt via cfe-commits


@@ -0,0 +1,129 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+#include 

5chmidti wrote:

Unused include ``

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-20 Thread Félix-Antoine Constantin via cfe-commits


@@ -0,0 +1,135 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+static const llvm::StringRef AlgorithmHeader("");
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+}
+
+void UseStdMinMaxCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  ifStmt(
+  hasCondition(binaryOperator(hasAnyOperatorName("<", ">", "<=", ">="),
+  hasLHS(expr().bind("CondLhs")),
+  hasRHS(expr().bind("CondRhs",
+  hasThen(anyOf(stmt(binaryOperator(hasOperatorName("="),
+hasLHS(expr().bind("AssignLhs")),
+hasRHS(expr().bind("AssignRhs",
+compoundStmt(has(binaryOperator(
+ hasOperatorName("="),
+ hasLHS(expr().bind("AssignLhs")),
+ hasRHS(expr().bind("AssignRhs")
+.bind("compound"
+  .bind("if"),
+  this);
+}
+
+void UseStdMinMaxCheck::registerPPCallbacks(const SourceManager ,
+Preprocessor *PP,
+Preprocessor *ModuleExpanderPP) {
+  IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseStdMinMaxCheck::check(const MatchFinder::MatchResult ) {
+  const auto *CondLhs = Result.Nodes.getNodeAs("CondLhs");
+  const auto *CondRhs = Result.Nodes.getNodeAs("CondRhs");
+  const auto *AssignLhs = Result.Nodes.getNodeAs("AssignLhs");
+  const auto *AssignRhs = Result.Nodes.getNodeAs("AssignRhs");
+  const auto *If = Result.Nodes.getNodeAs("if");
+  const auto *Compound = Result.Nodes.getNodeAs("compound");
+  const auto  = *Result.Context;
+  const auto  = Context.getLangOpts();
+  const SourceManager  = Context.getSourceManager();
+
+  const auto *BinaryOp = dyn_cast(If->getCond());
+  if (!BinaryOp || If->hasElseStorage())
+return;
+
+  if (Compound) {
+if (Compound->size() > 1)
+  return;
+  }
+
+  const SourceLocation IfLocation = If->getIfLoc();
+  const SourceLocation ThenLocation = If->getEndLoc();
+
+  if (IfLocation.isMacroID() || ThenLocation.isMacroID())
+return;
+
+  const auto CreateReplacement = [&](bool UseMax) {
+const auto *FunctionName = UseMax ? "std::max" : "std::min";
+const auto CondLhsStr = Lexer::getSourceText(
+Source.getExpansionRange(CondLhs->getSourceRange()), Source, LO);
+const auto CondRhsStr = Lexer::getSourceText(
+Source.getExpansionRange(CondRhs->getSourceRange()), Source, LO);
+const auto AssignLhsStr = Lexer::getSourceText(
+Source.getExpansionRange(AssignLhs->getSourceRange()), Source, LO);
+const auto AssignLhsType =
+AssignLhs->getType().getCanonicalType().getAsString();
+return (AssignLhsStr + " = " + FunctionName + "<" + AssignLhsType + ">(" +

felix642 wrote:

We should only specify the template type if the compiler is unable to deduce 
it. Otherwise it is redundant

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-20 Thread Piotr Zegar via cfe-commits


@@ -0,0 +1,129 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+  Options.store(Opts, "AlgorithmHeader",
+Options.get("AlgorithmHeader", ""));
+}
+
+void UseStdMinMaxCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  ifStmt(
+  hasCondition(binaryOperator(hasAnyOperatorName("<", ">", "<=", ">="),
+  hasLHS(expr().bind("CondLhs")),
+  hasRHS(expr().bind("CondRhs",
+  hasThen(anyOf(stmt(binaryOperator(hasOperatorName("="),
+hasLHS(expr().bind("AssignLhs")),
+hasRHS(expr().bind("AssignRhs",
+compoundStmt(has(binaryOperator(
+ hasOperatorName("="),
+ hasLHS(expr().bind("AssignLhs")),
+ hasRHS(expr().bind("AssignRhs")
+.bind("compound"
+  .bind("if"),
+  this);
+}
+
+void UseStdMinMaxCheck::registerPPCallbacks(const SourceManager ,
+Preprocessor *PP,
+Preprocessor *ModuleExpanderPP) {
+  IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseStdMinMaxCheck::check(const MatchFinder::MatchResult ) {
+  const auto *CondLhs = Result.Nodes.getNodeAs("CondLhs");
+  const auto *CondRhs = Result.Nodes.getNodeAs("CondRhs");
+  const auto *AssignLhs = Result.Nodes.getNodeAs("AssignLhs");
+  const auto *AssignRhs = Result.Nodes.getNodeAs("AssignRhs");
+  const auto *If = Result.Nodes.getNodeAs("if");
+  const auto *Compound = Result.Nodes.getNodeAs("compound");
+  const auto  = *Result.Context;
+  const auto  = Context.getLangOpts();
+  const SourceManager  = Context.getSourceManager();
+
+  const auto *BinaryOp = dyn_cast(If->getCond());
+  if (!BinaryOp || If->hasElseStorage())
+return;
+
+  if (Compound) {
+if (Compound->size() > 1)
+  return;
+  }
+
+  const SourceLocation IfLocation = If->getIfLoc();
+  const SourceLocation ThenLocation = If->getEndLoc();
+
+  if (IfLocation.isMacroID() || ThenLocation.isMacroID())
+return;
+
+  const auto CreateReplacement = [&](bool UseMax) {
+const auto *FunctionName = UseMax ? "std::max" : "std::min";
+const auto CondLhsStr = Lexer::getSourceText(
+Source.getExpansionRange(CondLhs->getSourceRange()), Source, LO);
+const auto CondRhsStr = Lexer::getSourceText(
+Source.getExpansionRange(CondRhs->getSourceRange()), Source, LO);
+const auto AssignLhsStr = Lexer::getSourceText(
+Source.getExpansionRange(AssignLhs->getSourceRange()), Source, LO);
+return (AssignLhsStr + " = " + FunctionName + "(" + CondLhsStr + ", " +
+CondRhsStr + ");")
+.str();
+  };
+  const auto OperatorStr = BinaryOp->getOpcodeStr();
+  if (((BinaryOp->getOpcode() == BO_LT || BinaryOp->getOpcode() == BO_LE) &&
+   (tidy::utils::areStatementsIdentical(CondLhs, AssignRhs, Context) &&
+tidy::utils::areStatementsIdentical(CondRhs, AssignLhs, Context))) ||
+  ((BinaryOp->getOpcode() == BO_GT || BinaryOp->getOpcode() == BO_GE) &&
+   (tidy::utils::areStatementsIdentical(CondLhs, AssignLhs, Context) &&
+tidy::utils::areStatementsIdentical(CondRhs, AssignRhs, Context {
+diag(IfLocation, "use `std::min` instead of `%0`")
+<< OperatorStr
+<< FixItHint::CreateReplacement(SourceRange(IfLocation, ThenLocation),
+CreateReplacement(/*UseMax=*/false))
+<< IncludeInserter.createIncludeInsertion(
+   Source.getFileID(If->getBeginLoc()), AlgorithmHeader);
+
+  } else if (((BinaryOp->getOpcode() == BO_LT ||
+   BinaryOp->getOpcode() == BO_LE) &&
+  

[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-20 Thread Félix-Antoine Constantin via cfe-commits


@@ -0,0 +1,129 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+  Options.store(Opts, "AlgorithmHeader",
+Options.get("AlgorithmHeader", ""));
+}
+
+void UseStdMinMaxCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  ifStmt(
+  hasCondition(binaryOperator(hasAnyOperatorName("<", ">", "<=", ">="),
+  hasLHS(expr().bind("CondLhs")),
+  hasRHS(expr().bind("CondRhs",
+  hasThen(anyOf(stmt(binaryOperator(hasOperatorName("="),
+hasLHS(expr().bind("AssignLhs")),
+hasRHS(expr().bind("AssignRhs",
+compoundStmt(has(binaryOperator(
+ hasOperatorName("="),
+ hasLHS(expr().bind("AssignLhs")),
+ hasRHS(expr().bind("AssignRhs")
+.bind("compound"
+  .bind("if"),
+  this);
+}
+
+void UseStdMinMaxCheck::registerPPCallbacks(const SourceManager ,
+Preprocessor *PP,
+Preprocessor *ModuleExpanderPP) {
+  IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseStdMinMaxCheck::check(const MatchFinder::MatchResult ) {
+  const auto *CondLhs = Result.Nodes.getNodeAs("CondLhs");
+  const auto *CondRhs = Result.Nodes.getNodeAs("CondRhs");
+  const auto *AssignLhs = Result.Nodes.getNodeAs("AssignLhs");
+  const auto *AssignRhs = Result.Nodes.getNodeAs("AssignRhs");
+  const auto *If = Result.Nodes.getNodeAs("if");
+  const auto *Compound = Result.Nodes.getNodeAs("compound");
+  const auto  = *Result.Context;
+  const auto  = Context.getLangOpts();
+  const SourceManager  = Context.getSourceManager();
+
+  const auto *BinaryOp = dyn_cast(If->getCond());
+  if (!BinaryOp || If->hasElseStorage())
+return;
+
+  if (Compound) {
+if (Compound->size() > 1)
+  return;
+  }
+
+  const SourceLocation IfLocation = If->getIfLoc();
+  const SourceLocation ThenLocation = If->getEndLoc();

felix642 wrote:

The thenLocation might not be valid in some cases.
Let's take for example this code :
```
if(a < b)
a = b;
```

I would assume that the ThenLocation will match on the character 'b', but in 
your case you want to match on the ';' otherwise you'll add an extra semicolon 
at the end of the line.

You'll need to add a call to `Lexer::getLocForEndOfToken` to resolve this 
issue. Please have a look on how other checks do it.

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-20 Thread Julian Schmidt via cfe-commits


@@ -0,0 +1,129 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+  Options.store(Opts, "AlgorithmHeader",
+Options.get("AlgorithmHeader", ""));
+}
+
+void UseStdMinMaxCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  ifStmt(
+  hasCondition(binaryOperator(hasAnyOperatorName("<", ">", "<=", ">="),
+  hasLHS(expr().bind("CondLhs")),
+  hasRHS(expr().bind("CondRhs",
+  hasThen(anyOf(stmt(binaryOperator(hasOperatorName("="),
+hasLHS(expr().bind("AssignLhs")),
+hasRHS(expr().bind("AssignRhs",
+compoundStmt(has(binaryOperator(
+ hasOperatorName("="),
+ hasLHS(expr().bind("AssignLhs")),
+ hasRHS(expr().bind("AssignRhs")
+.bind("compound"
+  .bind("if"),
+  this);
+}
+
+void UseStdMinMaxCheck::registerPPCallbacks(const SourceManager ,
+Preprocessor *PP,
+Preprocessor *ModuleExpanderPP) {
+  IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseStdMinMaxCheck::check(const MatchFinder::MatchResult ) {
+  const auto *CondLhs = Result.Nodes.getNodeAs("CondLhs");
+  const auto *CondRhs = Result.Nodes.getNodeAs("CondRhs");
+  const auto *AssignLhs = Result.Nodes.getNodeAs("AssignLhs");
+  const auto *AssignRhs = Result.Nodes.getNodeAs("AssignRhs");
+  const auto *If = Result.Nodes.getNodeAs("if");
+  const auto *Compound = Result.Nodes.getNodeAs("compound");
+  const auto  = *Result.Context;
+  const auto  = Context.getLangOpts();
+  const SourceManager  = Context.getSourceManager();
+
+  const auto *BinaryOp = dyn_cast(If->getCond());
+  if (!BinaryOp || If->hasElseStorage())
+return;
+
+  if (Compound) {
+if (Compound->size() > 1)
+  return;
+  }
+
+  const SourceLocation IfLocation = If->getIfLoc();
+  const SourceLocation ThenLocation = If->getEndLoc();
+
+  if (IfLocation.isMacroID() || ThenLocation.isMacroID())
+return;
+
+  const auto CreateReplacement = [&](bool useMax) {
+std::string functionName = useMax ? "std::max" : "std::min";

5chmidti wrote:

Please use `const auto*`, `const char*` or `const StringRef` for `FunctionName`

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-19 Thread Julian Schmidt via cfe-commits


@@ -0,0 +1,143 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+  Options.store(Opts, "AlgorithmHeader",
+Options.get("AlgorithmHeader", ""));
+}
+
+void UseStdMinMaxCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  ifStmt(
+  hasCondition(binaryOperator(hasAnyOperatorName("<", ">", "<=", ">="),
+  hasLHS(expr().bind("CondLhs")),
+  hasRHS(expr().bind("CondRhs",
+  hasThen(anyOf(stmt(binaryOperator(hasOperatorName("="),
+hasLHS(expr().bind("AssignLhs")),
+hasRHS(expr().bind("AssignRhs",
+compoundStmt(has(binaryOperator(
+ hasOperatorName("="),
+ hasLHS(expr().bind("AssignLhs")),
+ hasRHS(expr().bind("AssignRhs")
+.bind("compound"
+  .bind("if"),
+  this);
+}
+
+void UseStdMinMaxCheck::registerPPCallbacks(const SourceManager ,
+Preprocessor *PP,
+Preprocessor *ModuleExpanderPP) {
+  IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseStdMinMaxCheck::check(const MatchFinder::MatchResult ) {
+  const auto *CondLhs = Result.Nodes.getNodeAs("CondLhs");
+  const auto *CondRhs = Result.Nodes.getNodeAs("CondRhs");
+  const auto *AssignLhs = Result.Nodes.getNodeAs("AssignLhs");
+  const auto *AssignRhs = Result.Nodes.getNodeAs("AssignRhs");
+  const auto *If = Result.Nodes.getNodeAs("if");
+  const auto *Compound = Result.Nodes.getNodeAs("compound");
+  auto  = *Result.Context;

5chmidti wrote:

`Context` can be `const`

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-19 Thread Julian Schmidt via cfe-commits


@@ -0,0 +1,143 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+  Options.store(Opts, "AlgorithmHeader",
+Options.get("AlgorithmHeader", ""));
+}
+
+void UseStdMinMaxCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  ifStmt(
+  hasCondition(binaryOperator(hasAnyOperatorName("<", ">", "<=", ">="),
+  hasLHS(expr().bind("CondLhs")),
+  hasRHS(expr().bind("CondRhs",
+  hasThen(anyOf(stmt(binaryOperator(hasOperatorName("="),
+hasLHS(expr().bind("AssignLhs")),
+hasRHS(expr().bind("AssignRhs",
+compoundStmt(has(binaryOperator(
+ hasOperatorName("="),
+ hasLHS(expr().bind("AssignLhs")),
+ hasRHS(expr().bind("AssignRhs")
+.bind("compound"
+  .bind("if"),
+  this);
+}
+
+void UseStdMinMaxCheck::registerPPCallbacks(const SourceManager ,
+Preprocessor *PP,
+Preprocessor *ModuleExpanderPP) {
+  IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseStdMinMaxCheck::check(const MatchFinder::MatchResult ) {
+  const auto *CondLhs = Result.Nodes.getNodeAs("CondLhs");
+  const auto *CondRhs = Result.Nodes.getNodeAs("CondRhs");
+  const auto *AssignLhs = Result.Nodes.getNodeAs("AssignLhs");
+  const auto *AssignRhs = Result.Nodes.getNodeAs("AssignRhs");
+  const auto *If = Result.Nodes.getNodeAs("if");
+  const auto *Compound = Result.Nodes.getNodeAs("compound");
+  auto  = *Result.Context;
+  const SourceManager  = Context.getSourceManager();
+
+  const auto *BinaryOp = dyn_cast(If->getCond());
+  if (!BinaryOp || If->hasElseStorage())
+return;
+
+  if (Compound) {
+int count = 0;
+clang::Stmt::const_child_iterator I = Compound->child_begin();
+clang::Stmt::const_child_iterator E = Compound->child_end();
+for (; I != E; ++I) {
+  count++;
+}
+if (count > 1)
+  return;

5chmidti wrote:

Please use `Compound.size() > 1` instead of calculating the number of 
statements (https://clang.llvm.org/doxygen/Stmt_8h_source.html#l01647).

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-19 Thread Julian Schmidt via cfe-commits


@@ -224,6 +224,12 @@ New checks
   Recommends the smallest possible underlying type for an ``enum`` or ``enum``
   class based on the range of its enumerators.
 
+- New :doc:`readability-use-std-min-max
+  ` check.
+
+  Replaces certain conditional statements with equivalent ``std::min`` or
+  ``std::max`` expressions.
+

5chmidti wrote:

Please move this after the other newly added `readability` checks so that the 
list is sorted alphabetically.

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-19 Thread Julian Schmidt via cfe-commits

https://github.com/5chmidti edited 
https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-18 Thread Piotr Zegar via cfe-commits


@@ -0,0 +1,132 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()),
+  AlgorithmHeader(Options.get("AlgorithmHeader", "")) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+}
+
+void UseStdMinMaxCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  ifStmt(
+  has(binaryOperator(
+  anyOf(hasOperatorName("<"), hasOperatorName(">"),

PiotrZSL wrote:

if you leave it like this, use hasAnyOperatorName

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-18 Thread Piotr Zegar via cfe-commits


@@ -0,0 +1,132 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()),
+  AlgorithmHeader(Options.get("AlgorithmHeader", "")) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+}
+
+void UseStdMinMaxCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  ifStmt(
+  has(binaryOperator(
+  anyOf(hasOperatorName("<"), hasOperatorName(">"),
+hasOperatorName("<="), hasOperatorName(">=")),
+  hasLHS(expr().bind("lhsVar1")), hasRHS(expr().bind("rhsVar1",
+  hasThen(
+  anyOf(stmt(binaryOperator(hasOperatorName("="),
+hasLHS(expr().bind("lhsVar2")),
+hasRHS(expr().bind("rhsVar2",
+compoundStmt(has(binaryOperator(
+hasOperatorName("="), hasLHS(expr().bind("lhsVar2")),
+hasRHS(expr().bind("rhsVar2"
+  .bind("ifStmt"),
+  this);
+}
+
+void UseStdMinMaxCheck::registerPPCallbacks(const SourceManager ,
+Preprocessor *PP,
+Preprocessor *ModuleExpanderPP) {
+  IncludeInserter.registerPreprocessor(PP);
+}
+
+void UseStdMinMaxCheck::check(const MatchFinder::MatchResult ) {
+  const auto *lhsVar1 = Result.Nodes.getNodeAs("lhsVar1");
+  const auto *rhsVar1 = Result.Nodes.getNodeAs("rhsVar1");
+  const auto *lhsVar2 = Result.Nodes.getNodeAs("lhsVar2");
+  const auto *rhsVar2 = Result.Nodes.getNodeAs("rhsVar2");
+  const auto *ifStmt = Result.Nodes.getNodeAs("ifStmt");
+  auto  = *Result.Context;
+  const SourceManager  = Context.getSourceManager();
+
+  if (!lhsVar1 || !rhsVar1 || !lhsVar2 || !rhsVar2 || !ifStmt)
+return;
+
+  const auto *binaryOp = dyn_cast(ifStmt->getCond());
+  if (!binaryOp)
+return;
+
+  SourceLocation ifLocation = ifStmt->getIfLoc();
+  SourceLocation thenLocation = ifStmt->getEndLoc();
+
+  auto lhsVar1Str =
+  Lexer::getSourceText(Source.getExpansionRange(lhsVar1->getSourceRange()),
+   Context.getSourceManager(), Context.getLangOpts());
+
+  auto lhsVar2Str =
+  Lexer::getSourceText(Source.getExpansionRange(lhsVar2->getSourceRange()),
+   Context.getSourceManager(), Context.getLangOpts());
+
+  auto rhsVar1Str =
+  Lexer::getSourceText(Source.getExpansionRange(rhsVar1->getSourceRange()),
+   Context.getSourceManager(), Context.getLangOpts());
+
+  auto replacementMax = lhsVar2Str.str() + " = std::max(" + lhsVar1Str.str() +

PiotrZSL wrote:

no need to read text & produce strings if we do not enter into any if bellow.
you could wrap this into two local lambdas, and call it/create string only when 
needed.

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-18 Thread Piotr Zegar via cfe-commits


@@ -0,0 +1,132 @@
+//===--- UseStdMinMaxCheck.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 "UseStdMinMaxCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Preprocessor.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+UseStdMinMaxCheck::UseStdMinMaxCheck(StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+   utils::IncludeSorter::IS_LLVM),
+  areDiagsSelfContained()),
+  AlgorithmHeader(Options.get("AlgorithmHeader", "")) {}
+
+void UseStdMinMaxCheck::storeOptions(ClangTidyOptions::OptionMap ) {
+  Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());

PiotrZSL wrote:

remove AlgorithmHeader option, or add it here to store. I would personally 
remove it.

https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-18 Thread Piotr Zegar via cfe-commits


@@ -0,0 +1,149 @@
+// RUN: %check_clang_tidy %s readability-use-std-min-max %t
+
+#define MY_MACRO_MIN(a, b) ((a) < (b) ? (a) : (b))
+
+constexpr int myConstexprMin(int a, int b) {
+  return a < b ? a : b;
+}
+
+constexpr int myConstexprMax(int a, int b) {
+  return a > b ? a : b;
+}
+
+class MyClass {
+public:
+  int member1;
+  int member2;
+};
+
+void foo() {
+  int value1,value2,value3;
+  short value4;
+  MyClass obj;
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value1 = std::max(value1, value2);
+  if (value1 < value2)
+value1 = value2; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value2 = std::min(value1, value2);
+  if (value1 < value2)
+value2 = value1; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `>` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value2 = std::min(value2, value1);
+  if (value2 > value1)
+value2 = value1; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>` 
[readability-use-std-min-max
+  // CHECK-FIXES: value1 = std::max(value2, value1);
+  if (value2 > value1)
+value1 = value2; 
+
+  // No suggestion needed here
+  if (value1 == value2)
+value1 = value2;
+  
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value1 = std::max(value1, value4);
+  if(value1` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value1 = std::min(value1, myConstexprMax(value2, value3));
+  if (value1 > myConstexprMax(value2, value3))
+value1 = myConstexprMax(value2, value3); 
+  
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value2 = std::min(value1, value2);
+  if (value1 <= value2)
+value2 = value1; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value1 = std::max(value1, value2);
+  if (value1 <= value2)
+value1 = value2; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value1 = std::max(value2, value1);
+  if (value2 >= value1)
+value1 = value2; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `>=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value2 = std::min(value2, value1);
+  if (value2 >= value1)
+value2 = value1; 
+  
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<` 
[readability-use-std-min-max]
+  // CHECK-FIXES: obj.member1 = std::max(obj.member1, obj.member2);
+  if (obj.member1 < obj.member2)
+obj.member1 = obj.member2; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<` 
[readability-use-std-min-max]
+  // CHECK-FIXES: obj.member2 = std::min(obj.member1, obj.member2);
+  if (obj.member1 < obj.member2)
+obj.member2 = obj.member1; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `>` 
[readability-use-std-min-max]
+  // CHECK-FIXES: obj.member2 = std::min(obj.member2, obj.member1);
+  if (obj.member2 > obj.member1)
+obj.member2 = obj.member1; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>` 
[readability-use-std-min-max]
+  // CHECK-FIXES: obj.member1 = std::max(obj.member2, obj.member1);
+  if (obj.member2 > obj.member1)
+obj.member1 = obj.member2; 
+  
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<` 
[readability-use-std-min-max]
+  // CHECK-FIXES: obj.member1 = std::max(obj.member1, value4);
+  if (obj.member1 < value4)
+obj.member1 = value4; 
+  
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value3 = std::min(obj.member1 + value2, value3);
+  if (obj.member1 + value2 < value3)
+value3 = obj.member1 + value2; 
+  
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: obj.member2 = std::min(value1, obj.member2);
+  if (value1 <= obj.member2)
+obj.member2 = value1; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value1 = std::max(value1, obj.member2);
+  if (value1 <= obj.member2)
+value1 = obj.member2; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value1 = std::max(obj.member2, value1);
+  if (obj.member2 >= value1)
+value1 = obj.member2; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `>=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: obj.member2 = std::min(obj.member2, value1);
+  if (obj.member2 >= value1)
+obj.member2 = 

[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-18 Thread Piotr Zegar via cfe-commits

https://github.com/PiotrZSL edited 
https://github.com/llvm/llvm-project/pull/77816
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [llvm] Add clang-tidy check to suggest replacement of conditional statement with std::min/std::max (PR #77816)

2024-01-18 Thread Félix-Antoine Constantin via cfe-commits


@@ -0,0 +1,149 @@
+// RUN: %check_clang_tidy %s readability-use-std-min-max %t
+
+#define MY_MACRO_MIN(a, b) ((a) < (b) ? (a) : (b))
+
+constexpr int myConstexprMin(int a, int b) {
+  return a < b ? a : b;
+}
+
+constexpr int myConstexprMax(int a, int b) {
+  return a > b ? a : b;
+}
+
+class MyClass {
+public:
+  int member1;
+  int member2;
+};
+
+void foo() {
+  int value1,value2,value3;
+  short value4;
+  MyClass obj;
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value1 = std::max(value1, value2);
+  if (value1 < value2)
+value1 = value2; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value2 = std::min(value1, value2);
+  if (value1 < value2)
+value2 = value1; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `>` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value2 = std::min(value2, value1);
+  if (value2 > value1)
+value2 = value1; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>` 
[readability-use-std-min-max
+  // CHECK-FIXES: value1 = std::max(value2, value1);
+  if (value2 > value1)
+value1 = value2; 
+
+  // No suggestion needed here
+  if (value1 == value2)
+value1 = value2;
+  
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value1 = std::max(value1, value4);
+  if(value1` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value1 = std::min(value1, myConstexprMax(value2, value3));
+  if (value1 > myConstexprMax(value2, value3))
+value1 = myConstexprMax(value2, value3); 
+  
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value2 = std::min(value1, value2);
+  if (value1 <= value2)
+value2 = value1; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value1 = std::max(value1, value2);
+  if (value1 <= value2)
+value1 = value2; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value1 = std::max(value2, value1);
+  if (value2 >= value1)
+value1 = value2; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `>=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value2 = std::min(value2, value1);
+  if (value2 >= value1)
+value2 = value1; 
+  
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<` 
[readability-use-std-min-max]
+  // CHECK-FIXES: obj.member1 = std::max(obj.member1, obj.member2);
+  if (obj.member1 < obj.member2)
+obj.member1 = obj.member2; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<` 
[readability-use-std-min-max]
+  // CHECK-FIXES: obj.member2 = std::min(obj.member1, obj.member2);
+  if (obj.member1 < obj.member2)
+obj.member2 = obj.member1; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `>` 
[readability-use-std-min-max]
+  // CHECK-FIXES: obj.member2 = std::min(obj.member2, obj.member1);
+  if (obj.member2 > obj.member1)
+obj.member2 = obj.member1; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>` 
[readability-use-std-min-max]
+  // CHECK-FIXES: obj.member1 = std::max(obj.member2, obj.member1);
+  if (obj.member2 > obj.member1)
+obj.member1 = obj.member2; 
+  
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<` 
[readability-use-std-min-max]
+  // CHECK-FIXES: obj.member1 = std::max(obj.member1, value4);
+  if (obj.member1 < value4)
+obj.member1 = value4; 
+  
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value3 = std::min(obj.member1 + value2, value3);
+  if (obj.member1 + value2 < value3)
+value3 = obj.member1 + value2; 
+  
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `<=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: obj.member2 = std::min(value1, obj.member2);
+  if (value1 <= obj.member2)
+obj.member2 = value1; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value1 = std::max(value1, obj.member2);
+  if (value1 <= obj.member2)
+value1 = obj.member2; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `>=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: value1 = std::max(obj.member2, value1);
+  if (obj.member2 >= value1)
+value1 = obj.member2; 
+
+  // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `>=` 
[readability-use-std-min-max]
+  // CHECK-FIXES: obj.member2 = std::min(obj.member2, value1);
+  if (obj.member2 >= value1)
+obj.member2 =