[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-30 Thread Paul Heidekrüger via cfe-commits

https://github.com/PBHDK updated https://github.com/llvm/llvm-project/pull/95220

From 37292995de0c5aa87408586749795a97468d4725 Mon Sep 17 00:00:00 2001
From: Sebastian Wolf 
Date: Wed, 17 Apr 2024 16:16:35 +0200
Subject: [PATCH 01/23] Enforce SL.con.3: Add check to replace operator[] with
 at() on std containers

---
 .../AvoidBoundsErrorsCheck.cpp| 81 +++
 .../AvoidBoundsErrorsCheck.h  | 32 
 .../cppcoreguidelines/CMakeLists.txt  |  1 +
 .../CppCoreGuidelinesTidyModule.cpp   |  3 +
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 ++
 .../cppcoreguidelines/avoid-bounds-errors.rst | 20 +
 .../docs/clang-tidy/checks/list.rst   |  1 +
 .../cppcoreguidelines/avoid-bounds-errors.cpp | 66 +++
 8 files changed, 209 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-bounds-errors.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-bounds-errors.cpp

diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
new file mode 100644
index 0..524c21b5bdb81
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
@@ -0,0 +1,81 @@
+//===--- AvoidBoundsErrorsCheck.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 "AvoidBoundsErrorsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+#include 
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+bool isApplicable(const QualType &Type) {
+  const auto TypeStr = Type.getAsString();
+  bool Result = false;
+  // Only check for containers in the std namespace
+  if (TypeStr.find("std::vector") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::array") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::deque") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::unordered_map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::flat_map") != std::string::npos) {
+Result = true;
+  }
+  // TODO Add std::span with C++26
+  return Result;
+}
+
+void AvoidBoundsErrorsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  callExpr(callee(cxxMethodDecl(hasName("operator[]")).bind("f")))
+  .bind("x"),
+  this);
+}
+
+void AvoidBoundsErrorsCheck::check(const MatchFinder::MatchResult &Result) {
+  const ASTContext &Context = *Result.Context;
+  const SourceManager &Source = Context.getSourceManager();
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("x");
+  const auto *MatchedFunction = Result.Nodes.getNodeAs("f");
+  const auto Type = MatchedFunction->getThisType();
+  if (!isApplicable(Type)) {
+return;
+  }
+
+  // Get original code.
+  const SourceLocation b(MatchedExpr->getBeginLoc());
+  const SourceLocation e(MatchedExpr->getEndLoc());
+  const std::string OriginalCode =
+  Lexer::getSourceText(CharSourceRange::getTokenRange(b, e), Source,
+   getLangOpts())
+  .str();
+  const auto Range = SourceRange(b, e);
+
+  // Build replacement.
+  std::string NewCode = OriginalCode;
+  const auto BeginOpen = NewCode.find("[");
+  NewCode.replace(BeginOpen, 1, ".at(");
+  const auto BeginClose = NewCode.find("]");
+  NewCode.replace(BeginClose, 1, ")");
+
+  diag(MatchedExpr->getBeginLoc(), "Do not use operator[], use at() instead.")
+  << FixItHint::CreateReplacement(Range, NewCode);
+}
+
+} // namespace clang::tidy::cppcoreguidelines
diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
new file mode 100644
index 0..f915729cd7bbe
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
@@ -0,0 +1,32 @@
+//===--- AvoidBoundsErrorsCheck.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 
LLV

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-30 Thread Paul Heidekrüger via cfe-commits

https://github.com/PBHDK updated https://github.com/llvm/llvm-project/pull/95220

From 37292995de0c5aa87408586749795a97468d4725 Mon Sep 17 00:00:00 2001
From: Sebastian Wolf 
Date: Wed, 17 Apr 2024 16:16:35 +0200
Subject: [PATCH 01/24] Enforce SL.con.3: Add check to replace operator[] with
 at() on std containers

---
 .../AvoidBoundsErrorsCheck.cpp| 81 +++
 .../AvoidBoundsErrorsCheck.h  | 32 
 .../cppcoreguidelines/CMakeLists.txt  |  1 +
 .../CppCoreGuidelinesTidyModule.cpp   |  3 +
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 ++
 .../cppcoreguidelines/avoid-bounds-errors.rst | 20 +
 .../docs/clang-tidy/checks/list.rst   |  1 +
 .../cppcoreguidelines/avoid-bounds-errors.cpp | 66 +++
 8 files changed, 209 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-bounds-errors.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-bounds-errors.cpp

diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
new file mode 100644
index 0..524c21b5bdb81
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
@@ -0,0 +1,81 @@
+//===--- AvoidBoundsErrorsCheck.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 "AvoidBoundsErrorsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+#include 
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+bool isApplicable(const QualType &Type) {
+  const auto TypeStr = Type.getAsString();
+  bool Result = false;
+  // Only check for containers in the std namespace
+  if (TypeStr.find("std::vector") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::array") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::deque") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::unordered_map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::flat_map") != std::string::npos) {
+Result = true;
+  }
+  // TODO Add std::span with C++26
+  return Result;
+}
+
+void AvoidBoundsErrorsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  callExpr(callee(cxxMethodDecl(hasName("operator[]")).bind("f")))
+  .bind("x"),
+  this);
+}
+
+void AvoidBoundsErrorsCheck::check(const MatchFinder::MatchResult &Result) {
+  const ASTContext &Context = *Result.Context;
+  const SourceManager &Source = Context.getSourceManager();
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("x");
+  const auto *MatchedFunction = Result.Nodes.getNodeAs("f");
+  const auto Type = MatchedFunction->getThisType();
+  if (!isApplicable(Type)) {
+return;
+  }
+
+  // Get original code.
+  const SourceLocation b(MatchedExpr->getBeginLoc());
+  const SourceLocation e(MatchedExpr->getEndLoc());
+  const std::string OriginalCode =
+  Lexer::getSourceText(CharSourceRange::getTokenRange(b, e), Source,
+   getLangOpts())
+  .str();
+  const auto Range = SourceRange(b, e);
+
+  // Build replacement.
+  std::string NewCode = OriginalCode;
+  const auto BeginOpen = NewCode.find("[");
+  NewCode.replace(BeginOpen, 1, ".at(");
+  const auto BeginClose = NewCode.find("]");
+  NewCode.replace(BeginClose, 1, ")");
+
+  diag(MatchedExpr->getBeginLoc(), "Do not use operator[], use at() instead.")
+  << FixItHint::CreateReplacement(Range, NewCode);
+}
+
+} // namespace clang::tidy::cppcoreguidelines
diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
new file mode 100644
index 0..f915729cd7bbe
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
@@ -0,0 +1,32 @@
+//===--- AvoidBoundsErrorsCheck.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 
LLV

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-30 Thread Paul Heidekrüger via cfe-commits

https://github.com/PBHDK updated https://github.com/llvm/llvm-project/pull/95220

From 37292995de0c5aa87408586749795a97468d4725 Mon Sep 17 00:00:00 2001
From: Sebastian Wolf 
Date: Wed, 17 Apr 2024 16:16:35 +0200
Subject: [PATCH 01/25] Enforce SL.con.3: Add check to replace operator[] with
 at() on std containers

---
 .../AvoidBoundsErrorsCheck.cpp| 81 +++
 .../AvoidBoundsErrorsCheck.h  | 32 
 .../cppcoreguidelines/CMakeLists.txt  |  1 +
 .../CppCoreGuidelinesTidyModule.cpp   |  3 +
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 ++
 .../cppcoreguidelines/avoid-bounds-errors.rst | 20 +
 .../docs/clang-tidy/checks/list.rst   |  1 +
 .../cppcoreguidelines/avoid-bounds-errors.cpp | 66 +++
 8 files changed, 209 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-bounds-errors.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-bounds-errors.cpp

diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
new file mode 100644
index 0..524c21b5bdb81
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
@@ -0,0 +1,81 @@
+//===--- AvoidBoundsErrorsCheck.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 "AvoidBoundsErrorsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+#include 
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+bool isApplicable(const QualType &Type) {
+  const auto TypeStr = Type.getAsString();
+  bool Result = false;
+  // Only check for containers in the std namespace
+  if (TypeStr.find("std::vector") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::array") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::deque") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::unordered_map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::flat_map") != std::string::npos) {
+Result = true;
+  }
+  // TODO Add std::span with C++26
+  return Result;
+}
+
+void AvoidBoundsErrorsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  callExpr(callee(cxxMethodDecl(hasName("operator[]")).bind("f")))
+  .bind("x"),
+  this);
+}
+
+void AvoidBoundsErrorsCheck::check(const MatchFinder::MatchResult &Result) {
+  const ASTContext &Context = *Result.Context;
+  const SourceManager &Source = Context.getSourceManager();
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("x");
+  const auto *MatchedFunction = Result.Nodes.getNodeAs("f");
+  const auto Type = MatchedFunction->getThisType();
+  if (!isApplicable(Type)) {
+return;
+  }
+
+  // Get original code.
+  const SourceLocation b(MatchedExpr->getBeginLoc());
+  const SourceLocation e(MatchedExpr->getEndLoc());
+  const std::string OriginalCode =
+  Lexer::getSourceText(CharSourceRange::getTokenRange(b, e), Source,
+   getLangOpts())
+  .str();
+  const auto Range = SourceRange(b, e);
+
+  // Build replacement.
+  std::string NewCode = OriginalCode;
+  const auto BeginOpen = NewCode.find("[");
+  NewCode.replace(BeginOpen, 1, ".at(");
+  const auto BeginClose = NewCode.find("]");
+  NewCode.replace(BeginClose, 1, ")");
+
+  diag(MatchedExpr->getBeginLoc(), "Do not use operator[], use at() instead.")
+  << FixItHint::CreateReplacement(Range, NewCode);
+}
+
+} // namespace clang::tidy::cppcoreguidelines
diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
new file mode 100644
index 0..f915729cd7bbe
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
@@ -0,0 +1,32 @@
+//===--- AvoidBoundsErrorsCheck.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 
LLV

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-07-08 Thread Paul Heidekrüger via cfe-commits


