njames93 updated this revision to Diff 236617.
njames93 added a comment.
Added docs for const and volatile qualifiers
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,205 @@
+// 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();
+
+
+ volatile auto VolatilePtr = getIntPtr();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'volatile auto VolatilePtr' can be declared as 'auto *volatile VolatilePtr'
+ // CHECK-FIXES: {{^}} auto *volatile VolatilePtr = getIntPtr();
+ volatile auto VolatileCPtr = getCIntPtr();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'volatile auto VolatileCPtr' can be declared as 'const auto *volatile VolatileCPtr'
+ // CHECK-FIXES: {{^}} const auto *volatile VolatileCPtr = 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();
+ auto *const ConstantQualCPtr = getCIntPtr();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto *const ConstantQualCPtr' can be declared as 'const auto *const ConstantQualCPtr'
+ // CHECK-FIXES: {{^}} const auto *const ConstantQualCPtr = getCIntPtr();
+ auto *volatile VolatileQualCPtr = getCIntPtr();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto *volatile VolatileQualCPtr' can be declared as 'const auto *volatile VolatileQualCPtr'
+ // CHECK-FIXES: {{^}} const auto *volatile VolatileQualCPtr = 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-NOT: :[[@LINE-1]]:3: warning: 'auto MyFunctionPtr' can be declared as 'auto *MyFunctionPtr'
+ // CHECK-FIXES-NOT: {{^}} auto *MyFunctionPtr = getPtrFunction();
+ auto MyFunctionVal = getValFunction();
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: 'auto MyFunctionVal' can be declared as 'auto *MyFunctionVal'
+ // CHECK-FIXES-NOT: {{^}} 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; };
+
+ auto LambdaTest2 = +[] { return 0; };
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: 'auto LambdaTest2' can be declared as 'auto *LambdaTest2'
+ // CHECK-FIXES-NOT: {{^}} auto *LambdaTest2 = +[] { 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,63 @@
+.. 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);
+ }
+
+Note const volatile qualified types will retain their const and volatile qualifiers.
+
+.. code-block:: c++
+
+ const auto Foo = cast<int *>(Baz1);
+ const auto Bar = cast<const int *>(Baz2);
+ volatile auto FooBar = cast<int*>(Baz3);
+
+Would be transformed into:
+
+.. code-block:: c++
+
+ auto *const Foo = cast<int *>(Baz1);
+ const auto *const Bar = cast<const int *>(Baz2);
+ auto *volatile FooBar = cast<int*>(Baz3);
+
+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,257 @@
+//===--- 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 {
+enum class Qualifier {
+ Const,
+ Volatile // Ignore restrict as not c++ keyword.
+};
+
+llvm::Optional<Token> findQualToken(const VarDecl *Decl, Qualifier Qual,
+ const MatchFinder::MatchResult &Result) {
+ // 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.
+
+ assert(Qual == Qualifier::Const ||
+ Qual == Qualifier::Volatile && "Invalid Qualifier");
+
+ tok::TokenKind Tok =
+ Qual == Qualifier::Const ? tok::kw_const : tok::kw_volatile;
+
+ SourceLocation 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, 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(pointee(unless(functionType())))))),
+ "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 (llvm::Optional<SourceRange> TypeSpec =
+ getTypeSpecifierLocation(Var, Result)) {
+ TypeSpecifier = *TypeSpec;
+ } else {
+ return;
+ }
+
+ llvm::SmallVector<SourceRange, 2> RemoveQualifiersRange;
+ auto CheckQualifier = [&](bool IsPresent, Qualifier Qual) {
+ if (IsPresent) {
+ llvm::Optional<Token> Token = findQualToken(Var, Qual, Result);
+ if (!Token || Token->getLocation().isMacroID()) {
+ return true; // Disregard this VarDecl.
+ }
+ if (llvm::Optional<SourceRange> Result =
+ mergeReplacementRange(TypeSpecifier, *Token)) {
+ RemoveQualifiersRange.push_back(*Result);
+ }
+ }
+ return false;
+ };
+
+ bool IsLocalConst = Var->getType().isLocalConstQualified();
+ bool IsLocalVolatile = Var->getType().isLocalVolatileQualified();
+
+ if (CheckQualifier(IsLocalConst, Qualifier::Const))
+ return;
+ if (CheckQualifier(IsLocalVolatile, Qualifier::Volatile))
+ return;
+
+ // 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 = FixItRange.getBegin();
+ for (SourceRange &Range : RemoveQualifiersRange) {
+ if (Range.getBegin() < FixitLoc) {
+ FixitLoc = Range.getBegin();
+ }
+ }
+
+ std::string ReplStr = [&] {
+ llvm::StringRef PtrConst = IsPtrConst ? "const " : "";
+ llvm::StringRef LocalConst = IsLocalConst ? "const " : "";
+ llvm::StringRef LocalVol = IsLocalVolatile ? "volatile " : "";
+ return (PtrConst + "auto *" + LocalConst + LocalVol).str();
+ }();
+
+ DiagnosticBuilder Diag =
+ diag(FixitLoc, "'%0%1auto %2' can be declared as '%3%2'")
+ << (IsLocalConst ? "const " : "")
+ << (IsLocalVolatile ? "volatile " : "") << Var->getName() << ReplStr;
+
+ for (SourceRange &Range : RemoveQualifiersRange) {
+ Diag << FixItHint::CreateRemoval(
+ CharSourceRange::getCharRange(Range.getBegin(), Range.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> Token =
+ findQualToken(Var, Qualifier::Const, Result);
+ if (!Token || Token->getLocation().isMacroID()) {
+ return;
+ }
+ }
+ if (Var->getType().isLocalVolatileQualified()) {
+ llvm::Optional<Token> Token =
+ findQualToken(Var, Qualifier::Volatile, Result);
+ if (!Token || Token->getLocation().isMacroID()) {
+ return;
+ }
+ }
+
+ CharSourceRange FixItRange;
+ if (llvm::Optional<SourceRange> TypeSpec =
+ getTypeSpecifierLocation(Var, Result)) {
+ FixItRange = CharSourceRange::getCharRange(*TypeSpec);
+ if (FixItRange.isInvalid())
+ return;
+ } else {
+ return;
+ }
+
+ DiagnosticBuilder Diag =
+ diag(FixItRange.getBegin(),
+ "'auto *%0%1%2' can be declared as 'const auto *%0%1%2'")
+ << (Var->getType().isLocalConstQualified() ? "const " : "")
+ << (Var->getType().isLocalVolatileQualified() ? "volatile " : "")
+ << Var->getName();
+ Diag << FixItHint::CreateReplacement(FixItRange, "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 (llvm::Optional<SourceRange> 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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits