diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -9,6 +9,7 @@ ConcatNestedNamespacesCheck.cpp DeprecatedHeadersCheck.cpp DeprecatedIosBaseAliasesCheck.cpp + DeprecatedIteratorBaseCheck.cpp LoopConvertCheck.cpp LoopConvertUtils.cpp MakeSharedCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/DeprecatedIteratorBaseCheck.h b/clang-tools-extra/clang-tidy/modernize/DeprecatedIteratorBaseCheck.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/DeprecatedIteratorBaseCheck.h @@ -0,0 +1,35 @@ +//===--- DeprecatedIteratorBaseCheck.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_MODERNIZE_DEPRECATEDITERATORBASECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_DEPRECATEDITERATORBASECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace modernize { + +/// Finds deprecated in C++17 inheritance from `std::iterator` and replaces it +/// with type aliases. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-deprecated-iterator-base.html +class DeprecatedIteratorBaseCheck : public ClangTidyCheck { +public: + DeprecatedIteratorBaseCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace modernize +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_DEPRECATEDITERATORBASECHECK_H diff --git a/clang-tools-extra/clang-tidy/modernize/DeprecatedIteratorBaseCheck.cpp b/clang-tools-extra/clang-tidy/modernize/DeprecatedIteratorBaseCheck.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/DeprecatedIteratorBaseCheck.cpp @@ -0,0 +1,322 @@ +//===--- DeprecatedIteratorBaseCheck.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 "DeprecatedIteratorBaseCheck.h" +#include "../utils/LexerUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "llvm/ADT/Sequence.h" + +using namespace clang::ast_matchers; +using namespace clang::tidy::utils::lexer; + +namespace clang { +namespace tidy { +namespace modernize { + +/// Returns the first child of the CXXRecordDecl +static const Decl *getTopDecl(const CXXRecordDecl &RD) { + auto It = RD.decls_begin(); + // The first decl of CXXRecordDecl is self-reference, skip it + assert(It->getKind() == Decl::CXXRecord && "expecting self-reference"); + ++It; + return It != RD.decls_end() ? *It : nullptr; +} + +/// Returns an AccessSpecDecl if it is the first child of the CXXRecordDecl +static const AccessSpecDecl *getTopAccSpecDecl(const CXXRecordDecl &RD) { + return dyn_cast_or_null(getTopDecl(RD)); +} + +/// Returns an AccessSpecDecl child of the DeclContext, if any +static const AccessSpecDecl *getAnyAccSpecDecl(const DeclContext &DC) { + for (const Decl *D : DC.decls()) + if (auto const *ASD = dyn_cast(D)) + return ASD; + return nullptr; +} + +/// Returns a non-AccessSpecDecl child of the CXXRecordDecl, if any +static const Decl *getAnyNonAccSpecDecl(const CXXRecordDecl &RD) { + auto It = RD.decls_begin(); + // The first decl of CXXRecordDecl is self-reference, skip it + assert(It->getKind() == Decl::CXXRecord && "expecting self-reference"); + ++It; + for (; It != RD.decls_end(); ++It) + if (It->getKind() != Decl::AccessSpec) + return *It; + return nullptr; +} + +/// Returns default visibility for the TagDecl children +static AccessSpecifier defaultAccessSpecifierFor(const TagDecl &TD) { + switch (TD.getTagKind()) { + case TTK_Struct: + return AS_public; + case TTK_Class: + return AS_private; + default: + llvm_unreachable("unexpected tag kind"); + } +} + +/// Returns a base removal fixit +static FixItHint createBaseRemoval(const CXXRecordDecl &RD, + const CXXBaseSpecifier &Base, + const SourceManager &SM, + const LangOptions &LangOpts) { + SourceRange R = Base.getSourceRange(); + if (RD.getNumBases() == 1) { + // class RD : public Base { + // ^^^^^^^^^^^^^^ + // TODO: Is there a way to get the location without lexer gymnastics? + SourceLocation Colon = + findPreviousTokenKind(R.getBegin(), SM, LangOpts, tok::colon); + Token Tok = getPreviousToken(Colon, SM, LangOpts, /*SkipComments=*/true); + assert(!Tok.is(tok::unknown)); + R.setBegin(Lexer::getLocForEndOfToken(Tok.getLocation(), 0, SM, LangOpts)); + } else if (RD.bases_end() - 1 == &Base) { + // class RD : ... , public Base { + // ^^^^^^^^^^^^^^ + SourceLocation Loc = (RD.bases_end() - 2)->getEndLoc(); + R.setBegin(Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts)); + } else { + // class RD : ... , public Base, ... { + // ^^^^^^^^^^^^^ + auto It = + llvm::find_if(RD.bases(), [&Base](const CXXBaseSpecifier &Candidate) { + return &Candidate == &Base; + }); + R.setEnd(std::next(It)->getBeginLoc().getLocWithOffset(-1)); + } + return FixItHint::CreateRemoval(R); +} + +/// Returns an aliases insertion location for the CXXRecordDecl +static SourceLocation getInsertLoc(const CXXRecordDecl &RD) { + const AccessSpecDecl *TopAS = getTopAccSpecDecl(RD); + if (TopAS && TopAS->getAccessUnsafe() == AS_public) { + // class/struct { + // public: + // ^ + return TopAS->getColonLoc().getLocWithOffset(1); + } else { + // class/struct { + // ^ + return RD.getBraceRange().getBegin().getLocWithOffset(1); + } +} + +static bool isOpeningRequired(const CXXRecordDecl &RD) { + const AccessSpecDecl *TopAS = getTopAccSpecDecl(RD); + if (TopAS && TopAS->getAccessUnsafe() == AS_public) { + // class/struct { + // public: + // ^^^^^^^ + // Public access specifier is already at the top + return false; + } + if (RD.isStruct()) { + // struct : public ... { + // public: vvvvvv + // ^^^^^^^<<<<<<<< + // When a user types public access specifier for a struct base + // it is highly likely to also find it at the struct body top + for (const CXXBaseSpecifier &Base : RD.bases()) + switch (Base.getAccessSpecifierAsWritten()) { + case AS_public: + return true; + case AS_none: + return false; + default: + break; + } + } + return defaultAccessSpecifierFor(RD) != AS_public; +} + +static bool isClosingRequired(const CXXRecordDecl &RD) { + if (getTopAccSpecDecl(RD)) { + // class/struct { + // public/private/protected: + // ^^^^^^^^^^^^^^^^^^^^^^^^^ + // No need to emit a closing access specifier because there is already one + return false; + } else { + return defaultAccessSpecifierFor(RD) != AS_public; + } +} + +static TemplateSpecializationTypeLoc getTSTLoc(TypeLoc TL) { + if (auto TSTL = TL.getAsAdjusted()) + return TSTL; + if (auto TDTL = TL.getAs()) + return getTSTLoc( + TDTL.getTypedefNameDecl()->getTypeSourceInfo()->getTypeLoc()); + llvm_unreachable("failed to desugar TemplateSpecializationTypeLoc"); +} + +namespace { + +AST_MATCHER_P(Type, asTST, + ast_matchers::internal::Matcher, + InnerMatcher) { + if (const auto *TST = Node.getAs()) + return InnerMatcher.matches(*TST, Finder, Builder); + return false; +} + +enum StdIteratorArg { + ARG_iterator_category = 0, + ARG_value_type, + ARG_difference_type, + ARG_pointer, + ARG_reference, + ARG_num, +}; + +} // namespace + +void DeprecatedIteratorBaseCheck::registerMatchers(MatchFinder *Finder) { + // Requires C++. + if (!getLangOpts().CPlusPlus) + return; + + // Match record declarations which have std::iterator base. + Finder->addMatcher( + cxxRecordDecl( + anyOf(isClass(), isStruct()), isDefinition(), + unless(ast_matchers::isTemplateInstantiation()), + hasDirectBase(cxxBaseSpecifier( + hasType(asTST(templateSpecializationType( + hasDeclaration(namedDecl( + hasName("::std::iterator")))) + .bind("tst")))) + .bind("base"))) + .bind("subj"), + this); +} + +void DeprecatedIteratorBaseCheck::check( + const MatchFinder::MatchResult &Result) { + SourceManager &SM = *Result.SourceManager; + ASTContext &Context = *Result.Context; + const auto &Subj = *Result.Nodes.getNodeAs("subj"); + const auto &Base = *Result.Nodes.getNodeAs("base"); + const auto &TST = *Result.Nodes.getNodeAs("tst"); + const auto TSTL = getTSTLoc(Base.getTypeSourceInfo()->getTypeLoc()); + + auto Diag = diag(Base.getBaseTypeLoc(), + "inheriting from 'std::iterator' is deprecated"); + + // Non public inheritance from std::iterator? Skip the strange beast. + if (Base.getAccessSpecifier() != AS_public) + return; + + StringRef IndentAccSpec; + if (const AccessSpecDecl *ASD = getAnyAccSpecDecl(Subj)) + IndentAccSpec = Lexer::getIndentationForLine(ASD->getLocation(), SM); + else + IndentAccSpec = Lexer::getIndentationForLine(Subj.getBeginLoc(), SM); + + StringRef Indent; + if (const Decl *D = getAnyNonAccSpecDecl(Subj)) + Indent = Lexer::getIndentationForLine(D->getLocation(), SM); + else + Indent = IndentAccSpec; + + auto GetRealRange = [&](SourceRange Range) { + return Lexer::makeFileCharRange(CharSourceRange::getTokenRange(Range), SM, + getLangOpts()); + }; + + static const StringRef Names[] = { + "iterator_category", "value_type ", "difference_type ", + "pointer ", "reference ", + }; + + SourceRange Overrides[std::size(Names)]; + llvm::transform(Names, std::begin(Overrides), [&](StringRef Name) -> SourceRange { + if (const auto *ND = selectFirst( + "arg", match(cxxRecordDecl( + has(namedDecl(hasName(Name.rtrim())).bind("arg"))), + Subj, Context))) { + SourceRange Range = GetRealRange(ND->getSourceRange()).getAsRange(); + Range.setEnd(findNextTerminator(Range.getEnd(), SM, getLangOpts()) + .getLocWithOffset(1)); + return Range; + } + return {}; + }); + + auto ArgToVal = [&](unsigned Idx) -> std::string { + if (Idx < TSTL.getNumArgs()) { + SourceRange Range = TSTL.getArgLoc(Idx).getSourceRange(); + CharSourceRange CharRange = GetRealRange(Range); + return Lexer::getSourceText(CharRange, SM, getLangOpts()).str(); + } + switch (Idx) { + case ARG_difference_type: + return "std::ptrdiff_t"; + case ARG_pointer: + return Context.getPointerType(TST.getArg(ARG_value_type).getAsType()) + .getAsString(getLangOpts()); + case ARG_reference: + return Context + .getLValueReferenceType(TST.getArg(ARG_value_type).getAsType()) + .getAsString(getLangOpts()); + default: + llvm_unreachable("unexpected argument index"); + } + }; + auto GenAliasForArg = [&](unsigned Idx) { + return (llvm::Twine("using ") + Names[Idx] + " = " + ArgToVal(Idx) + ";") + .str(); + }; + auto EmitterAnchor = + llvm::find_if(Overrides, [](SourceRange SR) { return SR.isValid(); }); + if (EmitterAnchor != std::end(Overrides)) { + const auto B = std::begin(Overrides); + for (auto I = B; I != EmitterAnchor; ++I) + Diag << FixItHint::CreateInsertion( + EmitterAnchor->getBegin(), + (llvm::Twine(GenAliasForArg(std::distance(B, I))) + "\n" + Indent) + .str()); + + for (auto I = std::next(EmitterAnchor); I != std::end(Overrides); ++I) + if (I->isValid()) + EmitterAnchor = I; + else + Diag << FixItHint::CreateInsertion( + EmitterAnchor->getEnd(), + (llvm::Twine("\n") + Indent + GenAliasForArg(std::distance(B, I))) + .str()); + } else { + SmallString<256> Buf; + llvm::raw_svector_ostream StrOS(Buf); + + if (isOpeningRequired(Subj)) + StrOS << '\n' << IndentAccSpec << "public:"; + + for (auto I : llvm::seq(0, ARG_num)) + StrOS << '\n' << Indent << GenAliasForArg(I); + + StrOS << '\n'; + + if (isClosingRequired(Subj)) + StrOS << '\n' << IndentAccSpec << "private:"; + + Diag << FixItHint::CreateInsertion(getInsertLoc(Subj), StrOS.str()); + } + Diag << createBaseRemoval(Subj, Base, SM, getLangOpts()); +} + +} // namespace modernize +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -14,6 +14,7 @@ #include "ConcatNestedNamespacesCheck.h" #include "DeprecatedHeadersCheck.h" #include "DeprecatedIosBaseAliasesCheck.h" +#include "DeprecatedIteratorBaseCheck.h" #include "LoopConvertCheck.h" #include "MakeSharedCheck.h" #include "MakeUniqueCheck.h" @@ -58,6 +59,8 @@ "modernize-deprecated-headers"); CheckFactories.registerCheck( "modernize-deprecated-ios-base-aliases"); + CheckFactories.registerCheck( + "modernize-deprecated-iterator-base"); CheckFactories.registerCheck("modernize-loop-convert"); CheckFactories.registerCheck("modernize-make-shared"); CheckFactories.registerCheck("modernize-make-unique"); diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -95,6 +95,12 @@ Finds member initializations in the constructor body which can be placed into the initialization list instead. +- New :doc:`modernize-deprecated-iterator-base + ` check. + + Finds deprecated in C++17 inheritance from ``std::iterator`` and replaces it + with type aliases. + New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -221,6 +221,7 @@ `modernize-concat-nested-namespaces `_, "Yes" `modernize-deprecated-headers `_, "Yes" `modernize-deprecated-ios-base-aliases `_, "Yes" + `modernize-deprecated-iterator-base `_, "Yes" `modernize-loop-convert `_, "Yes" `modernize-make-shared `_, "Yes" `modernize-make-unique `_, "Yes" diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize-deprecated-iterator-base.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize-deprecated-iterator-base.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize-deprecated-iterator-base.rst @@ -0,0 +1,37 @@ +.. title:: clang-tidy - modernize-deprecated-iterator-base + +modernize-deprecated-iterator-base +================================== + +Finds deprecated in C++17 inheritance from ``std::iterator`` and replaces it +with type aliases. + +Example +------- + +.. code-block:: c++ + + struct my_iterator : std::iterator { + ... + }; + +transforms to: + +.. code-block:: c++ + + struct my_iterator { + using iterator_category = std::random_access_iterator_tag; + using value_type = int; + using difference_type = std::ptrdiff_t; + using pointer = int *; + using reference = int &; + + ... + }; + +Known Limitations +----------------- + +* Base class symbol ambiguities resolved with ``std::iterator`` values. + +* Will not remove ```` include even if it is no longer needed. diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize-deprecated-iterator-base.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize-deprecated-iterator-base.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize-deprecated-iterator-base.cpp @@ -0,0 +1,321 @@ +// RUN: %check_clang_tidy %s modernize-deprecated-iterator-base %t + +namespace std { +using ptrdiff_t = int; +struct input_iterator_tag; +template +struct iterator { + using iterator_category = C; + using value_type = T; + using difference_type = D; + using pointer = P; + using reference = R; +}; +} + + +using iterator_alias = std::iterator; +typedef std::iterator iterator_typedef; + + +// Sugar + +// CHECK-FIXES: struct from_alias { +// CHECK-MESSAGES: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct from_alias: iterator_alias {}; + +// CHECK-FIXES: struct from_typedef { +// CHECK-MESSAGES: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct from_typedef: iterator_typedef {}; + + +// False-positive + +// CHECK-FIXES: struct indirect_base: from_alias {}; +// CHECK-MESSAGES-NOT: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct indirect_base: from_alias {}; + + +// Unsupported + +// CHECK-FIXES: class skipif_non_public_inheritance: iterator_alias {}; +// CHECK-MESSAGES: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +class skipif_non_public_inheritance: iterator_alias {}; + + +// Base removal + +struct A {}; +struct B {}; + +struct collection { + template + struct iterator; +}; + +// CHECK-FIXES: template <> struct collection::iterator<> { +// CHECK-MESSAGES: :[[@LINE+1]]:45: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +template <> struct collection::iterator<> : iterator_alias {}; +// CHECK-FIXES: template <> struct collection::iterator : A { +// CHECK-MESSAGES: :[[@LINE+1]]:49: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +template <> struct collection::iterator : A, iterator_alias {}; +// CHECK-FIXES: template <> struct collection::iterator : B { +// CHECK-MESSAGES: :[[@LINE+1]]:46: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +template <> struct collection::iterator : iterator_alias, B {}; +// CHECK-FIXES: template <> struct collection::iterator : A, B { +// CHECK-MESSAGES: :[[@LINE+1]]:52: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +template <> struct collection::iterator : A, iterator_alias, B {}; + +// CHECK-FIXES: struct do_not_strip_final final { +// CHECK-MESSAGES: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct do_not_strip_final final : iterator_alias {}; + +// CHECK-FIXES: struct iteratorZ // iterator_alias +// CHECK-FIXES: { +// CHECK-MESSAGES: :[[@LINE+2]]:5: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct iteratorZ // iteratorZ + : iterator_alias // iterator_alias +{}; +// CHECK-FIXES: struct iteratorA // iteratorA +// CHECK-FIXES: : A // iterator_alias +// CHECK-FIXES: { +// CHECK-MESSAGES: :[[@LINE+3]]:5: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct iteratorA // iteratorA + : A // A + , iterator_alias // iterator_alias +{}; +// CHECK-FIXES: struct iteratorB // iteratorB +// CHECK-FIXES: : B // B +// CHECK-FIXES: { +// CHECK-MESSAGES: :[[@LINE+2]]:5: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct iteratorB // iteratorB + : iterator_alias // iterator_alias + , B // B +{}; +// CHECK-FIXES: struct iteratorAB // iteratorAB +// CHECK-FIXES: : A // A +// CHECK-FIXES: , B // B +// CHECK-FIXES: { +// CHECK-MESSAGES: :[[@LINE+3]]:5: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct iteratorAB // iteratorAB + : A // A + , iterator_alias // iterator_alias + , B // B +{}; +// CHECK-FIXES: struct iterator0Z // iterator_alias +// CHECK-FIXES: { +// CHECK-MESSAGES: :[[@LINE+2]]:5: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct iterator0Z : // iterator0Z + iterator_alias // iterator_alias +{}; +// CHECK-FIXES: struct iterator0A : // iterator0A +// CHECK-FIXES: A // iterator_alias +// CHECK-FIXES: { +// CHECK-MESSAGES: :[[@LINE+3]]:5: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct iterator0A : // iterator0A + A, // A + iterator_alias // iterator_alias +{}; +// CHECK-FIXES: struct iterator0B : // iterator0B +// CHECK-FIXES: B // B +// CHECK-FIXES: { +// CHECK-MESSAGES: :[[@LINE+2]]:5: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct iterator0B : // iterator0B + iterator_alias, // iterator_alias + B // B +{}; +// CHECK-FIXES: struct iterator0AB : // iterator0AB +// CHECK-FIXES: A, // A +// CHECK-FIXES: B // B +// CHECK-FIXES: { +// CHECK-MESSAGES: :[[@LINE+3]]:5: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct iterator0AB : // iterator0AB + A, // A + iterator_alias, // iterator_alias + B // B +{}; + + +// Opening/closing placement + +// CHECK-FIXES: class iterator00 { +// CHECK-FIXES-NEXT: public: +// CHECK-FIXES: private: +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +class iterator00 : public iterator_alias { + int dummy; +}; +// CHECK-FIXES: class iterator01 { +// CHECK-FIXES-NEXT: public: +// CHECK-FIXES-NOT: private: +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +class iterator01 : public iterator_alias { +protected: +}; +// CHECK-FIXES: class iterator02 { +// CHECK-FIXES-NEXT: public: +// CHECK-FIXES-NOT: private: +// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +class iterator02 : public iterator_alias { +public: +protected: +}; + +// CHECK-FIXES: struct iterator10 { +// CHECK-FIXES-NEXT: public: +// CHECK-FIXES-NOT: private: +// CHECK-MESSAGES: :[[@LINE+1]]:28: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct iterator10 : public iterator_alias { + int dummy; +}; +// CHECK-FIXES: struct iterator11 { +// CHECK-FIXES-NEXT: public: +// CHECK-FIXES-NOT: private: +// CHECK-MESSAGES: :[[@LINE+1]]:28: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct iterator11 : public iterator_alias { +protected: +}; +// CHECK-FIXES: struct iterator12 { +// CHECK-FIXES-NEXT: public: +// CHECK-FIXES-NOT: private: +// CHECK-MESSAGES: :[[@LINE+1]]:28: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct iterator12 : public iterator_alias { +public: +protected: +}; + +// CHECK-FIXES: struct iterator20 { +// CHECK-FIXES-NEXT: using iterator_category = std::input_iterator_tag; +// CHECK-FIXES-NOT: private: +// CHECK-MESSAGES: :[[@LINE+1]]:21: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct iterator20 : iterator_alias { + int dummy; +}; +// CHECK-FIXES: struct iterator21 { +// CHECK-FIXES-NEXT: using iterator_category = std::input_iterator_tag; +// CHECK-FIXES-NOT: private: +// CHECK-MESSAGES: :[[@LINE+1]]:21: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct iterator21 : iterator_alias { +protected: +}; +// CHECK-FIXES: struct iterator22 { +// CHECK-FIXES-NEXT: public: +// CHECK-FIXES-NOT: private: +// CHECK-MESSAGES: :[[@LINE+1]]:21: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct iterator22 : iterator_alias { +public: +protected: +}; + + +// Typedefs + +// CHECK-FIXES: struct basic { +// CHECK-FIXES-NEXT: using iterator_category = std::input_iterator_tag; +// CHECK-FIXES-NEXT: using value_type = int; +// CHECK-FIXES-NEXT: using difference_type = std::ptrdiff_t; +// CHECK-FIXES-NEXT: using pointer = int {{\*}}; +// CHECK-FIXES-NEXT: using reference = int &; +// CHECK-FIXES-NEXT-EMPTY: +// CHECK-MESSAGES: :[[@LINE+1]]:16: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct basic : std::iterator {}; + +// CHECK-FIXES: class nontempl +// CHECK-FIXES-NEXT: { +// CHECK-FIXES-NEXT: public: +// CHECK-FIXES-NEXT: using iterator_category = std::input_iterator_tag; +// CHECK-FIXES-NEXT: using value_type = int; +// CHECK-FIXES-NEXT: using difference_type = long; +// CHECK-FIXES-NEXT: using pointer = int const{{\*}}; +// CHECK-FIXES-NEXT: using reference = int const&; +// CHECK-FIXES-NEXT-EMPTY: +// CHECK-MESSAGES: :[[@LINE+2]]:12: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +class nontempl + : public std::iterator + < std::input_iterator_tag // iterator_category + , int // value_type + , long // difference_type + , int const* // pointer + , int const& // reference + > +{ + private: + int dummy; +}; + +// CHECK-FIXES: class templ +// CHECK-FIXES-NEXT: { +// CHECK-FIXES-NEXT: public: +// CHECK-FIXES-NEXT: using iterator_category = typename T::C; +// CHECK-FIXES-NEXT: using value_type = typename T::V; +// CHECK-FIXES-NEXT: using difference_type = typename T::D; +// CHECK-FIXES-NEXT: using pointer = typename T::P; +// CHECK-FIXES-NEXT: using reference = typename T::R; +// CHECK-FIXES-NEXT-EMPTY: +// CHECK-MESSAGES: :[[@LINE+3]]:12: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +template +class templ + : public std::iterator + < typename T::C // iterator_category + , typename T::V // value_type + , typename T::D // difference_type + , typename T::P // pointer + , typename T::R // reference + > +{ + protected: + int dummy; +}; + +// CHECK-FIXES: struct redeclared +// CHECK-FIXES-NEXT: { +// CHECK-FIXES-NEXT: using iterator_category = std::input_iterator_tag; +// CHECK-FIXES-NEXT: using value_type = void ; +// CHECK-FIXES-NEXT: using difference_type = long; +// CHECK-FIXES-NEXT: struct pointer {} ; +// CHECK-FIXES-NEXT: using reference = int&; +// CHECK-FIXES-NEXT: }; +// CHECK-MESSAGES: :[[@LINE+2]]:12: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] +struct redeclared + : public std::iterator< + std::input_iterator_tag, // iterator_category + int, // value_type + long, // difference_type + int*, // pointer + int&> // reference +{ + using value_type = void ; + struct pointer {} ; +}; + + +// Indentation + +// CHECK-FIXES: {{^ class indent_use_rec {}} +// CHECK-FIXES-NEXT: {{^ public:}} +// CHECK-FIXES-NEXT: {{^ using}} +// CHECK-MESSAGES: :[[@LINE+1]]:33: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] + class indent_use_rec : public iterator_alias { + }; +// CHECK-FIXES: {{^ class indent_use_acc {}} +// CHECK-FIXES-NEXT: {{^ public:}} +// CHECK-FIXES-NEXT: {{^ using}} +// CHECK-MESSAGES: :[[@LINE+1]]:33: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] + class indent_use_acc : public iterator_alias { + public: + }; +// CHECK-FIXES: {{^ class indent_use_memb {}} +// CHECK-FIXES-NEXT: {{^ public:}} +// CHECK-FIXES-NEXT: {{^ using}} +// CHECK-MESSAGES: :[[@LINE+1]]:34: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] + class indent_use_memb : public iterator_alias { + int dummy; + }; +// CHECK-FIXES: {{^ class indent_use_both {}} +// CHECK-FIXES-NEXT: {{^ public:}} +// CHECK-FIXES-NEXT: {{^ using}} +// CHECK-MESSAGES: :[[@LINE+1]]:34: warning: inheriting from 'std::iterator' is deprecated [modernize-deprecated-iterator-base] + class indent_use_both : public iterator_alias { + protected: + int dummy; + };