@@ -0,0 +1,124 @@
+//===--- ProBoundsAvoidUncheckedContainerAccesses.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 "ProBoundsAvoidUncheckedContainerAccesses.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+static constexpr std::array SubscriptDefaultExclusions = {
+llvm::StringRef("::std::map"), llvm::StringRef("::std::unordered_map"),
+llvm::StringRef("::std::flat_map")};
+
+ProBoundsAvoidUncheckedContainerAccesses::
+ProBoundsAvoidUncheckedContainerAccesses(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {
+
+  SubscriptExcludedClasses = clang::tidy::utils::options::parseStringList(
+  Options.get("ExcludeClasses", ""));
+  SubscriptExcludedClasses.insert(SubscriptExcludedClasses.end(),
+  SubscriptDefaultExclusions.begin(),
+  SubscriptDefaultExclusions.end());
+}
+
+void ProBoundsAvoidUncheckedContainerAccesses::storeOptions(
+ClangTidyOptions::OptionMap &Opts) {
+
+  if (SubscriptExcludedClasses.size() == SubscriptDefaultExclusions.size()) {
+Options.store(Opts, "ExcludeClasses", "");
+return;
+  }
+
+  // Sum up the sizes of the defaults ( + semicolons), so we can remove them
+  // from the saved options
+  size_t DefaultsStringLength = std::transform_reduce(
+  SubscriptDefaultExclusions.begin(), SubscriptDefaultExclusions.end(),
+  SubscriptDefaultExclusions.size(), std::plus<>(),
+  [](llvm::StringRef Name) { return Name.size(); });
+
+  std::string Serialized = clang::tidy::utils::options::serializeStringList(
+  SubscriptExcludedClasses);
+
+  Options.store(Opts, "ExcludeClasses",
+Serialized.substr(0, Serialized.size() - 
DefaultsStringLength));
+}
+
+const CXXMethodDecl *findAlternative(const CXXRecordDecl *MatchedParent,
+ const CXXMethodDecl *MatchedOperator) {

PBHDK wrote:

Ah, fair point.
@HerrCai0907, would a simple "TODO: account for alternative being defined in 
subclass" work? Or am I misunderstanding something?

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-07-08 Thread Paul Heidekrüger via cfe-commits


@@ -0,0 +1,124 @@
+//===--- ProBoundsAvoidUncheckedContainerAccesses.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 "ProBoundsAvoidUncheckedContainerAccesses.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+static constexpr std::array SubscriptDefaultExclusions = {
+llvm::StringRef("::std::map"), llvm::StringRef("::std::unordered_map"),
+llvm::StringRef("::std::flat_map")};

PBHDK wrote:

The "record have key_type, value_type, and .at method" suggestion would blindly 
exclude any map-related at() method, even if its semantics are different, 
correct? 
Do you think this could cause any issues? Is it fair to assume that other 
libraries will define it so that it needs to be excluded?
Worst case, we have false negatives. Or am I misunderstanding something?

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() (PR #90043)

2024-06-07 Thread Paul Heidekrüger via cfe-commits

PBHDK wrote:

> > > I am adding @leunam99 and @PBHDK to the PR, who will contribute in the 
> > > next few weeks.
> > 
> > 
> > Since we cannot push to this PR, we will be submitting a new PR with 
> > @sebwolf-de's + our work, correct, @EugeneZelenko, @PiotrZSL, @HerrCai0907?
> 
> Could you please resolve conversations for fixed comments?

Once we're clear on all our questions (see comments above), we'll submit a new 
PR that'll resolve all comments.
The code is ready, but we don't want to submit the PR as long as we still have 
open questions.
The problem is that we can't mark them as resolved on GitHub ourselves, and 
Sebastian is out-of-office right now.

I don't know if you can assign us to this PR somehow, but if not, someone else 
would have to mark them as resolved.

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() (PR #90043)

2024-06-10 Thread Paul Heidekrüger via cfe-commits

PBHDK wrote:

> Check if you can commit to sebwolf-de:avoid-bounds-error-check

Unfortunately, we can't. We do not have access to Sebastian's LLVM fork.
Since Sebastian is out of office right now - this is one of the reasons we're 
involved - would you be ok with us submitting a new PR with our changes where 
we reference the current PR?



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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-12 Thread Paul Heidekrüger via cfe-commits

https://github.com/PBHDK created https://github.com/llvm/llvm-project/pull/95220

This PR is based on the PR #90043 by @sebwolf-de, who has given us (@leunam99 
and myself) [permission to continue his 
work](https://github.com/llvm/llvm-project/pull/90043#issuecomment-2137455627).

The original PR message reads:

> The string based test to find out whether the check is applicable on the 
> class is not ideal, but I did not find a more elegant way, yet.
> If there is more clang-query magic available, that I'm not aware of, I'm 
> happy to adapt that.

As part of the reviews for that PR, @sebwolf-de changed the following: 

- Detect viable classes automatically instead of looking for fixed names
- Disable fix-it suggestions 

This PR contains the same changes and, in addition, addresses further feedback 
provided by the maintainers.

Changes in addition to the original PR:
- Exclude `std::map`, `std::flat_map`, and `std::unordered_set` from the 
analysis by default, and add the ability for users to exclude additional 
classes from the analysis
- Add the tests @PiotrZSL requested 
[here](https://github.com/llvm/llvm-project/pull/90043#discussion_r1579858850)
- Rename the analysis from AvoidBoundsErrorsCheck to 
PreferAtOverSubscriptOperatorCheck as requested by @PiotrZSL 
[here](https://github.com/llvm/llvm-project/pull/90043#discussion_r1579853430) 
- Add a more detailed description of what the analysis does as requested by 
@PiotrZSL 
[here](https://github.com/llvm/llvm-project/pull/90043#discussion_r1579847155)
 

We explicitly don't ignore unused code with `TK_IgnoreUnlessSpelledInSource`, 
as requested by @PiotrZSL 
[here](https://github.com/llvm/llvm-project/pull/90043#discussion_r1579844550), 
because it caused the template-related tests to fail.

We are not sure what the best behaviour for templates is; should we:

-  not warn if using `at()` will make a different instantiation not compile?
- warn at the place that requires the template instantiation?
- keep the warning and add the name of the class of the object / the template 
parameters that lead to the message?
- not warn in templates at all because the code is implicit?

@carlosgalvezp and @HerrCai0907 discussed the possibility of disabling the 
check when exceptions are disabled, but we were unsure whether they'd reached a 
conclusion and whether it was still relevant when fix-it suggestions are 
disabled.

What do you think?

From 37292995de0c5aa87408586749795a97468d4725 Mon Sep 17 00:00:00 2001
From: Sebastian Wolf 
Date: Wed, 17 Apr 2024 16:16:35 +0200
Subject: [PATCH 1/8] Enforce SL.con.3: Add check to replace operator[] with
 at() on std containers

---
 .../AvoidBoundsErrorsCheck.cpp| 81 +++
 .../AvoidBoundsErrorsCheck.h  | 32 
 .../cppcoreguidelines/CMakeLists.txt  |  1 +
 .../CppCoreGuidelinesTidyModule.cpp   |  3 +
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 ++
 .../cppcoreguidelines/avoid-bounds-errors.rst | 20 +
 .../docs/clang-tidy/checks/list.rst   |  1 +
 .../cppcoreguidelines/avoid-bounds-errors.cpp | 66 +++
 8 files changed, 209 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-bounds-errors.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-bounds-errors.cpp

diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
new file mode 100644
index 0..524c21b5bdb81
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
@@ -0,0 +1,81 @@
+//===--- AvoidBoundsErrorsCheck.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 "AvoidBoundsErrorsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+#include 
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+bool isApplicable(const QualType &Type) {
+  const auto TypeStr = Type.getAsString();
+  bool Result = false;
+  // Only check for containers in the std namespace
+  if (TypeStr.find("std::vector") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::array") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::deque") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::map") != std::string::npos) {
+Result = true;
+  }

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() (PR #90043)

2024-06-12 Thread Paul Heidekrüger via cfe-commits

PBHDK wrote:

> Yes, you can just submit new PR, reference this one.

Done! Here it is: https://github.com/llvm/llvm-project/pull/95220

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-12 Thread Paul Heidekrüger via cfe-commits


@@ -0,0 +1,31 @@
+.. title:: clang-tidy - cppcoreguidelines-prefer-at-over-subscript-operator
+
+cppcoreguidelines-prefer-at-over-subscript-operator
+=
+
+This check flags all uses of ``operator[]`` where an equivalent (same 
parameter and return types) ``at()`` method exists and suggest using that 
instead.

PBHDK wrote:

Which of the two statements do you prefer: this one or the one in the release 
notes?

> Please synchronize with statement in Release Notes.

Which of the two statements do you prefer: this one or the one in the release 
notes?

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-12 Thread Paul Heidekrüger via cfe-commits

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-12 Thread Paul Heidekrüger via cfe-commits

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-12 Thread Paul Heidekrüger via cfe-commits

https://github.com/PBHDK updated https://github.com/llvm/llvm-project/pull/95220

From 37292995de0c5aa87408586749795a97468d4725 Mon Sep 17 00:00:00 2001
From: Sebastian Wolf 
Date: Wed, 17 Apr 2024 16:16:35 +0200
Subject: [PATCH 01/11] Enforce SL.con.3: Add check to replace operator[] with
 at() on std containers

---
 .../AvoidBoundsErrorsCheck.cpp| 81 +++
 .../AvoidBoundsErrorsCheck.h  | 32 
 .../cppcoreguidelines/CMakeLists.txt  |  1 +
 .../CppCoreGuidelinesTidyModule.cpp   |  3 +
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 ++
 .../cppcoreguidelines/avoid-bounds-errors.rst | 20 +
 .../docs/clang-tidy/checks/list.rst   |  1 +
 .../cppcoreguidelines/avoid-bounds-errors.cpp | 66 +++
 8 files changed, 209 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-bounds-errors.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-bounds-errors.cpp

diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
new file mode 100644
index 0..524c21b5bdb81
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
@@ -0,0 +1,81 @@
+//===--- AvoidBoundsErrorsCheck.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 "AvoidBoundsErrorsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+#include 
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+bool isApplicable(const QualType &Type) {
+  const auto TypeStr = Type.getAsString();
+  bool Result = false;
+  // Only check for containers in the std namespace
+  if (TypeStr.find("std::vector") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::array") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::deque") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::unordered_map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::flat_map") != std::string::npos) {
+Result = true;
+  }
+  // TODO Add std::span with C++26
+  return Result;
+}
+
+void AvoidBoundsErrorsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  callExpr(callee(cxxMethodDecl(hasName("operator[]")).bind("f")))
+  .bind("x"),
+  this);
+}
+
+void AvoidBoundsErrorsCheck::check(const MatchFinder::MatchResult &Result) {
+  const ASTContext &Context = *Result.Context;
+  const SourceManager &Source = Context.getSourceManager();
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("x");
+  const auto *MatchedFunction = Result.Nodes.getNodeAs("f");
+  const auto Type = MatchedFunction->getThisType();
+  if (!isApplicable(Type)) {
+return;
+  }
+
+  // Get original code.
+  const SourceLocation b(MatchedExpr->getBeginLoc());
+  const SourceLocation e(MatchedExpr->getEndLoc());
+  const std::string OriginalCode =
+  Lexer::getSourceText(CharSourceRange::getTokenRange(b, e), Source,
+   getLangOpts())
+  .str();
+  const auto Range = SourceRange(b, e);
+
+  // Build replacement.
+  std::string NewCode = OriginalCode;
+  const auto BeginOpen = NewCode.find("[");
+  NewCode.replace(BeginOpen, 1, ".at(");
+  const auto BeginClose = NewCode.find("]");
+  NewCode.replace(BeginClose, 1, ")");
+
+  diag(MatchedExpr->getBeginLoc(), "Do not use operator[], use at() instead.")
+  << FixItHint::CreateReplacement(Range, NewCode);
+}
+
+} // namespace clang::tidy::cppcoreguidelines
diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
new file mode 100644
index 0..f915729cd7bbe
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
@@ -0,0 +1,32 @@
+//===--- AvoidBoundsErrorsCheck.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 
LLV

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-13 Thread Paul Heidekrüger via cfe-commits

https://github.com/PBHDK updated https://github.com/llvm/llvm-project/pull/95220

From 37292995de0c5aa87408586749795a97468d4725 Mon Sep 17 00:00:00 2001
From: Sebastian Wolf 
Date: Wed, 17 Apr 2024 16:16:35 +0200
Subject: [PATCH 01/12] Enforce SL.con.3: Add check to replace operator[] with
 at() on std containers

---
 .../AvoidBoundsErrorsCheck.cpp| 81 +++
 .../AvoidBoundsErrorsCheck.h  | 32 
 .../cppcoreguidelines/CMakeLists.txt  |  1 +
 .../CppCoreGuidelinesTidyModule.cpp   |  3 +
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 ++
 .../cppcoreguidelines/avoid-bounds-errors.rst | 20 +
 .../docs/clang-tidy/checks/list.rst   |  1 +
 .../cppcoreguidelines/avoid-bounds-errors.cpp | 66 +++
 8 files changed, 209 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-bounds-errors.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-bounds-errors.cpp

diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
new file mode 100644
index 0..524c21b5bdb81
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
@@ -0,0 +1,81 @@
+//===--- AvoidBoundsErrorsCheck.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 "AvoidBoundsErrorsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+#include 
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+bool isApplicable(const QualType &Type) {
+  const auto TypeStr = Type.getAsString();
+  bool Result = false;
+  // Only check for containers in the std namespace
+  if (TypeStr.find("std::vector") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::array") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::deque") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::unordered_map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::flat_map") != std::string::npos) {
+Result = true;
+  }
+  // TODO Add std::span with C++26
+  return Result;
+}
+
+void AvoidBoundsErrorsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  callExpr(callee(cxxMethodDecl(hasName("operator[]")).bind("f")))
+  .bind("x"),
+  this);
+}
+
+void AvoidBoundsErrorsCheck::check(const MatchFinder::MatchResult &Result) {
+  const ASTContext &Context = *Result.Context;
+  const SourceManager &Source = Context.getSourceManager();
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("x");
+  const auto *MatchedFunction = Result.Nodes.getNodeAs("f");
+  const auto Type = MatchedFunction->getThisType();
+  if (!isApplicable(Type)) {
+return;
+  }
+
+  // Get original code.
+  const SourceLocation b(MatchedExpr->getBeginLoc());
+  const SourceLocation e(MatchedExpr->getEndLoc());
+  const std::string OriginalCode =
+  Lexer::getSourceText(CharSourceRange::getTokenRange(b, e), Source,
+   getLangOpts())
+  .str();
+  const auto Range = SourceRange(b, e);
+
+  // Build replacement.
+  std::string NewCode = OriginalCode;
+  const auto BeginOpen = NewCode.find("[");
+  NewCode.replace(BeginOpen, 1, ".at(");
+  const auto BeginClose = NewCode.find("]");
+  NewCode.replace(BeginClose, 1, ")");
+
+  diag(MatchedExpr->getBeginLoc(), "Do not use operator[], use at() instead.")
+  << FixItHint::CreateReplacement(Range, NewCode);
+}
+
+} // namespace clang::tidy::cppcoreguidelines
diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
new file mode 100644
index 0..f915729cd7bbe
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
@@ -0,0 +1,32 @@
+//===--- AvoidBoundsErrorsCheck.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 
LLV

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-13 Thread Paul Heidekrüger via cfe-commits

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-17 Thread Paul Heidekrüger via cfe-commits

https://github.com/PBHDK updated https://github.com/llvm/llvm-project/pull/95220

From 37292995de0c5aa87408586749795a97468d4725 Mon Sep 17 00:00:00 2001
From: Sebastian Wolf 
Date: Wed, 17 Apr 2024 16:16:35 +0200
Subject: [PATCH 01/15] Enforce SL.con.3: Add check to replace operator[] with
 at() on std containers

---
 .../AvoidBoundsErrorsCheck.cpp| 81 +++
 .../AvoidBoundsErrorsCheck.h  | 32 
 .../cppcoreguidelines/CMakeLists.txt  |  1 +
 .../CppCoreGuidelinesTidyModule.cpp   |  3 +
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 ++
 .../cppcoreguidelines/avoid-bounds-errors.rst | 20 +
 .../docs/clang-tidy/checks/list.rst   |  1 +
 .../cppcoreguidelines/avoid-bounds-errors.cpp | 66 +++
 8 files changed, 209 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-bounds-errors.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-bounds-errors.cpp

diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
new file mode 100644
index 0..524c21b5bdb81
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
@@ -0,0 +1,81 @@
+//===--- AvoidBoundsErrorsCheck.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 "AvoidBoundsErrorsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+#include 
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+bool isApplicable(const QualType &Type) {
+  const auto TypeStr = Type.getAsString();
+  bool Result = false;
+  // Only check for containers in the std namespace
+  if (TypeStr.find("std::vector") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::array") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::deque") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::unordered_map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::flat_map") != std::string::npos) {
+Result = true;
+  }
+  // TODO Add std::span with C++26
+  return Result;
+}
+
+void AvoidBoundsErrorsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  callExpr(callee(cxxMethodDecl(hasName("operator[]")).bind("f")))
+  .bind("x"),
+  this);
+}
+
+void AvoidBoundsErrorsCheck::check(const MatchFinder::MatchResult &Result) {
+  const ASTContext &Context = *Result.Context;
+  const SourceManager &Source = Context.getSourceManager();
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("x");
+  const auto *MatchedFunction = Result.Nodes.getNodeAs("f");
+  const auto Type = MatchedFunction->getThisType();
+  if (!isApplicable(Type)) {
+return;
+  }
+
+  // Get original code.
+  const SourceLocation b(MatchedExpr->getBeginLoc());
+  const SourceLocation e(MatchedExpr->getEndLoc());
+  const std::string OriginalCode =
+  Lexer::getSourceText(CharSourceRange::getTokenRange(b, e), Source,
+   getLangOpts())
+  .str();
+  const auto Range = SourceRange(b, e);
+
+  // Build replacement.
+  std::string NewCode = OriginalCode;
+  const auto BeginOpen = NewCode.find("[");
+  NewCode.replace(BeginOpen, 1, ".at(");
+  const auto BeginClose = NewCode.find("]");
+  NewCode.replace(BeginClose, 1, ")");
+
+  diag(MatchedExpr->getBeginLoc(), "Do not use operator[], use at() instead.")
+  << FixItHint::CreateReplacement(Range, NewCode);
+}
+
+} // namespace clang::tidy::cppcoreguidelines
diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
new file mode 100644
index 0..f915729cd7bbe
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
@@ -0,0 +1,32 @@
+//===--- AvoidBoundsErrorsCheck.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 
LLV

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-17 Thread Paul Heidekrüger via cfe-commits

https://github.com/PBHDK updated https://github.com/llvm/llvm-project/pull/95220

From 37292995de0c5aa87408586749795a97468d4725 Mon Sep 17 00:00:00 2001
From: Sebastian Wolf 
Date: Wed, 17 Apr 2024 16:16:35 +0200
Subject: [PATCH 01/16] Enforce SL.con.3: Add check to replace operator[] with
 at() on std containers

---
 .../AvoidBoundsErrorsCheck.cpp| 81 +++
 .../AvoidBoundsErrorsCheck.h  | 32 
 .../cppcoreguidelines/CMakeLists.txt  |  1 +
 .../CppCoreGuidelinesTidyModule.cpp   |  3 +
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 ++
 .../cppcoreguidelines/avoid-bounds-errors.rst | 20 +
 .../docs/clang-tidy/checks/list.rst   |  1 +
 .../cppcoreguidelines/avoid-bounds-errors.cpp | 66 +++
 8 files changed, 209 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-bounds-errors.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-bounds-errors.cpp

diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
new file mode 100644
index 0..524c21b5bdb81
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
@@ -0,0 +1,81 @@
+//===--- AvoidBoundsErrorsCheck.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 "AvoidBoundsErrorsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+#include 
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+bool isApplicable(const QualType &Type) {
+  const auto TypeStr = Type.getAsString();
+  bool Result = false;
+  // Only check for containers in the std namespace
+  if (TypeStr.find("std::vector") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::array") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::deque") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::unordered_map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::flat_map") != std::string::npos) {
+Result = true;
+  }
+  // TODO Add std::span with C++26
+  return Result;
+}
+
+void AvoidBoundsErrorsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  callExpr(callee(cxxMethodDecl(hasName("operator[]")).bind("f")))
+  .bind("x"),
+  this);
+}
+
+void AvoidBoundsErrorsCheck::check(const MatchFinder::MatchResult &Result) {
+  const ASTContext &Context = *Result.Context;
+  const SourceManager &Source = Context.getSourceManager();
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("x");
+  const auto *MatchedFunction = Result.Nodes.getNodeAs("f");
+  const auto Type = MatchedFunction->getThisType();
+  if (!isApplicable(Type)) {
+return;
+  }
+
+  // Get original code.
+  const SourceLocation b(MatchedExpr->getBeginLoc());
+  const SourceLocation e(MatchedExpr->getEndLoc());
+  const std::string OriginalCode =
+  Lexer::getSourceText(CharSourceRange::getTokenRange(b, e), Source,
+   getLangOpts())
+  .str();
+  const auto Range = SourceRange(b, e);
+
+  // Build replacement.
+  std::string NewCode = OriginalCode;
+  const auto BeginOpen = NewCode.find("[");
+  NewCode.replace(BeginOpen, 1, ".at(");
+  const auto BeginClose = NewCode.find("]");
+  NewCode.replace(BeginClose, 1, ")");
+
+  diag(MatchedExpr->getBeginLoc(), "Do not use operator[], use at() instead.")
+  << FixItHint::CreateReplacement(Range, NewCode);
+}
+
+} // namespace clang::tidy::cppcoreguidelines
diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
new file mode 100644
index 0..f915729cd7bbe
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
@@ -0,0 +1,32 @@
+//===--- AvoidBoundsErrorsCheck.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 
LLV

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-17 Thread Paul Heidekrüger via cfe-commits


@@ -0,0 +1,123 @@
+//===--- PreferAtOverSubscriptOperatorCheck.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 "PreferAtOverSubscriptOperatorCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include 
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+static constexpr std::array DefaultExclusions = {
+llvm::StringRef("std::map"), llvm::StringRef("std::unordered_map"),
+llvm::StringRef("std::flat_map")};
+
+PreferAtOverSubscriptOperatorCheck::PreferAtOverSubscriptOperatorCheck(
+StringRef Name, ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {
+
+  ExcludedClasses = clang::tidy::utils::options::parseStringList(
+  Options.get("ExcludeClasses", ""));
+  ExcludedClasses.insert(ExcludedClasses.end(), DefaultExclusions.begin(),
+ DefaultExclusions.end());
+}
+
+void PreferAtOverSubscriptOperatorCheck::storeOptions(
+ClangTidyOptions::OptionMap &Opts) {
+
+  if (ExcludedClasses.size() == DefaultExclusions.size()) {
+Options.store(Opts, "ExcludeClasses", "");
+return;
+  }
+
+  // Sum up the sizes of the defaults ( + semicolons), so we can remove them
+  // from the saved options
+  size_t DefaultsStringLength =
+  std::transform_reduce(DefaultExclusions.begin(), DefaultExclusions.end(),
+DefaultExclusions.size(), std::plus<>(),
+[](llvm::StringRef Name) { return Name.size(); });
+
+  std::string Serialized =
+  clang::tidy::utils::options::serializeStringList(ExcludedClasses);
+
+  Options.store(Opts, "ExcludeClasses",
+Serialized.substr(0, Serialized.size() - 
DefaultsStringLength));
+}
+
+const CXXMethodDecl *findAlternative(const CXXRecordDecl *MatchedParent,
+ const CXXMethodDecl *MatchedOperator) {
+  for (const CXXMethodDecl *Method : MatchedParent->methods()) {
+const bool CorrectName = Method->getNameInfo().getAsString() == "at";
+if (!CorrectName)
+  continue;
+
+const bool SameReturnType =
+Method->getReturnType() == MatchedOperator->getReturnType();
+if (!SameReturnType)
+  continue;
+
+const bool SameNumberOfArguments =
+Method->getNumParams() == MatchedOperator->getNumParams();
+if (!SameNumberOfArguments)
+  continue;
+
+for (unsigned ArgInd = 0; ArgInd < Method->getNumParams(); ArgInd++) {
+  const bool SameArgType =
+  Method->parameters()[ArgInd]->getOriginalType() ==
+  MatchedOperator->parameters()[ArgInd]->getOriginalType();
+  if (!SameArgType)
+continue;
+}
+
+return Method;
+  }
+  return static_cast(nullptr);
+}
+
+void PreferAtOverSubscriptOperatorCheck::registerMatchers(MatchFinder *Finder) 
{
+  // Need a callExpr here to match CXXOperatorCallExpr ``(&a)->operator[](0)``
+  // and CXXMemberCallExpr ``a[0]``.
+  Finder->addMatcher(
+  callExpr(
+  callee(
+  cxxMethodDecl(hasOverloadedOperatorName("[]")).bind("operator")),
+  callee(cxxMethodDecl(hasParent(
+  cxxRecordDecl(hasMethod(hasName("at"))).bind("parent")
+  .bind("caller"),
+  this);
+}
+
+void PreferAtOverSubscriptOperatorCheck::check(
+const MatchFinder::MatchResult &Result) {
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("caller");
+  const auto *MatchedOperator =
+  Result.Nodes.getNodeAs("operator");
+  const auto *MatchedParent = Result.Nodes.getNodeAs("parent");
+
+  std::string ClassIdentifier = MatchedParent->getQualifiedNameAsString();
+
+  if (std::find(ExcludedClasses.begin(), ExcludedClasses.end(),
+ClassIdentifier) != ExcludedClasses.end())
+return;

PBHDK wrote:

Like so: 5098f65dc68e33ef854335e243b9570c4b0cf696?

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-17 Thread Paul Heidekrüger via cfe-commits

https://github.com/PBHDK updated https://github.com/llvm/llvm-project/pull/95220

From 37292995de0c5aa87408586749795a97468d4725 Mon Sep 17 00:00:00 2001
From: Sebastian Wolf 
Date: Wed, 17 Apr 2024 16:16:35 +0200
Subject: [PATCH 01/17] Enforce SL.con.3: Add check to replace operator[] with
 at() on std containers

---
 .../AvoidBoundsErrorsCheck.cpp| 81 +++
 .../AvoidBoundsErrorsCheck.h  | 32 
 .../cppcoreguidelines/CMakeLists.txt  |  1 +
 .../CppCoreGuidelinesTidyModule.cpp   |  3 +
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 ++
 .../cppcoreguidelines/avoid-bounds-errors.rst | 20 +
 .../docs/clang-tidy/checks/list.rst   |  1 +
 .../cppcoreguidelines/avoid-bounds-errors.cpp | 66 +++
 8 files changed, 209 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-bounds-errors.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-bounds-errors.cpp

diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
new file mode 100644
index 0..524c21b5bdb81
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
@@ -0,0 +1,81 @@
+//===--- AvoidBoundsErrorsCheck.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 "AvoidBoundsErrorsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+#include 
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+bool isApplicable(const QualType &Type) {
+  const auto TypeStr = Type.getAsString();
+  bool Result = false;
+  // Only check for containers in the std namespace
+  if (TypeStr.find("std::vector") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::array") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::deque") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::unordered_map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::flat_map") != std::string::npos) {
+Result = true;
+  }
+  // TODO Add std::span with C++26
+  return Result;
+}
+
+void AvoidBoundsErrorsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  callExpr(callee(cxxMethodDecl(hasName("operator[]")).bind("f")))
+  .bind("x"),
+  this);
+}
+
+void AvoidBoundsErrorsCheck::check(const MatchFinder::MatchResult &Result) {
+  const ASTContext &Context = *Result.Context;
+  const SourceManager &Source = Context.getSourceManager();
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("x");
+  const auto *MatchedFunction = Result.Nodes.getNodeAs("f");
+  const auto Type = MatchedFunction->getThisType();
+  if (!isApplicable(Type)) {
+return;
+  }
+
+  // Get original code.
+  const SourceLocation b(MatchedExpr->getBeginLoc());
+  const SourceLocation e(MatchedExpr->getEndLoc());
+  const std::string OriginalCode =
+  Lexer::getSourceText(CharSourceRange::getTokenRange(b, e), Source,
+   getLangOpts())
+  .str();
+  const auto Range = SourceRange(b, e);
+
+  // Build replacement.
+  std::string NewCode = OriginalCode;
+  const auto BeginOpen = NewCode.find("[");
+  NewCode.replace(BeginOpen, 1, ".at(");
+  const auto BeginClose = NewCode.find("]");
+  NewCode.replace(BeginClose, 1, ")");
+
+  diag(MatchedExpr->getBeginLoc(), "Do not use operator[], use at() instead.")
+  << FixItHint::CreateReplacement(Range, NewCode);
+}
+
+} // namespace clang::tidy::cppcoreguidelines
diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
new file mode 100644
index 0..f915729cd7bbe
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
@@ -0,0 +1,32 @@
+//===--- AvoidBoundsErrorsCheck.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 
LLV

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-17 Thread Paul Heidekrüger via cfe-commits


@@ -0,0 +1,40 @@
+//===--- PreferAtOverSubscriptOperatorCheck.h - clang-tidy --*- C++ 
-*-===//
+//===--- PreferMemberInitializerCheck.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_CPPCOREGUIDELINES_PREFERATOVERSUBSCRIPTOPERATORCHECK_H
+#define 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PREFERATOVERSUBSCRIPTOPERATORCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::cppcoreguidelines {
+
+/// Enforce CPP core guidelines SL.con.3

PBHDK wrote:

Maybe we can just replace the Doxygen comment above with what's in the  release 
notes + check description right now:

> Flags the unsafe ``operator[]`` and suggests replacing it with ``at()``.

What do you think?

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-17 Thread Paul Heidekrüger via cfe-commits

PBHDK wrote:

> Btw, I realize that this check is part of the [bounds 
> profile](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-bounds)
>  (Bounds.4), so for consistency it should probably be named 
> `cppcoreguidelines-pro-bounds-...`.

What do you think of: 
`cppcoreguidelines-pro-bounds-avoid-unchecked-container-accesses`?
That's just me attempting to capture all of the previous suggestions in one 
name.

> This becomes then the last remaining check to complete the bounds profile!

That was actually @leunam99's and my main our motivation for getting involved 
with this work :-)

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-18 Thread Paul Heidekrüger via cfe-commits

PBHDK wrote:

> Btw, I realize that this check is part of the [bounds 
> profile](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#SS-bounds)
>  (Bounds.4), so for consistency it should probably be named 
> `cppcoreguidelines-pro-bounds-...`. This becomes then the last remaining 
> check to complete the bounds profile!

Does the fact that this check implements the bounds profile need to be 
mentioned anywhere else? Or is it enough to have it be implicit, e.g., via the 
name.

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-21 Thread Paul Heidekrüger via cfe-commits

https://github.com/PBHDK updated https://github.com/llvm/llvm-project/pull/95220

From 37292995de0c5aa87408586749795a97468d4725 Mon Sep 17 00:00:00 2001
From: Sebastian Wolf 
Date: Wed, 17 Apr 2024 16:16:35 +0200
Subject: [PATCH 01/18] Enforce SL.con.3: Add check to replace operator[] with
 at() on std containers

---
 .../AvoidBoundsErrorsCheck.cpp| 81 +++
 .../AvoidBoundsErrorsCheck.h  | 32 
 .../cppcoreguidelines/CMakeLists.txt  |  1 +
 .../CppCoreGuidelinesTidyModule.cpp   |  3 +
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 ++
 .../cppcoreguidelines/avoid-bounds-errors.rst | 20 +
 .../docs/clang-tidy/checks/list.rst   |  1 +
 .../cppcoreguidelines/avoid-bounds-errors.cpp | 66 +++
 8 files changed, 209 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-bounds-errors.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-bounds-errors.cpp

diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
new file mode 100644
index 0..524c21b5bdb81
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
@@ -0,0 +1,81 @@
+//===--- AvoidBoundsErrorsCheck.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 "AvoidBoundsErrorsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+#include 
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+bool isApplicable(const QualType &Type) {
+  const auto TypeStr = Type.getAsString();
+  bool Result = false;
+  // Only check for containers in the std namespace
+  if (TypeStr.find("std::vector") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::array") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::deque") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::unordered_map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::flat_map") != std::string::npos) {
+Result = true;
+  }
+  // TODO Add std::span with C++26
+  return Result;
+}
+
+void AvoidBoundsErrorsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  callExpr(callee(cxxMethodDecl(hasName("operator[]")).bind("f")))
+  .bind("x"),
+  this);
+}
+
+void AvoidBoundsErrorsCheck::check(const MatchFinder::MatchResult &Result) {
+  const ASTContext &Context = *Result.Context;
+  const SourceManager &Source = Context.getSourceManager();
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("x");
+  const auto *MatchedFunction = Result.Nodes.getNodeAs("f");
+  const auto Type = MatchedFunction->getThisType();
+  if (!isApplicable(Type)) {
+return;
+  }
+
+  // Get original code.
+  const SourceLocation b(MatchedExpr->getBeginLoc());
+  const SourceLocation e(MatchedExpr->getEndLoc());
+  const std::string OriginalCode =
+  Lexer::getSourceText(CharSourceRange::getTokenRange(b, e), Source,
+   getLangOpts())
+  .str();
+  const auto Range = SourceRange(b, e);
+
+  // Build replacement.
+  std::string NewCode = OriginalCode;
+  const auto BeginOpen = NewCode.find("[");
+  NewCode.replace(BeginOpen, 1, ".at(");
+  const auto BeginClose = NewCode.find("]");
+  NewCode.replace(BeginClose, 1, ")");
+
+  diag(MatchedExpr->getBeginLoc(), "Do not use operator[], use at() instead.")
+  << FixItHint::CreateReplacement(Range, NewCode);
+}
+
+} // namespace clang::tidy::cppcoreguidelines
diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
new file mode 100644
index 0..f915729cd7bbe
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
@@ -0,0 +1,32 @@
+//===--- AvoidBoundsErrorsCheck.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 
LLV

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-21 Thread Paul Heidekrüger via cfe-commits

