njames93 updated this revision to Diff 236255.
njames93 marked 13 inline comments as done.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D72217/new/

https://reviews.llvm.org/D72217

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
  clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability-qualified-auto.rst
  clang-tools-extra/test/clang-tidy/checkers/readability-qualified-auto.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-qualified-auto.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-qualified-auto.cpp
@@ -0,0 +1,100 @@
+// RUN: %check_clang_tidy %s readability-qualified-auto %t -- -- -std=c++17
+
+int getInt();
+int *getIntPtr();
+const int *getCIntPtr();
+
+void foo() {
+  // make sure check disregards named types
+  int TypedInt = getInt();
+  int *TypedPtr = getIntPtr();
+  const int *TypedConstPtr = getCIntPtr();
+  int &TypedRef = *getIntPtr();
+  const int &TypedConstRef = *getCIntPtr();
+
+  // make sure check disregards auto types that aren't pointers or references
+  auto AutoInt = getInt();
+
+  auto NakedPtr = getIntPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto variable' can be declared as an 'auto pointer'
+  // CHECK-FIXES: {{^}}  auto * NakedPtr = getIntPtr();
+  auto NakedCPtr = getCIntPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto variable' can be declared as a 'const auto pointer'
+  // CHECK-FIXES: {{^}}  const auto * NakedCPtr = getCIntPtr();
+
+  const auto ConstPtr = getIntPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto variable' can be declared as an 'auto pointer'
+  // CHECK-FIXES: {{^}}  auto *const  ConstPtr = getIntPtr();
+  const auto ConstCPtr = getCIntPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto variable' can be declared as a 'const auto pointer'
+  // CHECK-FIXES: {{^}}  const auto *const  ConstCPtr = getCIntPtr();
+
+  auto *QualPtr = getIntPtr();
+  auto *QualCPtr = getCIntPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto pointer' can be declared as a 'const auto pointer'
+  // CHECK-FIXES: {{^}}  const auto *QualCPtr = getCIntPtr();
+  const auto *ConstQualCPtr = getCIntPtr();
+
+  auto &Ref = *getIntPtr();
+  auto &CRef = *getCIntPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto reference' can be declared as a 'const auto reference'
+  // CHECK-FIXES: {{^}}  const auto &CRef = *getCIntPtr();
+  const auto &ConstCRef = *getCIntPtr();
+
+  if (auto X = getCIntPtr()) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'auto variable' can be declared as a 'const auto pointer'
+    // CHECK-FIXES: {{^}}  if (const auto * X = getCIntPtr()) {
+  }
+  if (auto X = getIntPtr(); X != nullptr) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'auto variable' can be declared as an 'auto pointer'
+    // CHECK-FIXES: {{^}}  if (auto * X = getIntPtr(); X != nullptr) {
+  }
+}
+
+namespace std {
+template <typename T>
+class vector { // dummy impl
+  T _data[1];
+
+public:
+  T *begin() { return _data; }
+  const T *begin() const { return _data; }
+  T *end() { return &_data[1]; }
+  const T *end() const { return &_data[1]; }
+};
+} // namespace std
+
+void change(int &);
+void observe(const int &);
+
+void loopRef(std::vector<int> &Mutate, const std::vector<int> &Constant) {
+  for (auto &Data : Mutate) {
+    change(Data);
+  }
+  for (auto &Data : Constant) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'auto reference' can be declared as a 'const auto reference'
+    // CHECK-FIXES: {{^}}  for (const auto &Data : Constant) {
+    observe(Data);
+  }
+}
+
+void loopPtr(const std::vector<int *> &Mutate, const std::vector<const int *> &Constant) {
+  for (auto Data : Mutate) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'auto variable' can be declared as an 'auto pointer'
+    // CHECK-FIXES: {{^}}  for (auto * Data : Mutate) {
+    change(*Data);
+  }
+  for (auto Data : Constant) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'auto variable' can be declared as a 'const auto pointer'
+    // CHECK-FIXES: {{^}}  for (const auto * Data : Constant) {
+    observe(*Data);
+  }
+}
+
+void bar() {
+  std::vector<int> Vec;
+  std::vector<int *> PtrVec;
+  std::vector<const int *> CPtrVec;
+  loopRef(Vec, Vec);
+  loopPtr(PtrVec, CPtrVec);
+}
Index: clang-tools-extra/docs/clang-tidy/checks/readability-qualified-auto.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/readability-qualified-auto.rst
@@ -0,0 +1,48 @@
+.. title:: clang-tidy - readability-qualified-auto
+
+readability-qualified-auto
+==========================
+
+Adds pointer and const qualifications to auto typed variables  that are deduced
+to pointers and const pointers.
+`LLVM Coding Standards <https://llvm.org/docs/CodingStandards.html>`_ advises to
+make it obvious if a auto typed variable is a pointer, constant pointer or 
+constant reference. This check will transform ``auto`` to ``auto *`` when the 
+type is deduced to be a pointer, as well as adding ``const`` when applicable to
+auto pointers or references
+
+.. code-block:: c++
+
+  for (auto &Data : MutatableContainer) {
+    change(Data);
+  }
+  for (auto &Data : ConstantContainer) {
+    observe(Data);
+  }
+  for (auto Data : MutatablePtrContainer) {
+    change(*Data);
+  }
+  for (auto Data : ConstantPtrContainer) {
+    observe(*Data);
+  }
+
+Would be transformed into:
+
+.. code-block:: c++
+
+  for (auto &Data : MutatableContainer) {
+    change(Data);
+  }
+  for (const auto &Data : ConstantContainer) {
+    observe(Data);
+  }
+  for (auto *Data : MutatablePtrContainer) {
+    change(*Data);
+  }
+  for (const auto *Data : ConstantPtrContainer) {
+    observe(*Data);
+  }
+
+
+This check helps to enforce this `LLVM Coding Standards recommendation
+<https://llvm.org/docs/CodingStandards.html#beware-unnecessary-copies-with-auto>`_.
Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -264,6 +264,7 @@
    `readability-misplaced-array-index <readability-misplaced-array-index.html>`_, "Yes"
    `readability-named-parameter <readability-named-parameter.html>`_, "Yes"
    `readability-non-const-parameter <readability-non-const-parameter.html>`_, "Yes"
