summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp
diff options
context:
space:
mode:
authorEdwin Vane <edwin.vane@intel.com>2013-02-28 16:29:24 +0000
committerEdwin Vane <edwin.vane@intel.com>2013-02-28 16:29:24 +0000
commit266b625ca90de49dac72022232deac1a59f09ccd (patch)
treec1d3ec4cf38c7f06d5205ee702e0f5c4d85e09a6 /clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp
parent3305b177e6b62e54efb3fa92b5cafbc0c58df981 (diff)
downloadbcm5719-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.cpp247
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);
+}
OpenPOWER on IntegriCloud