forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			281 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			281 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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 "Core/CustomMatchers.h"
 | |
| #include "clang/AST/ASTContext.h"
 | |
| 
 | |
| using namespace clang::ast_matchers;
 | |
| using namespace clang;
 | |
| 
 | |
| const char *IteratorDeclStmtId = "iterator_decl";
 | |
| const char *DeclWithNewId = "decl_new";
 | |
| const char *NewExprId = "new_expr";
 | |
| 
 | |
| 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;
 | |
| /// \endcode
 | |
| ///
 | |
| /// \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;
 | |
| /// \endcode
 | |
| ///
 | |
| /// \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 {};
 | |
| /// \endcode
 | |
| ///
 | |
| /// \c recordDecl(hasStdContainerName()) matches \c vector and \c forward_list
 | |
| /// but not \c my_vec.
 | |
| AST_MATCHER(NamedDecl, hasStdContainerName) {
 | |
|   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) {
 | |
|     if (hasName(ContainerNames[i]).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(), isFromStdNamespace())
 | |
|                )
 | |
|              )
 | |
|            )
 | |
|          );
 | |
| }
 | |
| 
 | |
| // \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(), isFromStdNamespace())
 | |
|                )
 | |
|              )
 | |
|            )
 | |
|          );
 | |
| }
 | |
| 
 | |
| // \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(
 | |
|                specifiesType(
 | |
|                  templateSpecializationType(
 | |
|                    hasDeclaration(
 | |
|                      namedDecl(hasStdContainerName(), isFromStdNamespace())
 | |
|                    )
 | |
|                  )
 | |
|                )
 | |
|              ),
 | |
|              // 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
 | |
| 
 | |
| // \brief This matcher returns delaration statements that contain variable
 | |
| // declarations with written non-list initializer for standard iterators.
 | |
| StatementMatcher makeIteratorDeclMatcher() {
 | |
|   return declStmt(
 | |
|     // At least one varDecl should be a child of the declStmt to ensure it's a
 | |
|     // declaration list and avoid matching other declarations
 | |
|     // e.g. using directives.
 | |
|     has(varDecl()),
 | |
|     unless(has(varDecl(
 | |
|       anyOf(
 | |
|         unless(hasWrittenNonListInitializer()),
 | |
|         hasType(autoType()),
 | |
|         unless(hasType(
 | |
|           isSugarFor(
 | |
|             anyOf(
 | |
|               typedefIterator(),
 | |
|               nestedIterator(),
 | |
|               iteratorFromUsingDeclaration()
 | |
|             )
 | |
|           )
 | |
|         ))
 | |
|       )
 | |
|     )))
 | |
|   ).bind(IteratorDeclStmtId);
 | |
| }
 | |
| 
 | |
| StatementMatcher makeDeclWithNewMatcher() {
 | |
|   return declStmt(
 | |
|     has(varDecl()),
 | |
|     unless(has(varDecl(
 | |
|       anyOf(
 | |
|         unless(hasInitializer(
 | |
|           ignoringParenImpCasts(newExpr())
 | |
|         )),
 | |
|         // FIXME: TypeLoc information is not reliable where CV qualifiers are
 | |
|         // concerned so these types can't be handled for now.
 | |
|         hasType(pointerType(pointee(hasCanonicalType(hasLocalQualifiers())))),
 | |
| 
 | |
|         // FIXME: Handle function pointers. For now we ignore them because
 | |
|         // the replacement replaces the entire type specifier source range
 | |
|         // which includes the identifier.
 | |
|         hasType(
 | |
|           pointsTo(
 | |
|             pointsTo(
 | |
|               parenType(innerType(functionType()))
 | |
|             )
 | |
|           )
 | |
|         )
 | |
|       )
 | |
|     )))
 | |
|    ).bind(DeclWithNewId);
 | |
| }
 |