njames93 updated this revision to Diff 236486.
njames93 added a comment.

I have tried to make the code more robust against macro decls. Also target the 
actual type specifier rather than everything before the name when doing the 
replacements. This should leave any other qualifiers or attributes in tact. The 
test cases have been updated to add checks for using and typedefs alias. There 
are also tests for function pointers and lambdas,  with the current behaviour 
to add pointer qual for function pointer but not for lambdas(as they aren't 
function pointers under the hood). Not sure I want to implement support for 
pointers to pointers as that's not going to help readability(Are you a pointer 
to an array of arrays, array of pointers, pointer to array or pointer to 
pointer). As for the alias whats the correct procedure for creating an alias


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,186 @@
+// RUN: %check_clang_tidy %s readability-qualified-auto %t -- -- -std=c++17
+
+namespace typedefs {
+typedef int *MyPtr;
+typedef int &MyRef;
+typedef const int *CMyPtr;
+typedef const int &CMyRef;
+
+MyPtr getPtr();
+MyRef getRef();
+CMyPtr getCPtr();
+CMyRef getCRef();
+
+void foo() {
+  auto TdNakedPtr = getPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto TdNakedPtr' can be declared as 'auto *TdNakedPtr'
+  // CHECK-FIXES: {{^}}  auto *TdNakedPtr = getPtr();
+  auto &TdNakedRef = getRef();
+  auto TdNakedRefDeref = getRef();
+  auto TdNakedCPtr = getCPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto TdNakedCPtr' can be declared as 'const auto *TdNakedCPtr'
+  // CHECK-FIXES: {{^}}  const auto *TdNakedCPtr = getCPtr();
+  auto &TdNakedCRef = getCRef();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto &TdNakedCRef' can be declared as 'const auto &TdNakedCRef'
+  // CHECK-FIXES: {{^}}  const auto &TdNakedCRef = getCRef();
+  auto TdNakedCRefDeref = getCRef();
+}
+
+}; // namespace typedefs
+
+namespace usings {
+using MyPtr = int *;
+using MyRef = int &;
+using CMyPtr = const int *;
+using CMyRef = const int &;
+
+MyPtr getPtr();
+MyRef getRef();
+CMyPtr getCPtr();
+CMyRef getCRef();
+
+void foo() {
+  auto UNakedPtr = getPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto UNakedPtr' can be declared as 'auto *UNakedPtr'
+  // CHECK-FIXES: {{^}}  auto *UNakedPtr = getPtr();
+  auto &UNakedRef = getRef();
+  auto UNakedRefDeref = getRef();
+  auto UNakedCPtr = getCPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto UNakedCPtr' can be declared as 'const auto *UNakedCPtr'
+  // CHECK-FIXES: {{^}}  const auto *UNakedCPtr = getCPtr();
+  auto &UNakedCRef = getCRef();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto &UNakedCRef' can be declared as 'const auto &UNakedCRef'
+  // CHECK-FIXES: {{^}}  const auto &UNakedCRef = getCRef();
+  auto UNakedCRefDeref = getCRef();
+}
+
+}; // namespace usings
+
+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 NakedPtr' can be declared as 'auto *NakedPtr'
+  // CHECK-FIXES: {{^}}  auto *NakedPtr = getIntPtr();
+  auto NakedCPtr = getCIntPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto NakedCPtr' can be declared as 'const auto *NakedCPtr'
+  // CHECK-FIXES: {{^}}  const auto *NakedCPtr = getCIntPtr();
+
+  const auto ConstPtr = getIntPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'const auto ConstPtr' can be declared as 'auto *const ConstPtr'
+  // CHECK-FIXES: {{^}}  auto *const ConstPtr = getIntPtr();
+  const auto ConstCPtr = getCIntPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'const auto ConstCPtr' can be declared as 'const auto *const ConstCPtr'
+  // CHECK-FIXES: {{^}}  const auto *const ConstCPtr = getCIntPtr();
+
+  auto *QualPtr = getIntPtr();
+  auto *QualCPtr = getCIntPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto *QualCPtr' can be declared as 'const auto *QualCPtr'
+  // CHECK-FIXES: {{^}}  const auto *QualCPtr = getCIntPtr();
+  const auto *ConstQualCPtr = getCIntPtr();
+
+  auto &Ref = *getIntPtr();
+  auto &CRef = *getCIntPtr();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto &CRef' can be declared as 'const auto &CRef'
+  // CHECK-FIXES: {{^}}  const auto &CRef = *getCIntPtr();
+  const auto &ConstCRef = *getCIntPtr();
+
+  if (auto X = getCIntPtr()) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'auto X' can be declared as 'const auto *X'
+    // CHECK-FIXES: {{^}}  if (const auto *X = getCIntPtr()) {
+  }
+  if (auto X = getIntPtr(); X != nullptr) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'auto X' can be declared as 'auto *X'
+    // CHECK-FIXES: {{^}}  if (auto *X = getIntPtr(); X != nullptr) {
+  }
+}
+
+void macroTest() {
+#define _AUTO auto
+#define _CONST const
+  _AUTO AutoMACROPtr = getIntPtr();
+  const _AUTO ConstAutoMacroPtr = getIntPtr();
+  _CONST _AUTO ConstMacroAutoMacroPtr = getIntPtr();
+  _CONST auto ConstMacroAutoPtr = getIntPtr();
+#undef _AUTO
+#undef _CONST
+}
+
+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 &Data' can be declared as 'const auto &Data'
+    // 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 Data' can be declared as 'auto *Data'
+    // CHECK-FIXES: {{^}}  for (auto *Data : Mutate) {
+    change(*Data);
+  }
+  for (auto Data : Constant) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'auto Data' can be declared as 'const auto *Data'
+    // 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);
+}
+
+typedef int *(*functionRetPtr)();
+typedef int (*functionRetVal)();
+
+functionRetPtr getPtrFunction();
+functionRetVal getValFunction();
+
+void baz() {
+  auto MyFunctionPtr = getPtrFunction();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto MyFunctionPtr' can be declared as 'auto *MyFunctionPtr'
+  // CHECK-FIXES: {{^}}  auto *MyFunctionPtr = getPtrFunction();
+  auto MyFunctionVal = getValFunction();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto MyFunctionVal' can be declared as 'auto *MyFunctionVal'
+  // CHECK-FIXES: {{^}}  auto *MyFunctionVal = getValFunction();
+
+  auto LambdaTest = [] { return 0; };
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: 'auto LambdaTest' can be declared as 'auto *LambdaTest'
+  // CHECK-FIXES-NOT: {{^}}  auto *LambdaTest = [] { return 0; };
+}
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,47 @@
+.. 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,215 @@
+//===--- 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"
+#include "../utils/LexerUtils.h"
+#include "llvm/ADT/Optional.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+namespace {
+llvm::Optional<Token> findConstQual(const VarDecl *Decl,
+                                    const MatchFinder::MatchResult &Result) {
+  if (!Decl->getType().isLocalConstQualified())
+    return None;
+
+  // Since either of the locs can be in a macro, use `makeFileCharRange` to be
+  // sure that we have a consistent `CharSourceRange`, located entirely in the
+  // source file.
+
+  auto BeginLoc = Decl->getQualifierLoc().getBeginLoc();
+  if (BeginLoc.isInvalid())
+    BeginLoc = Decl->getBeginLoc();
+
+  SourceLocation EndLoc = Decl->getLocation();
+
+  CharSourceRange FileRange = Lexer::makeFileCharRange(
+      CharSourceRange::getCharRange(BeginLoc, EndLoc), *Result.SourceManager,
+      Result.Context->getLangOpts());
+
+  if (FileRange.isInvalid())
+    return None;
+
+  return utils::lexer::getQualifyingToken(
+      tok::kw_const, FileRange, *Result.Context, *Result.SourceManager);
+}
+
+llvm::Optional<SourceRange>
+getTypeSpecifierLocation(const VarDecl *Var,
+                         const MatchFinder::MatchResult &Result) {
+  SourceRange TypeSpecifier(
+      Var->getTypeSpecStartLoc(),
+      Var->getTypeSpecEndLoc().getLocWithOffset(Lexer::MeasureTokenLength(
+          Var->getTypeSpecEndLoc(), *Result.SourceManager,
+          Result.Context->getLangOpts())));
+
+  if (TypeSpecifier.getBegin().isMacroID() ||
+      TypeSpecifier.getEnd().isMacroID()) {
+    return llvm::None;
+  }
+  return TypeSpecifier;
+}
+
+llvm::Optional<SourceRange> mergeReplacementRange(SourceRange &TypeSpecifier,
+                                                  const Token &ConstToken) {
+  if (TypeSpecifier.getBegin().getLocWithOffset(-1) == ConstToken.getEndLoc()) {
+    TypeSpecifier.setBegin(ConstToken.getLocation());
+    return llvm::None;
+  } else if (TypeSpecifier.getEnd().getLocWithOffset(1) ==
+             ConstToken.getLocation()) {
+    TypeSpecifier.setEnd(ConstToken.getEndLoc());
+    return llvm::None;
+  }
+  return SourceRange(ConstToken.getLocation(), ConstToken.getEndLoc());
+}
+
+bool isPointerConst(QualType QType) {
+  return QType.getTypePtr()->getPointeeType().isConstQualified();
+}
+bool isAutoPointerConst(QualType QType) {
+  return dyn_cast<AutoType>(QType.getTypePtr()->getPointeeType().getTypePtr())
+      ->getDeducedType()
+      .isConstQualified();
+}
+
+} // namespace
+
+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);
+}
+
+void QualifiedAutoCheck::check(const MatchFinder::MatchResult &Result) {
+  if (auto Var = Result.Nodes.getNodeAs<VarDecl>("auto")) {
+    bool IsPtrConst = isPointerConst(Var->getType());
+
+    SourceRange TypeSpecifier;
+    if (auto TypeSpec = getTypeSpecifierLocation(Var, Result)) {
+      TypeSpecifier = *TypeSpec;
+    } else {
+      return;
+    }
+
+    bool IsLocalConst = Var->getType().isLocalConstQualified();
+    llvm::Optional<SourceRange> RemoveConstRange;
+    if (IsLocalConst) {
+      llvm::Optional<Token> ConstToken = findConstQual(Var, Result);
+      if (!ConstToken || ConstToken->getLocation().isMacroID()) {
+        return;
+      }
+      RemoveConstRange = mergeReplacementRange(TypeSpecifier, *ConstToken);
+    }
+
+    // Check for bridging the gap between the asterisk and name.
+    if (Var->getLocation() == TypeSpecifier.getEnd().getLocWithOffset(1))
+      TypeSpecifier.setEnd(TypeSpecifier.getEnd().getLocWithOffset(1));
+
+    CharSourceRange FixItRange = CharSourceRange::getCharRange(TypeSpecifier);
+    if (FixItRange.isInvalid())
+      return;
+
+    SourceLocation FixitLoc =
+        RemoveConstRange
+            ? std::min(RemoveConstRange->getBegin(), FixItRange.getBegin())
+            : FixItRange.getBegin();
+
+    llvm::StringRef ReplStr =
+        IsPtrConst ? (IsLocalConst ? "const auto *const " : "const auto *")
+                   : (IsLocalConst ? "auto *const " : "auto *");
+
+    DiagnosticBuilder Diag =
+        diag(FixitLoc, "'%0auto %1' can be declared as '%2%1'")
+        << (IsLocalConst ? "const " : "") << Var->getName() << ReplStr;
+    if (RemoveConstRange)
+      Diag << FixItHint::CreateRemoval(CharSourceRange::getCharRange(
+          RemoveConstRange->getBegin(), RemoveConstRange->getEnd()));
+    Diag << FixItHint::CreateReplacement(FixItRange, ReplStr);
+    return;
+  }
+  if (auto Var = Result.Nodes.getNodeAs<VarDecl>("auto_ptr")) {
+    if (!isPointerConst(Var->getType()))
+      return; // Pointer isn't const, no need to add const qualifier.
+    if (!isAutoPointerConst(Var->getType()))
+      // Const isnt wrapped in the auto type, so must be declared explicitly.
+      return;
+
+    if (Var->getType().isLocalConstQualified()) {
+      llvm::Optional<Token> ConstToken = findConstQual(Var, Result);
+      if (!ConstToken || ConstToken->getLocation().isMacroID()) {
+        return;
+      }
+    }
+
+    CharSourceRange FixItRange;
+    if (auto TypeSpec = getTypeSpecifierLocation(Var, Result)) {
+      FixItRange = CharSourceRange::getCharRange(*TypeSpec);
+      if (FixItRange.isInvalid())
+        return;
+    } else {
+      return;
+    }
+
+    DiagnosticBuilder Diag =
+        diag(FixItRange.getBegin(),
+             "'auto *%0' can be declared as 'const auto *%0'")
+        << Var->getName();
+    Diag << FixItHint::CreateReplacement(FixItRange,
+                                         Var->getType().isLocalConstQualified()
+                                             ? "const auto *const "
+                                             : "const auto *");
+    return;
+  }
+  if (auto Var = Result.Nodes.getNodeAs<VarDecl>("auto_ref")) {
+    if (!isPointerConst(Var->getType()))
+      return; // Pointer isn't const, no need to add const qualifier.
+    if (!isAutoPointerConst(Var->getType()))
+      // Const isnt wrapped in the auto type, so must be declared explicitly.
+      return;
+
+    CharSourceRange FixItRange;
+    if (auto TypeSpec = getTypeSpecifierLocation(Var, Result)) {
+      FixItRange = CharSourceRange::getCharRange(*TypeSpec);
+      if (FixItRange.isInvalid())
+        return;
+    } else {
+      return;
+    }
+
+    DiagnosticBuilder Diag =
+        diag(FixItRange.getBegin(),
+             "'auto &%0' can be declared as 'const auto &%0'")
+        << Var->getName();
+    Diag << 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