Index: clang-tidy/modernize/CMakeLists.txt =================================================================== --- clang-tidy/modernize/CMakeLists.txt +++ clang-tidy/modernize/CMakeLists.txt @@ -18,6 +18,7 @@ UseDefaultCheck.cpp UseNullptrCheck.cpp UseOverrideCheck.cpp + UseUsingCheck.cpp LINK_LIBS clangAST Index: clang-tidy/modernize/ModernizeTidyModule.cpp =================================================================== --- clang-tidy/modernize/ModernizeTidyModule.cpp +++ clang-tidy/modernize/ModernizeTidyModule.cpp @@ -24,6 +24,7 @@ #include "UseDefaultCheck.h" #include "UseNullptrCheck.h" #include "UseOverrideCheck.h" +#include "UseUsingCheck.h" using namespace clang::ast_matchers; @@ -53,6 +54,7 @@ CheckFactories.registerCheck("modernize-use-default"); CheckFactories.registerCheck("modernize-use-nullptr"); CheckFactories.registerCheck("modernize-use-override"); + CheckFactories.registerCheck("modernize-use-using"); } ClangTidyOptions getModuleOptions() override { Index: clang-tidy/modernize/UseUsingCheck.h =================================================================== --- /dev/null +++ clang-tidy/modernize/UseUsingCheck.h @@ -0,0 +1,35 @@ +//===--- UseUsingCheck.h - clang-tidy----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_USING_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_USING_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace modernize { + +/// Check finds typedefs and replaces it with usings. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-using.html +class UseUsingCheck : public ClangTidyCheck { +public: + UseUsingCheck(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_USE_USING_H Index: clang-tidy/modernize/UseUsingCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/modernize/UseUsingCheck.cpp @@ -0,0 +1,91 @@ +//===--- UseUsingCheck.cpp - clang-tidy------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "UseUsingCheck.h" +#include "../utils/LexerUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace modernize { + +void UseUsingCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus11) + return; + Finder->addMatcher(typedefDecl().bind("typedef"), this); +} + +// Checks if 'typedef' keyword can be removed - we do it only if +// it is the only declaration in a declaration chain. +static bool CheckRemoval(SourceManager &SM, const SourceLocation &LocStart, + const SourceLocation &LocEnd, ASTContext &Context, + SourceRange &ResultRange) { + FileID FID = SM.getFileID(LocEnd); + llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, LocEnd); + Lexer DeclLexer(SM.getLocForStartOfFile(FID), Context.getLangOpts(), + Buffer->getBufferStart(), SM.getCharacterData(LocStart), + Buffer->getBufferEnd()); + Token DeclToken; + bool result = false; + int parenthesisLevel = 0; + while (!DeclLexer.LexFromRawLexer(DeclToken)) { + if (DeclToken.getKind() == tok::TokenKind::l_paren) + parenthesisLevel++; + if (DeclToken.getKind() == tok::TokenKind::r_paren) + parenthesisLevel--; + if (DeclToken.getKind() == tok::TokenKind::semi) + break; + // if there is comma and we are not between open parenthesis then it is + // two or more declatarions in this chain + if (parenthesisLevel == 0 && DeclToken.getKind() == tok::TokenKind::comma) + return false; + + if (DeclToken.isOneOf(tok::TokenKind::identifier, + tok::TokenKind::raw_identifier)) { + auto TokenStr = DeclToken.getRawIdentifier().str(); + + if (TokenStr == "typedef") { + ResultRange = + SourceRange(DeclToken.getLocation(), DeclToken.getEndLoc()); + result = true; + } + } + } + // assert if there was keyword 'typedef' in declaration + assert(result && "No typedef found"); + + return result; +} + +void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs("typedef"); + if (!MatchedDecl->getLocation().isValid()) + return; + + auto &Context = *Result.Context; + auto &SM = *Result.SourceManager; + + auto Diag = + diag(MatchedDecl->getLocStart(), "use 'using' instead of 'typedef'"); + SourceRange RemovalRange; + if (CheckRemoval(SM, MatchedDecl->getLocStart(), MatchedDecl->getLocEnd(), + Context, RemovalRange)) { + Diag << FixItHint::CreateReplacement( + MatchedDecl->getSourceRange(), + "using " + MatchedDecl->getNameAsString() + " = " + + MatchedDecl->getUnderlyingType().getAsString(getLangOpts())); + } +} + +} // namespace modernize +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -201,6 +201,11 @@ Finds integer literals which are cast to bool. +- New `modernize-use-using + `_ check + + Finds typedefs and replaces it with usings. + - New `performance-faster-string-find `_ check Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -105,6 +105,7 @@ modernize-use-default modernize-use-nullptr modernize-use-override + modernize-use-using performance-faster-string-find performance-for-range-copy performance-implicit-cast-in-loop Index: docs/clang-tidy/checks/modernize-use-using.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/modernize-use-using.rst @@ -0,0 +1,26 @@ +.. title:: clang-tidy - modernize-use-using + +modernize-use-using +=================== + +Use C++11's ``using`` instead of ``typedef``. + +Before: + +.. code:: c++ + + typedef int variable; + + class Class{}; + typedef void (Class::* MyPtrType)() const; + +After: + +.. code:: c++ + + using variable = int; + + class Class{}; + using MyPtrType = void (Class::*)() const; + +This check requires using C++11 or higher to run. Index: test/clang-tidy/modernize-use-using.cpp =================================================================== --- /dev/null +++ test/clang-tidy/modernize-use-using.cpp @@ -0,0 +1,82 @@ +// RUN: %check_clang_tidy %s modernize-use-using %t + +typedef int Type; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using] +// CHECK-FIXES: using Type = int; + +typedef long LL; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' +// CHECK-FIXES: using LL = long; + +typedef int Bla; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' +// CHECK-FIXES: using Bla = int; + +typedef Bla Bla2; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' +// CHECK-FIXES: using Bla2 = Bla; + +typedef void (*type)(int, int); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' +// CHECK-FIXES: using type = void (*)(int, int); + +typedef void (*type2)(); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' +// CHECK-FIXES: using type2 = void (*)(); + +class Class { + typedef long long Type; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' + // CHECK-FIXES: using Type = long long; +}; + +typedef void (Class::*MyPtrType)(Bla) const; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' +// CHECK-FIXES: using MyPtrType = void (Class::*)(Bla) const; + +class Iterable { +public: + class Iterator {}; +}; + +template +class Test { + typedef typename T::iterator Iter; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef' + // CHECK-FIXES: using Iter = typename T::iterator; +}; + +using balba = long long; + +union A {}; + +typedef void (A::*PtrType)(int, int) const; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' +// CHECK-FIXES: using PtrType = void (A::*)(int, int) const; + +typedef Class some_class; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' +// CHECK-FIXES: using some_class = Class; + +typedef Class Cclass; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' +// CHECK-FIXES: using Cclass = Class; + +typedef Cclass cclass2; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' +// CHECK-FIXES: using cclass2 = Cclass; + +class cclass {}; + +typedef void (cclass::*MyPtrType3)(Bla); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' +// CHECK-FIXES: using MyPtrType3 = void (cclass::*)(Bla); + +using my_class = int; + +typedef Test another; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' +// CHECK-FIXES: using another = Test; + +typedef int bla1, bla2, bla3; +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'