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 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,117 @@ +//===--- 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) { + // auto deduction not used in c + return; + } + auto ExplicitSingleVarDecl = + [](const ast_matchers::internal::Matcher &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("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("auto_ptr")) { + + if (!Var->getType().getTypePtr()->getPointeeType().isConstQualified()) { + // Pointer isn't const, no need to add const qualifier + return; + } + bool IsAutoPtrConst = + dyn_cast( + 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("auto_ref")) { + if (!Var->getType().getTypePtr()->getPointeeType().isConstQualified()) { + // Reference isn't const, no need to add const qualifier + return; + } + bool IsAutoRefConst = + dyn_cast( + 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/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( "readability-misplaced-array-index"); + CheckFactories.registerCheck( + "readability-qualified-auto"); CheckFactories.registerCheck( "readability-redundant-access-specifiers"); CheckFactories.registerCheck( Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -173,6 +173,12 @@ ` fix no longer adds semicolons where they would be redundant. +- New :doc:`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 ` check. 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 `_, "Yes" `readability-named-parameter `_, "Yes" `readability-non-const-parameter `_, "Yes" + `readability-qualified-auto `_, "Yes" `readability-redundant-access-specifiers `_, "Yes" `readability-redundant-control-flow `_, "Yes" `readability-redundant-declaration `_, "Yes" 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,45 @@ +.. title:: clang-tidy - readability-qualified-auto + +readability-qualified-auto +========================== + +`LLVM Coding Standards `_ 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 +`_. 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 +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 &Mutate, const std::vector &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 &Mutate, const std::vector &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 Vec; + std::vector PtrVec; + std::vector CPtrVec; + loopRef(Vec, Vec); + loopPtr(PtrVec, CPtrVec); +}