+   `readability-qualified-auto <readability-qualified-auto.html>`_, "Yes"
    `readability-redundant-access-specifiers <readability-redundant-access-specifiers.html>`_, "Yes"
    `readability-redundant-control-flow <readability-redundant-control-flow.html>`_, "Yes"
    `readability-redundant-declaration <readability-redundant-declaration.html>`_, "Yes"
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -173,6 +173,12 @@
   <clang-tidy/checks/modernize-use-equals-default>` fix no longer adds
   semicolons where they would be redundant.
 
+- New :doc:`readability-qualified-auto
+  <clang-tidy/checks/readability-qualified-auto>` check.
+
+  Adds pointer and const qualifications to auto typed variables 
+  that are deduced to pointers and const pointers.
+
 - New :doc:`readability-redundant-access-specifiers
   <clang-tidy/checks/readability-redundant-access-specifiers>` check.
 
Index: clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -28,6 +28,7 @@
 #include "MisplacedArrayIndexCheck.h"
 #include "NamedParameterCheck.h"
 #include "NonConstParameterCheck.h"
+#include "QualifiedAutoCheck.h"
 #include "RedundantAccessSpecifiersCheck.h"
 #include "RedundantControlFlowCheck.h"
 #include "RedundantDeclarationCheck.h"
@@ -86,6 +87,8 @@
         "readability-misleading-indentation");
     CheckFactories.registerCheck<MisplacedArrayIndexCheck>(
         "readability-misplaced-array-index");
+    CheckFactories.registerCheck<QualifiedAutoCheck>(
+        "readability-qualified-auto");
     CheckFactories.registerCheck<RedundantAccessSpecifiersCheck>(
         "readability-redundant-access-specifiers");
     CheckFactories.registerCheck<RedundantFunctionPtrDereferenceCheck>(
Index: clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h
@@ -0,0 +1,36 @@
+//===--- QualifiedAutoCheck.h - clang-tidy ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_QUALIFIEDAUTOCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_QUALIFIEDAUTOCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Finds variables declared as auto that could be declared as:
+/// 'auto*' or 'const auto *' and reference variables declared as:
+/// 'const auto &'.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-qualified-auto.html
+class QualifiedAutoCheck : public ClangTidyCheck {
+public:
+  QualifiedAutoCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_QUALIFIEDAUTOCHECK_H
Index: clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
@@ -0,0 +1,107 @@
+//===--- QualifiedAutoCheck.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 "QualifiedAutoCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) {
+  if (!getLangOpts().CPlusPlus)
+    return; // Auto deduction not used in 'C', so don't register Matchers.
+  auto ExplicitSingleVarDecl =
+      [](const ast_matchers::internal::Matcher<VarDecl> &InnerMatcher,
+         llvm::StringRef ID) {
+        return declStmt(hasSingleDecl(
+            varDecl(unless(isImplicit()), InnerMatcher).bind(ID)));
+      };
+  Finder->addMatcher(
+      ExplicitSingleVarDecl(hasType(autoType(hasDeducedType(pointerType()))),
+                            "auto"),
+      this);
+  Finder->addMatcher(ExplicitSingleVarDecl(
+                         hasType(pointerType(pointee(autoType()))), "auto_ptr"),
+                     this);
+  Finder->addMatcher(
+      ExplicitSingleVarDecl(hasType(lValueReferenceType(pointee(autoType()))),
+                            "auto_ref"),
+      this);
+}
+
+SourceLocation getTokLocationBeforeName(const NamedDecl *Decl) {
+  return DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
+      .getBeginLoc()
+      .getLocWithOffset(-1);
+}
+
+CharSourceRange getFixitRange(const VarDecl *Var) {
+  return CharSourceRange::getTokenRange(Var->getBeginLoc(),
+                                        getTokLocationBeforeName(Var));
+}
+
+void QualifiedAutoCheck::check(const MatchFinder::MatchResult &Result) {
+  if (auto Var = Result.Nodes.getNodeAs<VarDecl>("auto")) {
+    bool IsPtrConst =
+        Var->getType().getTypePtr()->getPointeeType().isConstQualified();
+    CharSourceRange FixItRange = getFixitRange(Var);
+    DiagnosticBuilder Diag =
+        diag(FixItRange.getBegin(), "'auto variable' can be declared as %0'")
+        << (IsPtrConst ? "a 'const auto pointer" : "an 'auto pointer");
+    if (Var->getType().isConstQualified()) {
+      Diag << FixItHint::CreateReplacement(
+          FixItRange, IsPtrConst ? "const auto *const " : "auto *const ");
+    } else {
+      Diag << FixItHint::CreateReplacement(
+          FixItRange, IsPtrConst ? "const auto *" : "auto *");
+    }
+    return;
+  }
+  if (auto Var = Result.Nodes.getNodeAs<VarDecl>("auto_ptr")) {
+    if (!Var->getType().getTypePtr()->getPointeeType().isConstQualified())
+      return; // Pointer isn't const, no need to add const qualifier.
+    bool IsAutoPtrConst =
+        dyn_cast<AutoType>(
+            Var->getType().getTypePtr()->getPointeeType().getTypePtr())
+            ->getDeducedType()
+            .isConstQualified();
+    if (!IsAutoPtrConst)
+      return;
+    CharSourceRange FixItRange = getFixitRange(Var);
+    DiagnosticBuilder Diag =
+        diag(FixItRange.getBegin(),
+             "'auto pointer' can be declared as a 'const auto pointer'");
+    if (Var->getType().isConstQualified())
+      Diag << FixItHint::CreateReplacement(FixItRange, "const auto *const ");
+    else
+      Diag << FixItHint::CreateReplacement(FixItRange, "const auto *");
+    return;
+  }
+  if (auto Var = Result.Nodes.getNodeAs<VarDecl>("auto_ref")) {
+    if (!Var->getType().getTypePtr()->getPointeeType().isConstQualified())
+      return; // Reference isn't const, no need to add const qualifier.
+    bool IsAutoRefConst =
+        dyn_cast<AutoType>(
+            Var->getType().getTypePtr()->getPointeeType().getTypePtr())
+            ->getDeducedType()
+            .isConstQualified();
+    if (!IsAutoRefConst)
+      return;
+    CharSourceRange FixItRange = getFixitRange(Var);
+    diag(FixItRange.getBegin(),
+         "'auto reference' can be declared as a 'const auto reference'")
+        << FixItHint::CreateReplacement(FixItRange, "const auto &");
+    return;
+  }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/clang-tidy/readability/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -21,6 +21,7 @@
   NamedParameterCheck.cpp
   NamespaceCommentCheck.cpp
   NonConstParameterCheck.cpp
+  QualifiedAutoCheck.cpp
   ReadabilityTidyModule.cpp
   RedundantAccessSpecifiersCheck.cpp
   RedundantControlFlowCheck.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to