diff options
author | Edwin Vane <edwin.vane@intel.com> | 2013-02-28 16:29:24 +0000 |
---|---|---|
committer | Edwin Vane <edwin.vane@intel.com> | 2013-02-28 16:29:24 +0000 |
commit | 266b625ca90de49dac72022232deac1a59f09ccd (patch) | |
tree | c1d3ec4cf38c7f06d5205ee702e0f5c4d85e09a6 /clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp | |
parent | 3305b177e6b62e54efb3fa92b5cafbc0c58df981 (diff) | |
download | bcm5719-llvm-266b625ca90de49dac72022232deac1a59f09ccd.tar.gz bcm5719-llvm-266b625ca90de49dac72022232deac1a59f09ccd.zip |
Introducing Use-Auto transform for cpp11-migrate
The new Use-Auto transform replaces the type specifier for variable
declarations with the special C++11 'auto' type specifier. For now, the
replacement is done only for variables that are iterators of any of the
std containers and only if the type used is one of those explicitly
allowed by the standard (i.e. not an implementation-specific type).
Reviewers: gribozavr, silvas, klimek
llvm-svn: 176266
Diffstat (limited to 'clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp')
-rw-r--r-- | clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp b/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp new file mode 100644 index 00000000000..6522f4f10bd --- /dev/null +++ b/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp @@ -0,0 +1,247 @@ +//===-- UseAutoMatchers.cpp - Matchers for use-auto transform -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file contains the implementation for matcher-generating +/// functions and custom AST_MATCHERs. +/// +//===----------------------------------------------------------------------===// +#include "UseAutoMatchers.h" +#include "clang/AST/ASTContext.h" + +using namespace clang::ast_matchers; +using namespace clang; + +const char *DeclNodeId = "decl"; + +namespace clang { +namespace ast_matchers { + +/// \brief Matches variable declarations that have explicit initializers that +/// are not initializer lists. +/// +/// Given +/// \code +/// iterator I = Container.begin(); +/// MyType A(42); +/// MyType B{2}; +/// MyType C; +/// \endcode +/// varDecl(hasWrittenNonListInitializer()) matches \c I and \c A but not \c B +/// or \c C. +AST_MATCHER(VarDecl, hasWrittenNonListInitializer) { + const Expr *Init = Node.getAnyInitializer(); + if (!Init) + return false; + + // The following test is based on DeclPrinter::VisitVarDecl() to find if an + // initializer is implicit or not. + bool ImplicitInit = false; + if (const CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init)) { + if (Construct->isListInitialization()) + return false; + ImplicitInit = Construct->getNumArgs() == 0 || + Construct->getArg(0)->isDefaultArgument(); + } else + if (Node.getInitStyle() == VarDecl::ListInit) + return false; + + return !ImplicitInit; +} + +/// \brief Matches QualTypes that are type sugar for QualTypes that match \c +/// SugarMatcher. +/// +/// Given +/// \code +/// class C {}; +/// typedef C my_type +/// typedef my_type my_other_type; +/// \code +/// +/// \c qualType(isSugarFor(recordType(hasDeclaration(namedDecl(hasName("C")))))) +/// matches \c my_type and \c my_other_type. +AST_MATCHER_P(QualType, isSugarFor, internal::Matcher<QualType>, SugarMatcher) { + QualType QT = Node; + for (;;) { + if (SugarMatcher.matches(QT, Finder, Builder)) + return true; + + QualType NewQT = QT.getSingleStepDesugaredType(Finder->getASTContext()); + if (NewQT == QT) + break; + QT = NewQT; + } + return false; +} + +/// \brief Matches named declarations that have one of the standard iterator +/// names: iterator, reverse_iterator, const_iterator, const_reverse_iterator. +/// +/// Given +/// \code +/// iterator I; +/// const_iterator CI; +/// \code +/// +/// \c namedDecl(hasStdIteratorName()) matches \c I and \c CI. +AST_MATCHER(NamedDecl, hasStdIteratorName) { + static const char *IteratorNames[] = { + "iterator", + "reverse_iterator", + "const_iterator", + "const_reverse_iterator" + }; + + for (unsigned int i = 0; + i < llvm::array_lengthof(IteratorNames); + ++i) { + if (hasName(IteratorNames[i]).matches(Node, Finder, Builder)) + return true; + } + return false; +} + +/// \brief Matches named declarations that have one of the standard container +/// names. +/// +/// Given +/// \code +/// class vector {}; +/// class forward_list {}; +/// class my_vec {}; +/// \code +/// +/// \c recordDecl(hasStdContainerName()) matches \c vector and \c forward_list +/// but not \c my_vec. +AST_MATCHER_P(NamedDecl, hasStdContainerName, bool, WithStd) { + static const char *ContainerNames[] = { + "array", + "deque", + "forward_list", + "list", + "vector", + + "map", + "multimap", + "set", + "multiset", + + "unordered_map", + "unordered_multimap", + "unordered_set", + "unordered_multiset", + + "queue", + "priority_queue", + "stack" + }; + + for (unsigned int i = 0; + i < llvm::array_lengthof(ContainerNames); + ++i) { + std::string Name(ContainerNames[i]); + if (WithStd) + Name = "std::" + Name; + if (hasName(Name).matches(Node, Finder, Builder)) + return true; + } + return false; +} + +} // namespace ast_matchers +} // namespace clang + +namespace { +// \brief Returns a TypeMatcher that matches typedefs for standard iterators +// inside records with a standard container name. +TypeMatcher typedefIterator() { + return typedefType( + hasDeclaration( + allOf( + namedDecl(hasStdIteratorName()), + hasDeclContext( + recordDecl(hasStdContainerName(true)) + ) + ) + ) + ); +} + +// \brief Returns a TypeMatcher that matches records named for standard +// iterators nested inside records named for standard containers. +TypeMatcher nestedIterator() { + return recordType( + hasDeclaration( + allOf( + namedDecl(hasStdIteratorName()), + hasDeclContext( + recordDecl(hasStdContainerName(true)) + ) + ) + ) + ); +} + +// \brief Returns a TypeMatcher that matches types declared with using +// declarations and which name standard iterators for standard containers. +TypeMatcher iteratorFromUsingDeclaration() { + // Types resulting from using declarations are + // represented by ElaboratedType. + return elaboratedType( + allOf( + // Unwrap the nested name specifier to test for + // one of the standard containers. + hasQualifier(allOf( + specifiesType( + templateSpecializationType( + hasDeclaration( + namedDecl(hasStdContainerName(false)) + ) + ) + ), + hasPrefix( + specifiesNamespace(hasName("std")) + ) + )), + // The named type is what comes after the final + // '::' in the type. It should name one of the + // standard iterator names. + namesType(anyOf( + typedefType( + hasDeclaration( + namedDecl(hasStdIteratorName()) + ) + ), + recordType( + hasDeclaration( + namedDecl(hasStdIteratorName()) + ) + ) + )) + ) + ); +} +} // namespace + +DeclarationMatcher makeIteratorMatcher() { + return varDecl(allOf( + hasWrittenNonListInitializer(), + unless(hasType(autoType())), + hasType( + isSugarFor( + anyOf( + typedefIterator(), + nestedIterator(), + iteratorFromUsingDeclaration() + ) + ) + ) + )).bind(DeclNodeId); +} |