https://github.com/PBHDK updated https://github.com/llvm/llvm-project/pull/95220

From 37292995de0c5aa87408586749795a97468d4725 Mon Sep 17 00:00:00 2001
From: Sebastian Wolf 
Date: Wed, 17 Apr 2024 16:16:35 +0200
Subject: [PATCH 01/19] Enforce SL.con.3: Add check to replace operator[] with
 at() on std containers

---
 .../AvoidBoundsErrorsCheck.cpp| 81 +++
 .../AvoidBoundsErrorsCheck.h  | 32 
 .../cppcoreguidelines/CMakeLists.txt  |  1 +
 .../CppCoreGuidelinesTidyModule.cpp   |  3 +
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 ++
 .../cppcoreguidelines/avoid-bounds-errors.rst | 20 +
 .../docs/clang-tidy/checks/list.rst   |  1 +
 .../cppcoreguidelines/avoid-bounds-errors.cpp | 66 +++
 8 files changed, 209 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-bounds-errors.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-bounds-errors.cpp

diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
new file mode 100644
index 0..524c21b5bdb81
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
@@ -0,0 +1,81 @@
+//===--- AvoidBoundsErrorsCheck.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 "AvoidBoundsErrorsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+#include 
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+bool isApplicable(const QualType &Type) {
+  const auto TypeStr = Type.getAsString();
+  bool Result = false;
+  // Only check for containers in the std namespace
+  if (TypeStr.find("std::vector") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::array") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::deque") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::unordered_map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::flat_map") != std::string::npos) {
+Result = true;
+  }
+  // TODO Add std::span with C++26
+  return Result;
+}
+
+void AvoidBoundsErrorsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  callExpr(callee(cxxMethodDecl(hasName("operator[]")).bind("f")))
+  .bind("x"),
+  this);
+}
+
+void AvoidBoundsErrorsCheck::check(const MatchFinder::MatchResult &Result) {
+  const ASTContext &Context = *Result.Context;
+  const SourceManager &Source = Context.getSourceManager();
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("x");
+  const auto *MatchedFunction = Result.Nodes.getNodeAs("f");
+  const auto Type = MatchedFunction->getThisType();
+  if (!isApplicable(Type)) {
+return;
+  }
+
+  // Get original code.
+  const SourceLocation b(MatchedExpr->getBeginLoc());
+  const SourceLocation e(MatchedExpr->getEndLoc());
+  const std::string OriginalCode =
+  Lexer::getSourceText(CharSourceRange::getTokenRange(b, e), Source,
+   getLangOpts())
+  .str();
+  const auto Range = SourceRange(b, e);
+
+  // Build replacement.
+  std::string NewCode = OriginalCode;
+  const auto BeginOpen = NewCode.find("[");
+  NewCode.replace(BeginOpen, 1, ".at(");
+  const auto BeginClose = NewCode.find("]");
+  NewCode.replace(BeginClose, 1, ")");
+
+  diag(MatchedExpr->getBeginLoc(), "Do not use operator[], use at() instead.")
+  << FixItHint::CreateReplacement(Range, NewCode);
+}
+
+} // namespace clang::tidy::cppcoreguidelines
diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
new file mode 100644
index 0..f915729cd7bbe
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
@@ -0,0 +1,32 @@
+//===--- AvoidBoundsErrorsCheck.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 
LLV

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-21 Thread Paul Heidekrüger via cfe-commits

https://github.com/PBHDK updated https://github.com/llvm/llvm-project/pull/95220

From 37292995de0c5aa87408586749795a97468d4725 Mon Sep 17 00:00:00 2001
From: Sebastian Wolf 
Date: Wed, 17 Apr 2024 16:16:35 +0200
Subject: [PATCH 01/21] Enforce SL.con.3: Add check to replace operator[] with
 at() on std containers

---
 .../AvoidBoundsErrorsCheck.cpp| 81 +++
 .../AvoidBoundsErrorsCheck.h  | 32 
 .../cppcoreguidelines/CMakeLists.txt  |  1 +
 .../CppCoreGuidelinesTidyModule.cpp   |  3 +
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 ++
 .../cppcoreguidelines/avoid-bounds-errors.rst | 20 +
 .../docs/clang-tidy/checks/list.rst   |  1 +
 .../cppcoreguidelines/avoid-bounds-errors.cpp | 66 +++
 8 files changed, 209 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-bounds-errors.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-bounds-errors.cpp

diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
new file mode 100644
index 0..524c21b5bdb81
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
@@ -0,0 +1,81 @@
+//===--- AvoidBoundsErrorsCheck.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 "AvoidBoundsErrorsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+#include 
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+bool isApplicable(const QualType &Type) {
+  const auto TypeStr = Type.getAsString();
+  bool Result = false;
+  // Only check for containers in the std namespace
+  if (TypeStr.find("std::vector") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::array") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::deque") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::unordered_map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::flat_map") != std::string::npos) {
+Result = true;
+  }
+  // TODO Add std::span with C++26
+  return Result;
+}
+
+void AvoidBoundsErrorsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  callExpr(callee(cxxMethodDecl(hasName("operator[]")).bind("f")))
+  .bind("x"),
+  this);
+}
+
+void AvoidBoundsErrorsCheck::check(const MatchFinder::MatchResult &Result) {
+  const ASTContext &Context = *Result.Context;
+  const SourceManager &Source = Context.getSourceManager();
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("x");
+  const auto *MatchedFunction = Result.Nodes.getNodeAs("f");
+  const auto Type = MatchedFunction->getThisType();
+  if (!isApplicable(Type)) {
+return;
+  }
+
+  // Get original code.
+  const SourceLocation b(MatchedExpr->getBeginLoc());
+  const SourceLocation e(MatchedExpr->getEndLoc());
+  const std::string OriginalCode =
+  Lexer::getSourceText(CharSourceRange::getTokenRange(b, e), Source,
+   getLangOpts())
+  .str();
+  const auto Range = SourceRange(b, e);
+
+  // Build replacement.
+  std::string NewCode = OriginalCode;
+  const auto BeginOpen = NewCode.find("[");
+  NewCode.replace(BeginOpen, 1, ".at(");
+  const auto BeginClose = NewCode.find("]");
+  NewCode.replace(BeginClose, 1, ")");
+
+  diag(MatchedExpr->getBeginLoc(), "Do not use operator[], use at() instead.")
+  << FixItHint::CreateReplacement(Range, NewCode);
+}
+
+} // namespace clang::tidy::cppcoreguidelines
diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
new file mode 100644
index 0..f915729cd7bbe
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
@@ -0,0 +1,32 @@
+//===--- AvoidBoundsErrorsCheck.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 
LLV

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-21 Thread Paul Heidekrüger via cfe-commits


@@ -0,0 +1,40 @@
+//===--- PreferAtOverSubscriptOperatorCheck.h - clang-tidy --*- C++ 
-*-===//
+//===--- PreferMemberInitializerCheck.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_CPPCOREGUIDELINES_PREFERATOVERSUBSCRIPTOPERATORCHECK_H
+#define 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PREFERATOVERSUBSCRIPTOPERATORCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::cppcoreguidelines {
+
+/// Enforce CPP core guidelines SL.con.3

PBHDK wrote:

> Maybe we can just replace the Doxygen comment above with what's in the 
> release notes + check description right now:
> > Flags the unsafe `operator[]` and suggests replacing it with `at()`.
> 
> What do you think?

@5chmidti just giving this a polite bump in case it got lost 🙂

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() (PR #90043)

2024-06-03 Thread Paul Heidekrüger via cfe-commits

PBHDK wrote:

> I am adding @leunam99 and @PBHDK to the PR, who will contribute in the next 
> few weeks.

Since we cannot push to this PR, we will be submitting a new PR with 
@sebwolf-de's + our work, correct, @EugeneZelenko, @PiotrZSL, @HerrCai0907?

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-08-02 Thread Paul Heidekrüger via cfe-commits


@@ -0,0 +1,137 @@
+//===--- ProBoundsAvoidUncheckedContainerAccesses.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 "ProBoundsAvoidUncheckedContainerAccesses.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+static constexpr std::array SubscriptDefaultExclusions = {
+llvm::StringRef("::std::map"), llvm::StringRef("::std::unordered_map"),
+llvm::StringRef("::std::flat_map")};
+
+ProBoundsAvoidUncheckedContainerAccesses::
+ProBoundsAvoidUncheckedContainerAccesses(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {
+
+  SubscriptExcludedClasses = clang::tidy::utils::options::parseStringList(
+  Options.get("ExcludeClasses", ""));
+  SubscriptExcludedClasses.insert(SubscriptExcludedClasses.end(),
+  SubscriptDefaultExclusions.begin(),
+  SubscriptDefaultExclusions.end());
+}
+
+void ProBoundsAvoidUncheckedContainerAccesses::storeOptions(
+ClangTidyOptions::OptionMap &Opts) {
+
+  if (SubscriptExcludedClasses.size() == SubscriptDefaultExclusions.size()) {
+Options.store(Opts, "ExcludeClasses", "");
+return;
+  }
+
+  // Sum up the sizes of the defaults ( + semicolons), so we can remove them
+  // from the saved options
+  size_t DefaultsStringLength = std::transform_reduce(
+  SubscriptDefaultExclusions.begin(), SubscriptDefaultExclusions.end(),
+  SubscriptDefaultExclusions.size(), std::plus<>(),
+  [](llvm::StringRef Name) { return Name.size(); });
+
+  std::string Serialized = clang::tidy::utils::options::serializeStringList(
+  SubscriptExcludedClasses);
+
+  Options.store(Opts, "ExcludeClasses",
+Serialized.substr(0, Serialized.size() - 
DefaultsStringLength));
+}
+
+static const CXXMethodDecl *
+findAlternative(const CXXMethodDecl *MatchedOperator) {
+  const CXXRecordDecl *Parent = MatchedOperator->getParent();
+  const QualType SubscriptThisObjType =
+  MatchedOperator->getFunctionObjectParameterReferenceType();
+
+  for (const CXXMethodDecl *Method : Parent->methods()) {
+// Require 'Method' to be as accessible as 'MatchedOperator' or more
+if (MatchedOperator->getAccess() < Method->getAccess())
+  continue;
+
+if (MatchedOperator->isConst() != Method->isConst())
+  continue;
+
+const QualType AtThisObjType =
+Method->getFunctionObjectParameterReferenceType();
+if (SubscriptThisObjType != AtThisObjType)
+  continue;
+
+const bool CorrectName = Method->getNameInfo().getAsString() == "at";
+if (!CorrectName)
+  continue;
+
+const bool SameReturnType =
+Method->getReturnType() == MatchedOperator->getReturnType();
+if (!SameReturnType)
+  continue;
+
+const bool SameNumberOfArguments =
+Method->getNumParams() == MatchedOperator->getNumParams();
+if (!SameNumberOfArguments)
+  continue;
+
+for (unsigned ArgInd = 0; ArgInd < Method->getNumParams(); ArgInd++) {
+  const bool SameArgType =
+  Method->parameters()[ArgInd]->getOriginalType() ==
+  MatchedOperator->parameters()[ArgInd]->getOriginalType();
+  if (!SameArgType)
+continue;
+}
+
+return Method;
+  }
+  return nullptr;
+}
+
+void ProBoundsAvoidUncheckedContainerAccesses::registerMatchers(
+MatchFinder *Finder) {
+  Finder->addMatcher(
+  mapAnyOf(cxxOperatorCallExpr, cxxMemberCallExpr)
+  .with(callee(cxxMethodDecl(hasOverloadedOperatorName("[]"),
+ ofClass(cxxRecordDecl(hasMethod(
+ cxxMethodDecl(hasName("at"),
+ unless(matchers::matchesAnyListedName(
+ SubscriptExcludedClasses)))
+   .bind("operator")))
+  .bind("caller"),
+  this);
+}
+
+void ProBoundsAvoidUncheckedContainerAccesses::check(
+const MatchFinder::MatchResult &Result) {
+  const auto *MatchedOperator =
+  Result.Nodes.getNodeAs("operator");
+  const CXXMethodDecl *Alternative = findAlternative(MatchedOperator);
+
+  if (!Alternative)
+return;
+
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("caller");
+
+  diag(MatchedExpr->getBeginLoc(),
+   "found possibly unsafe 'operator[]', consider using 'at()' instead")
+  << MatchedExpr->getSourceRange();
+  diag(Alternative->getBeginLoc(), "alternative 'at()' defined here",
+ 

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-08-02 Thread Paul Heidekrüger via cfe-commits


@@ -0,0 +1,137 @@
+//===--- ProBoundsAvoidUncheckedContainerAccesses.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 "ProBoundsAvoidUncheckedContainerAccesses.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+static constexpr std::array SubscriptDefaultExclusions = {
+llvm::StringRef("::std::map"), llvm::StringRef("::std::unordered_map"),
+llvm::StringRef("::std::flat_map")};
+
+ProBoundsAvoidUncheckedContainerAccesses::
+ProBoundsAvoidUncheckedContainerAccesses(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {
+
+  SubscriptExcludedClasses = clang::tidy::utils::options::parseStringList(
+  Options.get("ExcludeClasses", ""));
+  SubscriptExcludedClasses.insert(SubscriptExcludedClasses.end(),
+  SubscriptDefaultExclusions.begin(),
+  SubscriptDefaultExclusions.end());
+}
+
+void ProBoundsAvoidUncheckedContainerAccesses::storeOptions(
+ClangTidyOptions::OptionMap &Opts) {
+
+  if (SubscriptExcludedClasses.size() == SubscriptDefaultExclusions.size()) {
+Options.store(Opts, "ExcludeClasses", "");
+return;
+  }
+
+  // Sum up the sizes of the defaults ( + semicolons), so we can remove them
+  // from the saved options
+  size_t DefaultsStringLength = std::transform_reduce(
+  SubscriptDefaultExclusions.begin(), SubscriptDefaultExclusions.end(),
+  SubscriptDefaultExclusions.size(), std::plus<>(),
+  [](llvm::StringRef Name) { return Name.size(); });
+
+  std::string Serialized = clang::tidy::utils::options::serializeStringList(
+  SubscriptExcludedClasses);
+
+  Options.store(Opts, "ExcludeClasses",
+Serialized.substr(0, Serialized.size() - 
DefaultsStringLength));
+}
+
+static const CXXMethodDecl *
+findAlternative(const CXXMethodDecl *MatchedOperator) {
+  const CXXRecordDecl *Parent = MatchedOperator->getParent();
+  const QualType SubscriptThisObjType =
+  MatchedOperator->getFunctionObjectParameterReferenceType();
+
+  for (const CXXMethodDecl *Method : Parent->methods()) {
+// Require 'Method' to be as accessible as 'MatchedOperator' or more
+if (MatchedOperator->getAccess() < Method->getAccess())
+  continue;
+
+if (MatchedOperator->isConst() != Method->isConst())
+  continue;
+
+const QualType AtThisObjType =
+Method->getFunctionObjectParameterReferenceType();
+if (SubscriptThisObjType != AtThisObjType)
+  continue;
+
+const bool CorrectName = Method->getNameInfo().getAsString() == "at";

PBHDK wrote:

If I use `const bool CorrectName = Method->getName() == "at";` instead, it 
immediately triggers the assert in `getName()` when running the tests.

Was your suggestion to only use `getName()` when we can and fall back to 
`getNameInfo()->getAsString()` otherwise?

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-08-08 Thread Paul Heidekrüger via cfe-commits


@@ -0,0 +1,124 @@
+//===--- ProBoundsAvoidUncheckedContainerAccesses.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 "ProBoundsAvoidUncheckedContainerAccesses.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+static constexpr std::array SubscriptDefaultExclusions = {
+llvm::StringRef("::std::map"), llvm::StringRef("::std::unordered_map"),
+llvm::StringRef("::std::flat_map")};

PBHDK wrote:

> Should be fine, other option would be to check if at and [] parameters as 
> integers, and do not come from template.

In this case, we would just iterate over all arguments of `operator[]` and 
`at()` call - in C++ 23, there could be multiple - and check if they're 
integers and don't come from a template. This would eliminate the need for 
hard-coded types, correct? However, we would still keep the exclusion list 
mechanism so that users can exclude their custom range-checked subscript 
operator overloads. Do you think this can be easily implemented like this?

> Or other option even better instead of having exclusions list, have inclusion 
> list. and just configure check for std::array, std::vector, std::span, 
> gsl::span, std::deque. That would be better, than trying to exclude some not 
> related types.

There'd still be hard-coded types in this case, but we drastically reduce the 
risk of false positives, correct? However, we would still be missing a lot of 
cases in custom libraries or user-defined overloads of the subscript operator, 
which were explicitly requested in other discussions, IIRC. Would you still 
prefer this over the first suggestion, even though we would be missing cases?

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-08-08 Thread Paul Heidekrüger via cfe-commits


@@ -0,0 +1,124 @@
+//===--- ProBoundsAvoidUncheckedContainerAccesses.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 "ProBoundsAvoidUncheckedContainerAccesses.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+static constexpr std::array SubscriptDefaultExclusions = {
+llvm::StringRef("::std::map"), llvm::StringRef("::std::unordered_map"),
+llvm::StringRef("::std::flat_map")};
+
+ProBoundsAvoidUncheckedContainerAccesses::
+ProBoundsAvoidUncheckedContainerAccesses(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {
+
+  SubscriptExcludedClasses = clang::tidy::utils::options::parseStringList(

PBHDK wrote:

If we were just to rely on the `const` check, we would also be excluding 
std::vectors for instance, because their subscript operator might not be 
`const` either, as it returns a reference. Correct?

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-08-08 Thread Paul Heidekrüger via cfe-commits

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-08-08 Thread Paul Heidekrüger via cfe-commits


@@ -0,0 +1,40 @@
+//===--- ProBoundsAvoidUncheckedContainerAccesses.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_CPPCOREGUIDELINES_PRO_BOUNDS_AVOID_UNCHECKED_CONTAINER_ACCESSES_H
+#define 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_AVOID_UNCHECKED_CONTAINER_ACCESSES_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::cppcoreguidelines {
+
+/// Enforce CPP core guidelines SL.con.3
+///
+/// See
+/// 
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#slcon3-avoid-bounds-errors
+/// For the user-facing documentation see:
+/// 
http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/pro-bounds-avoid-unchecked-container-accesses.html
+class ProBoundsAvoidUncheckedContainerAccesses : public ClangTidyCheck {
+public:
+  ProBoundsAvoidUncheckedContainerAccesses(StringRef Name,
+   ClangTidyContext *Context);
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+return LangOpts.CPlusPlus;
+  }
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+

PBHDK wrote:

> exclude implicit code via TK_IgnoreUnlessSpelledInSource here, like other 
> checks.

This currently breaks the following test case. How should we handle this?

```
std::array a;

template int TestTemplate(T t){
  return t[0];
  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: found possibly unsafe 
'operator[]', consider using 'at()' instead 
[cppcoreguidelines-pro-bounds-avoid-unchecked-container-accesses]

}

auto v = TestTemplate<>(a);

```

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-08-08 Thread Paul Heidekrüger via cfe-commits


@@ -0,0 +1,137 @@
+//===--- ProBoundsAvoidUncheckedContainerAccesses.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 "ProBoundsAvoidUncheckedContainerAccesses.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+static constexpr std::array SubscriptDefaultExclusions = {
+llvm::StringRef("::std::map"), llvm::StringRef("::std::unordered_map"),
+llvm::StringRef("::std::flat_map")};
+
+ProBoundsAvoidUncheckedContainerAccesses::
+ProBoundsAvoidUncheckedContainerAccesses(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {
+
+  SubscriptExcludedClasses = clang::tidy::utils::options::parseStringList(
+  Options.get("ExcludeClasses", ""));
+  SubscriptExcludedClasses.insert(SubscriptExcludedClasses.end(),
+  SubscriptDefaultExclusions.begin(),
+  SubscriptDefaultExclusions.end());
+}
+
+void ProBoundsAvoidUncheckedContainerAccesses::storeOptions(
+ClangTidyOptions::OptionMap &Opts) {
+
+  if (SubscriptExcludedClasses.size() == SubscriptDefaultExclusions.size()) {
+Options.store(Opts, "ExcludeClasses", "");
+return;
+  }
+
+  // Sum up the sizes of the defaults ( + semicolons), so we can remove them
+  // from the saved options
+  size_t DefaultsStringLength = std::transform_reduce(
+  SubscriptDefaultExclusions.begin(), SubscriptDefaultExclusions.end(),
+  SubscriptDefaultExclusions.size(), std::plus<>(),
+  [](llvm::StringRef Name) { return Name.size(); });
+
+  std::string Serialized = clang::tidy::utils::options::serializeStringList(
+  SubscriptExcludedClasses);
+
+  Options.store(Opts, "ExcludeClasses",
+Serialized.substr(0, Serialized.size() - 
DefaultsStringLength));
+}
+
+static const CXXMethodDecl *
+findAlternative(const CXXMethodDecl *MatchedOperator) {
+  const CXXRecordDecl *Parent = MatchedOperator->getParent();
+  const QualType SubscriptThisObjType =
+  MatchedOperator->getFunctionObjectParameterReferenceType();
+
+  for (const CXXMethodDecl *Method : Parent->methods()) {
+// Require 'Method' to be as accessible as 'MatchedOperator' or more
+if (MatchedOperator->getAccess() < Method->getAccess())
+  continue;
+
+if (MatchedOperator->isConst() != Method->isConst())
+  continue;
+
+const QualType AtThisObjType =
+Method->getFunctionObjectParameterReferenceType();
+if (SubscriptThisObjType != AtThisObjType)
+  continue;
+
+const bool CorrectName = Method->getNameInfo().getAsString() == "at";
+if (!CorrectName)
+  continue;
+
+const bool SameReturnType =
+Method->getReturnType() == MatchedOperator->getReturnType();
+if (!SameReturnType)
+  continue;
+
+const bool SameNumberOfArguments =
+Method->getNumParams() == MatchedOperator->getNumParams();
+if (!SameNumberOfArguments)
+  continue;
+
+for (unsigned ArgInd = 0; ArgInd < Method->getNumParams(); ArgInd++) {
+  const bool SameArgType =
+  Method->parameters()[ArgInd]->getOriginalType() ==
+  MatchedOperator->parameters()[ArgInd]->getOriginalType();
+  if (!SameArgType)
+continue;
+}
+
+return Method;
+  }
+  return nullptr;
+}
+
+void ProBoundsAvoidUncheckedContainerAccesses::registerMatchers(
+MatchFinder *Finder) {
+  Finder->addMatcher(
+  mapAnyOf(cxxOperatorCallExpr, cxxMemberCallExpr)
+  .with(callee(cxxMethodDecl(hasOverloadedOperatorName("[]"),
+ ofClass(cxxRecordDecl(hasMethod(
+ cxxMethodDecl(hasName("at"),
+ unless(matchers::matchesAnyListedName(
+ SubscriptExcludedClasses)))
+   .bind("operator")))
+  .bind("caller"),
+  this);
+}
+
+void ProBoundsAvoidUncheckedContainerAccesses::check(
+const MatchFinder::MatchResult &Result) {
+  const auto *MatchedOperator =
+  Result.Nodes.getNodeAs("operator");
+  const CXXMethodDecl *Alternative = findAlternative(MatchedOperator);
+
+  if (!Alternative)
+return;
+
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("caller");
+
+  diag(MatchedExpr->getBeginLoc(),
+   "found possibly unsafe 'operator[]', consider using 'at()' instead")
+  << MatchedExpr->getSourceRange();

PBHDK wrote:

Like this? 

```
4:13: warning: found possibly

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-08-08 Thread Paul Heidekrüger via cfe-commits


@@ -160,6 +160,11 @@ New checks
   Replaces nested ``std::min`` and ``std::max`` calls with an initializer list
   where applicable.
 
+- New :doc:`cppcoreguidelines-pro-bounds-avoid-unchecked-container-accesses

PBHDK wrote:

Are you referring to a double "it" somewhere? I am not seeing the error in line 
163 or line 150?

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-22 Thread Paul Heidekrüger via cfe-commits

https://github.com/PBHDK updated https://github.com/llvm/llvm-project/pull/95220

From 37292995de0c5aa87408586749795a97468d4725 Mon Sep 17 00:00:00 2001
From: Sebastian Wolf 
Date: Wed, 17 Apr 2024 16:16:35 +0200
Subject: [PATCH 01/22] Enforce SL.con.3: Add check to replace operator[] with
 at() on std containers

---
 .../AvoidBoundsErrorsCheck.cpp| 81 +++
 .../AvoidBoundsErrorsCheck.h  | 32 
 .../cppcoreguidelines/CMakeLists.txt  |  1 +
 .../CppCoreGuidelinesTidyModule.cpp   |  3 +
 clang-tools-extra/docs/ReleaseNotes.rst   |  5 ++
 .../cppcoreguidelines/avoid-bounds-errors.rst | 20 +
 .../docs/clang-tidy/checks/list.rst   |  1 +
 .../cppcoreguidelines/avoid-bounds-errors.cpp | 66 +++
 8 files changed, 209 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-bounds-errors.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-bounds-errors.cpp

diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
new file mode 100644
index 0..524c21b5bdb81
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.cpp
@@ -0,0 +1,81 @@
+//===--- AvoidBoundsErrorsCheck.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 "AvoidBoundsErrorsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+#include 
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+bool isApplicable(const QualType &Type) {
+  const auto TypeStr = Type.getAsString();
+  bool Result = false;
+  // Only check for containers in the std namespace
+  if (TypeStr.find("std::vector") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::array") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::deque") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::unordered_map") != std::string::npos) {
+Result = true;
+  }
+  if (TypeStr.find("std::flat_map") != std::string::npos) {
+Result = true;
+  }
+  // TODO Add std::span with C++26
+  return Result;
+}
+
+void AvoidBoundsErrorsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+  callExpr(callee(cxxMethodDecl(hasName("operator[]")).bind("f")))
+  .bind("x"),
+  this);
+}
+
+void AvoidBoundsErrorsCheck::check(const MatchFinder::MatchResult &Result) {
+  const ASTContext &Context = *Result.Context;
+  const SourceManager &Source = Context.getSourceManager();
+  const auto *MatchedExpr = Result.Nodes.getNodeAs("x");
+  const auto *MatchedFunction = Result.Nodes.getNodeAs("f");
+  const auto Type = MatchedFunction->getThisType();
+  if (!isApplicable(Type)) {
+return;
+  }
+
+  // Get original code.
+  const SourceLocation b(MatchedExpr->getBeginLoc());
+  const SourceLocation e(MatchedExpr->getEndLoc());
+  const std::string OriginalCode =
+  Lexer::getSourceText(CharSourceRange::getTokenRange(b, e), Source,
+   getLangOpts())
+  .str();
+  const auto Range = SourceRange(b, e);
+
+  // Build replacement.
+  std::string NewCode = OriginalCode;
+  const auto BeginOpen = NewCode.find("[");
+  NewCode.replace(BeginOpen, 1, ".at(");
+  const auto BeginClose = NewCode.find("]");
+  NewCode.replace(BeginClose, 1, ")");
+
+  diag(MatchedExpr->getBeginLoc(), "Do not use operator[], use at() instead.")
+  << FixItHint::CreateReplacement(Range, NewCode);
+}
+
+} // namespace clang::tidy::cppcoreguidelines
diff --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
new file mode 100644
index 0..f915729cd7bbe
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidBoundsErrorsCheck.h
@@ -0,0 +1,32 @@
+//===--- AvoidBoundsErrorsCheck.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 
LLV

[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-06-26 Thread Paul Heidekrüger via cfe-commits

PBHDK wrote:

> The name sounds nice. Thanks.
> Please address the concerns here and in #90043 to always suggest `at` as 
> well. An option to enable suggesting and providing a fix to use `at` (or 
> `gsl::at`), like others have suggested, sounds like the best option.

Thank you for taking another look as well as your comments. On it!

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2024-09-12 Thread Paul Heidekrüger via cfe-commits

paulhdk wrote:

Hi all,

just giving this a polite bump.
Please do let us know if you have any questions or if there's anything we can 
do to make reviewing easier.

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2025-02-14 Thread Paul Heidekrüger via cfe-commits


@@ -0,0 +1,227 @@
+// RUN: %check_clang_tidy -std=c++2b -check-suffix=DEFAULT %s \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-accesses %t -- \
+// RUN: -config='{CheckOptions: 
{cppcoreguidelines-pro-bounds-avoid-unchecked-container-accesses.ExcludeClasses:
 "::ExcludedClass1;::ExcludedClass2"}}'
+
+// RUN: %check_clang_tidy -std=c++2b -check-suffix=AT %s \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-accesses %t -- \
+// RUN: -config='{CheckOptions: 
{cppcoreguidelines-pro-bounds-avoid-unchecked-container-accesses.ExcludeClasses:
 "::ExcludedClass1;::ExcludedClass2", \
+// RUN: 
cppcoreguidelines-pro-bounds-avoid-unchecked-container-accesses.SubscriptFixMode:
 at}}'
+
+// RUN: %check_clang_tidy -std=c++2b -check-suffix=FUNC %s \
+// RUN: cppcoreguidelines-pro-bounds-avoid-unchecked-container-accesses %t -- \
+// RUN: -config='{CheckOptions: 
{cppcoreguidelines-pro-bounds-avoid-unchecked-container-accesses.ExcludeClasses:
 "::ExcludedClass1;::ExcludedClass2", \
+// RUN: 
cppcoreguidelines-pro-bounds-avoid-unchecked-container-accesses.SubscriptFixMode:
 function, \
+// RUN: 
cppcoreguidelines-pro-bounds-avoid-unchecked-container-accesses.SubscriptFixFunction:
 "f"}}'
+
+namespace std {
+  template
+  struct array {
+T operator[](unsigned i) {
+  return T{1};
+}
+T operator[]() {
+  return T{1};
+}
+T at(unsigned i) {
+  return T{1};
+}
+T at() {
+  return T{1};
+}
+  };
+
+  template
+  struct map {
+T operator[](unsigned i) {
+  return T{1};
+}
+T at(unsigned i) {
+  return T{1};
+}
+  };
+
+  template
+  struct unique_ptr {
+T operator[](unsigned i) {
+  return T{1};
+}
+  };
+
+  template
+  struct span {
+T operator[](unsigned i) {
+  return T{1};
+}
+  };
+} // namespace std
+
+namespace json {
+  template
+  struct node{
+T operator[](unsigned i) {
+  return T{1};
+}
+  };
+} // namespace json
+
+struct SubClass : std::array {};
+
+class ExcludedClass1 {
+  public:
+int operator[](unsigned i) {
+  return 1;
+}
+int at(unsigned i) {
+  return 1;
+}
+};
+
+class ExcludedClass2 {
+  public:
+int operator[](unsigned i) {
+  return 1;
+}
+int at(unsigned i) {
+  return 1;
+}
+};
+
+template int f(T, unsigned){ return 0;}
+template int f(T){ return 0;}
+
+std::array a;
+
+auto b = a[0];
+// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:11: warning: possibly unsafe 
'operator[]', consider bound-safe alternatives 
[cppcoreguidelines-pro-bounds-avoid-unchecked-container-accesses]
+// CHECK-FIXES-AT: auto b = a.at(0);
+// CHECK-FIXES-FUNC: auto b = f(a, 0);
+
+auto b23 = a[];

paulhdk wrote:

https://github.com/llvm/llvm-project/blob/a7be15062a853218f5b577d0c4973d96b66682ee/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-bounds-avoid-unchecked-container-accesses.cpp#L16-L31

We overload `std::array`'s subscript operator in line 22 s.t. that it can be 
called without an index. This should be legal as of C++23. See 
[p2128r5](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2128r5.pdf).
 Also, clang-tidy is giving me the respective warning here: 
https://github.com/llvm/llvm-project/blob/a7be15062a853218f5b577d0c4973d96b66682ee/clang/test/Parser/cxx2b-subscript.cpp?plain=1#L13-L15

What do you think?

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2025-02-17 Thread Paul Heidekrüger via cfe-commits


@@ -0,0 +1,124 @@
+//===--- ProBoundsAvoidUncheckedContainerAccesses.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 "ProBoundsAvoidUncheckedContainerAccesses.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::cppcoreguidelines {
+
+static constexpr std::array SubscriptDefaultExclusions = {
+llvm::StringRef("::std::map"), llvm::StringRef("::std::unordered_map"),
+llvm::StringRef("::std::flat_map")};
+
+ProBoundsAvoidUncheckedContainerAccesses::
+ProBoundsAvoidUncheckedContainerAccesses(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {
+
+  SubscriptExcludedClasses = clang::tidy::utils::options::parseStringList(
+  Options.get("ExcludeClasses", ""));
+  SubscriptExcludedClasses.insert(SubscriptExcludedClasses.end(),
+  SubscriptDefaultExclusions.begin(),
+  SubscriptDefaultExclusions.end());
+}
+
+void ProBoundsAvoidUncheckedContainerAccesses::storeOptions(
+ClangTidyOptions::OptionMap &Opts) {
+
+  if (SubscriptExcludedClasses.size() == SubscriptDefaultExclusions.size()) {
+Options.store(Opts, "ExcludeClasses", "");
+return;
+  }
+
+  // Sum up the sizes of the defaults ( + semicolons), so we can remove them
+  // from the saved options
+  size_t DefaultsStringLength = std::transform_reduce(
+  SubscriptDefaultExclusions.begin(), SubscriptDefaultExclusions.end(),
+  SubscriptDefaultExclusions.size(), std::plus<>(),
+  [](llvm::StringRef Name) { return Name.size(); });
+
+  std::string Serialized = clang::tidy::utils::options::serializeStringList(
+  SubscriptExcludedClasses);
+
+  Options.store(Opts, "ExcludeClasses",
+Serialized.substr(0, Serialized.size() - 
DefaultsStringLength));
+}
+
+const CXXMethodDecl *findAlternative(const CXXRecordDecl *MatchedParent,

paulhdk wrote:

I'm unsure what you are referring to. Does this still apply to the current 
version of the code?

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2025-02-17 Thread Paul Heidekrüger via cfe-commits

paulhdk wrote:

Sorry for letting this sit for long!

I've addressed the most recent comments.

Based on what @leunam99 wrote above, the following questions are still 
unresolved:
* It is still unclear to us how templates should be addressed when suggesting 
fixes.
 For instance, what should happen in this case:
 
https://github.com/llvm/llvm-project/blob/98483ae1581c9a12fc7b4c8b5b64330db8292c29/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-bounds-avoid-unchecked-container-accesses.cpp?plain=1#L176-L184
* Should we worry about the cases where the subscript operator can have 0 
parameters or more than 1 parameter in C++23? At the moment we’re accounting 
for the case where there is no parameter, but don't explicitly handle multiple 
parameters.
* As @carlosgalvezp noted, there are still open comments. I’ve resolved them or 
responded to those that we’re uncertain about. @PiotrZSL, it would be great if 
you could have another look!

Sorry again, for taking so long. 

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


[clang-tools-extra] Enforce SL.con.3: Add check to replace operator[] with at() [Cont.] (PR #95220)

2025-04-06 Thread Paul Heidekrüger via cfe-commits

paulhdk wrote:

Gentle bump. Thank you for taking a look!

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