[clang-tools-extra] r176266 - Introducing Use-Auto transform for cpp11-migrate

David Blaikie dblaikie at gmail.com
Thu Feb 28 11:36:24 PST 2013


On Thu, Feb 28, 2013 at 8:29 AM, Edwin Vane <edwin.vane at intel.com> wrote:
> Author: revane
> Date: Thu Feb 28 10:29:24 2013
> New Revision: 176266
>
> URL: http://llvm.org/viewvc/llvm-project?rev=176266&view=rev
> Log:
> 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
>
> Added:
>     clang-tools-extra/trunk/cpp11-migrate/UseAuto/
>     clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.cpp
>     clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.h
>     clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.cpp
>     clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.h
>     clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.cpp
>     clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.h
>     clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/iterator.cpp

Failing here: http://lab.llvm.org:8011/builders/clang-x86_64-ubuntu-gdb-75/builds/2711
http://lab.llvm.org:8011/builders/clang-x86_64-ubuntu-gdb-75/builds/2711/steps/check-all/logs/Clang%20Tools%20%3A%3A%20cpp11-migrate__UseAuto__iterator.cpp

Please fix or revert.

> Modified:
>     clang-tools-extra/trunk/cpp11-migrate/CMakeLists.txt
>     clang-tools-extra/trunk/cpp11-migrate/Makefile
>     clang-tools-extra/trunk/cpp11-migrate/Transforms.cpp
>     clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/Inputs/gen_my_std.h.py
>     clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/gen_basic_std_iterator_tests.cpp.py
>
> Modified: clang-tools-extra/trunk/cpp11-migrate/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/CMakeLists.txt?rev=176266&r1=176265&r2=176266&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/cpp11-migrate/CMakeLists.txt (original)
> +++ clang-tools-extra/trunk/cpp11-migrate/CMakeLists.txt Thu Feb 28 10:29:24 2013
> @@ -15,6 +15,9 @@ list(APPEND Cpp11MigrateSources ${LoopCo
>  file(GLOB_RECURSE UseNullptrSources "UseNullptr/*.cpp")
>  list(APPEND Cpp11MigrateSources ${UseNullptrSources})
>
> +file(GLOB_RECURSE UseAutoSources "UseAuto/*.cpp")
> +list(APPEND Cpp11MigrateSources ${UseAutoSources})
> +
>  add_clang_executable(cpp11-migrate
>    ${Cpp11MigrateSources}
>    )
>
> Modified: clang-tools-extra/trunk/cpp11-migrate/Makefile
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/Makefile?rev=176266&r1=176265&r2=176266&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/cpp11-migrate/Makefile (original)
> +++ clang-tools-extra/trunk/cpp11-migrate/Makefile Thu Feb 28 10:29:24 2013
> @@ -26,6 +26,8 @@ SOURCES += $(addprefix LoopConvert/,$(no
>  BUILT_SOURCES = $(ObjDir)/LoopConvert/.objdir
>  SOURCES += $(addprefix UseNullptr/,$(notdir $(wildcard $(PROJ_SRC_DIR)/UseNullptr/*.cpp)))
>  BUILT_SOURCES += $(ObjDir)/UseNullptr/.objdir
> +SOURCES += $(addprefix UseAuto/,$(notdir $(wildcard $(PROJ_SRC_DIR)/UseAuto/*.cpp)))
> +BUILT_SOURCES += $(ObjDir)/UseAuto/.objdir
>
>  LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
>  USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
>
> Modified: clang-tools-extra/trunk/cpp11-migrate/Transforms.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/Transforms.cpp?rev=176266&r1=176265&r2=176266&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/cpp11-migrate/Transforms.cpp (original)
> +++ clang-tools-extra/trunk/cpp11-migrate/Transforms.cpp Thu Feb 28 10:29:24 2013
> @@ -15,6 +15,7 @@
>  #include "Transforms.h"
>  #include "LoopConvert/LoopConvert.h"
>  #include "UseNullptr/UseNullptr.h"
> +#include "UseAuto/UseAuto.h"
>
>  namespace cl = llvm::cl;
>
> @@ -47,6 +48,12 @@ void Transforms::createTransformOpts() {
>          cl::desc("Make use of nullptr keyword where possible")),
>        &ConstructTransform<UseNullptrTransform>));
>
> +  Options.push_back(
> +    OptionVec::value_type(
> +      new cl::opt<bool>("use-auto",
> +        cl::desc("Use of 'auto' type specifier")),
> +      &ConstructTransform<UseAutoTransform>));
> +
>    // Add more transform options here.
>  }
>
>
> Added: clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.cpp?rev=176266&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.cpp (added)
> +++ clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.cpp Thu Feb 28 10:29:24 2013
> @@ -0,0 +1,58 @@
> +//===-- UseAuto/UseAuto.cpp - Use auto type specifier ---------------------===//
> +//
> +//                     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 provides the implementation of the UseAutoTransform class.
> +///
> +//===----------------------------------------------------------------------===//
> +
> +#include "UseAuto.h"
> +#include "UseAutoActions.h"
> +#include "UseAutoMatchers.h"
> +
> +using clang::ast_matchers::MatchFinder;
> +using namespace clang;
> +using namespace clang::tooling;
> +
> +int UseAutoTransform::apply(const FileContentsByPath &InputStates,
> +                            RiskLevel MaxRisk,
> +                            const clang::tooling::CompilationDatabase &Database,
> +                            const std::vector<std::string> &SourcePaths,
> +                            FileContentsByPath &ResultStates) {
> +  RefactoringTool UseAutoTool(Database, SourcePaths);
> +
> +  for (FileContentsByPath::const_iterator I = InputStates.begin(),
> +                                          E = InputStates.end();
> +       I != E; ++I)
> +    UseAutoTool.mapVirtualFile(I->first, I->second);
> +
> +  unsigned AcceptedChanges = 0;
> +
> +  MatchFinder Finder;
> +  UseAutoFixer Fixer(UseAutoTool.getReplacements(), AcceptedChanges, MaxRisk);
> +
> +  Finder.addMatcher(makeIteratorMatcher(), &Fixer);
> +
> +  if (int Result = UseAutoTool.run(newFrontendActionFactory(&Finder))) {
> +    llvm::errs() << "Error encountered during translation.\n";
> +    return Result;
> +  }
> +
> +  RewriterContainer Rewrite(UseAutoTool.getFiles(), InputStates);
> +
> +  // FIXME: Do something if some replacements didn't get applied?
> +  UseAutoTool.applyAllReplacements(Rewrite.getRewriter());
> +
> +  collectResults(Rewrite.getRewriter(), InputStates, ResultStates);
> +
> +  if (AcceptedChanges > 0)
> +    setChangesMade();
> +
> +  return 0;
> +}
>
> Added: clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.h?rev=176266&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.h (added)
> +++ clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAuto.h Thu Feb 28 10:29:24 2013
> @@ -0,0 +1,40 @@
> +//===-- UseAuto/UseAuto.h - Use auto type specifier -------------*- C++ -*-===//
> +//
> +//                     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 provides the definition of the UseAutoTransform class
> +/// which is the main interface to the use-auto transform that replaces
> +/// type specifiers with the special C++11 'auto' type specifier in certain
> +/// situations.
> +///
> +//===----------------------------------------------------------------------===//
> +#ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_H
> +#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_H
> +
> +#include "Transform.h"
> +#include "llvm/Support/Compiler.h"
> +
> +/// \brief Subclass of Transform that transforms type specifiers for variable
> +/// declarations into the special C++11 'auto' type specifier for certain cases:
> +/// * Iterators of std containers.
> +/// * More to come...
> +///
> +/// Other uses of the auto type specifier as outlined in C++11 [dcl.spec.auto]
> +/// p2 are not handled by this transform.
> +class UseAutoTransform : public Transform {
> +public:
> +  /// \see Transform::run().
> +  virtual int apply(const FileContentsByPath &InputStates,
> +                    RiskLevel MaxRiskLEvel,
> +                    const clang::tooling::CompilationDatabase &Database,
> +                    const std::vector<std::string> &SourcePaths,
> +                    FileContentsByPath &ResultStates) LLVM_OVERRIDE;
> +};
> +
> +#endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_H
>
> Added: clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.cpp?rev=176266&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.cpp (added)
> +++ clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.cpp Thu Feb 28 10:29:24 2013
> @@ -0,0 +1,63 @@
> +//===-- UseAuto/UseAutoActions.cpp - Matcher callback impl ----------------===//
> +//
> +//                     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 of the UseAutoFixer class.
> +///
> +//===----------------------------------------------------------------------===//
> +#include "UseAutoActions.h"
> +#include "UseAutoMatchers.h"
> +#include "clang/AST/ASTContext.h"
> +
> +using namespace clang::ast_matchers;
> +using namespace clang::tooling;
> +using namespace clang;
> +
> +void UseAutoFixer::run(const MatchFinder::MatchResult &Result) {
> +  const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>(DeclNodeId);
> +
> +  assert(D && "Bad Callback. No node provided");
> +
> +  SourceManager &SM = *Result.SourceManager;
> +  if (!SM.isFromMainFile(D->getLocStart()))
> +    return;
> +
> +  const CXXConstructExpr *Construct = cast<CXXConstructExpr>(D->getInit());
> +  assert(Construct->getNumArgs() == 1u &&
> +         "Expected constructor with single argument");
> +
> +  // Drill down to the as-written initializer.
> +  const Expr *E = Construct->arg_begin()->IgnoreParenImpCasts();
> +  if (E != E->IgnoreConversionOperator())
> +    // We hit a conversion operator. Early-out now as they imply an implicit
> +    // conversion from a different type. Could also mean an explicit conversion
> +    // from the same type but that's pretty rare.
> +    return;
> +
> +  if (const CXXConstructExpr *NestedConstruct = dyn_cast<CXXConstructExpr>(E))
> +    // If we ran into an implicit conversion constructor, can't convert.
> +    //
> +    // FIXME: The following only checks if the constructor can be used
> +    // implicitly, not if it actually was. Cases where the converting constructor
> +    // was used explicitly won't get converted.
> +    if (NestedConstruct->getConstructor()->isConvertingConstructor(false))
> +      return;
> +
> +  if (Result.Context->hasSameType(D->getType(), E->getType())) {
> +    TypeLoc TL = D->getTypeSourceInfo()->getTypeLoc();
> +
> +    // WARNING: TypeLoc::getSourceRange() will include the identifier for things
> +    // like function pointers. Not a concern since this action only works with
> +    // iterators but something to keep in mind in the future.
> +
> +    CharSourceRange Range(TL.getSourceRange(), true);
> +    Replace.insert(tooling::Replacement(SM, Range, "auto"));
> +    ++AcceptedChanges;
> +  }
> +}
>
> Added: clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.h?rev=176266&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.h (added)
> +++ clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoActions.h Thu Feb 28 10:29:24 2013
> @@ -0,0 +1,38 @@
> +//===-- UseAuto/Actions.h - Matcher callback ---------------------*- C++ -*-==//
> +//
> +//                     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 declaration of the UseAutoFixer class which
> +///  is used as an ASTMatcher callback.
> +///
> +//===----------------------------------------------------------------------===//
> +#ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_ACTIONS_H
> +#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_ACTIONS_H
> +
> +#include "Transform.h"
> +#include "clang/ASTMatchers/ASTMatchFinder.h"
> +#include "clang/Tooling/Refactoring.h"
> +
> +/// \brief The callback to be used for use-auto AST matchers.
> +class UseAutoFixer : public clang::ast_matchers::MatchFinder::MatchCallback {
> +public:
> +  UseAutoFixer(clang::tooling::Replacements &Replace, unsigned &AcceptedChanges,
> +               RiskLevel)
> +      : Replace(Replace), AcceptedChanges(AcceptedChanges) {
> +  }
> +
> +  /// \brief Entry point to the callback called when matches are made.
> +  virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result);
> +
> +private:
> +  clang::tooling::Replacements &Replace;
> +  unsigned &AcceptedChanges;
> +};
> +
> +#endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_ACTIONS_H
>
> Added: clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.cpp?rev=176266&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.cpp (added)
> +++ clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.cpp Thu Feb 28 10:29:24 2013
> @@ -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);
> +}
>
> Added: clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.h?rev=176266&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.h (added)
> +++ clang-tools-extra/trunk/cpp11-migrate/UseAuto/UseAutoMatchers.h Thu Feb 28 10:29:24 2013
> @@ -0,0 +1,27 @@
> +//===-- UseAutoMatchers.h - Matchers for use-auto transform ----*- C++ -*--===//
> +//
> +//                     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 declarations for matcher-generating functions
> +///  and names for bound nodes found by AST matchers.
> +///
> +//===----------------------------------------------------------------------===//
> +#ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_MATCHERS_H
> +#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_MATCHERS_H
> +
> +#include "clang/ASTMatchers/ASTMatchers.h"
> +
> +extern const char *DeclNodeId;
> +
> +/// \brief Create a matcher that matches variable declarations where the type
> +/// is an iterator for an std container and has an explicit initializer of the
> +/// same type.
> +clang::ast_matchers::DeclarationMatcher makeIteratorMatcher();
> +
> +#endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_USE_AUTO_MATCHERS_H
>
> Modified: clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/Inputs/gen_my_std.h.py
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/Inputs/gen_my_std.h.py?rev=176266&r1=176265&r2=176266&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/Inputs/gen_my_std.h.py (original)
> +++ clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/Inputs/gen_my_std.h.py Thu Feb 28 10:29:24 2013
> @@ -1,47 +1,57 @@
>  #!/usr/bin/python
>
> +# Each std container is represented below. To test the various ways in which
> +# a type may be defined, the containers are split into categories:
> +# * Define iterator types with typedefs
> +# * Define iterator types as nested classes
> +# * Define iterator types with using declarations
> +#
> +# Further, one class in each category is chosen to be defined in a way mimicing
> +# libc++: The container is actually defined in a different namespace (std::_1
> +# is used here) and then imported into the std namespace with a using
> +# declaration. This is controlled with the 'using' key in the dictionary
> +# describing each container.
>  typedef_containers = [
> -    "array",
> -    "deque",
> -    "forward_list",
> -    "list",
> -    "vector"
> +  {"name" : "array",
> +   "using" : True},
> +  {"name" : "deque",
> +   "using" : False},
> +  {"name" : "forward_list",
> +   "using" : False},
> +  {"name" : "list",
> +   "using" : False},
> +  {"name" : "vector",
> +   "using" : False}
>  ]
>  subclass_containers = [
> -    "map",
> -    "multimap",
> -    "set",
> -    "multiset",
> +  {"name" : "map",
> +   "using" : True},
> +  {"name" : "multimap",
> +   "using" : False},
> +  {"name" : "set",
> +   "using" : False},
> +  {"name" : "multiset",
> +   "using" : False},
>  ]
>  using_containers = [
> -    "unordered_map",
> -    "unordered_multimap",
> -    "unordered_set",
> -    "unordered_multiset",
> -    "queue",
> -    "priority_queue",
> -    "stack"
> +  {"name" : "unordered_map",
> +   "using" : True},
> +  {"name" : "unordered_multimap",
> +   "using" : False},
> +  {"name" : "unordered_set",
> +   "using" : False},
> +  {"name" : "unordered_multiset",
> +   "using" : False},
> +  {"name" : "queue",
> +   "using" : False},
> +  {"name" : "priority_queue",
> +   "using" : False},
> +  {"name" : "stack",
> +   "using" : False}
>  ]
>
> -print """namespace internal {
> -
> -template <typename T, int i>
> -struct iterator_wrapper {
> -};
> -
> -template <typename T>
> -class iterator_provider {
> -public:
> -  class iterator {};
> -  class const_iterator {};
> -  class reverse_iterator {};
> -  class const_reverse_iterator {};
> -};
> -
> -} // namespace internal
> -
> -namespace std {"""
>
> +# Every class requires these functions.
>  iterator_generators = """
>    iterator begin() { return iterator(); }
>    iterator end() { return iterator(); }
> @@ -56,21 +66,97 @@ iterator_generators = """
>    const_reverse_iterator rend() const { return const_reverse_iterator(); }
>  """
>
> +
> +# Convenience function for nested class definition within a special namespace
> +# to mimic libc++ style std container definitions.
> +def outputClassDef(Definition, ClassName, Import):
> +  if Import:
> +    print "namespace _1 {"
> +
> +  print Definition
> +
> +  if Import:
> +    print """
> +}} // namespace _1
> +using _1::{0};""".format(ClassName)
> +
> +
> +# Output preamble and common functionality
> +print """
> +//===-----------------------------------------------------------*- C++ -*--===//
> +//
> +// This file was automatically generated from gen_my_std.h.py by the build
> +// system as a dependency for cpp11-migrate's test suite.
> +//
> +// This file contains a shell implementation of std containers and iterators for
> +// testing the use-auto transform of cpp11-migrate. All std containers and
> +// iterators are present. Container and iterator implementations vary to cover
> +// various ways the std container and iterator types are made available:
> +//
> +// Variations for how iterator types are presented:
> +// * Typedef (array, deque, forward_list, list, vector)
> +// * Nested class (map, multimap, set, multiset)
> +// * Using declaration {unordered_} X {map, multimap, set, multiset}
> +//
> +// Variations for how container types are presented:
> +// * Defined directly in namespace std
> +// * Imported into namespace std with using declarations (a la libc++).
> +//
> +//===----------------------------------------------------------------------===//
> +
> +namespace internal {
> +
> +template <typename T, int i>
> +struct iterator_wrapper {
> +  iterator_wrapper() {}
> +
> +  // These are required for tests using iteration statements.
> +  bool operator!=(const iterator_wrapper<T, i>&) { return false; }
> +  iterator_wrapper& operator++() { return *this; }
> +  typename T::value_type operator*() { return typename T::value_type(); }
> +};
> +
> +template <typename T>
> +class iterator_provider {
> +public:
> +  class iterator {
> +  public:
> +    iterator() {}
> +    iterator(const iterator&) {}
> +  };
> +  class const_iterator {
> +  public:
> +    const_iterator(int i=0) {}
> +    const_iterator(const iterator &) {}
> +    const_iterator(const const_iterator &) {}
> +    operator iterator() { return iterator(); }
> +  };
> +  class reverse_iterator {};
> +  class const_reverse_iterator {};
> +};
> +
> +} // namespace internal
> +
> +namespace std {""".lstrip() # Take off leading newline
> +
>  for c in typedef_containers:
> -  print """
> +  Definition = """
>  template <typename T>
>  class {0} {{
>  public:
> +  typedef T value_type;
>    typedef typename internal::iterator_wrapper<{0}<T>, 0> iterator;
>    typedef typename internal::iterator_wrapper<{0}<T>, 1> const_iterator;
>    typedef typename internal::iterator_wrapper<{0}<T>, 3> reverse_iterator;
>    typedef typename internal::iterator_wrapper<{0}<T>, 2> const_reverse_iterator;
>
>    {0}() {{}}
> -  {1}}};""".format(c, iterator_generators)
> +  {1}}};""".format(c['name'], iterator_generators)
> +
> +  outputClassDef(Definition, c['name'], c['using'])
>
>  for c in subclass_containers:
> -  print """
> +  Definition = """
>  template <typename T>
>  class {0} {{
>  public:
> @@ -80,10 +166,12 @@ public:
>    class const_reverse_iterator {{}};
>
>    {0}() {{}}
> -  {1}}};""".format(c, iterator_generators)
> +  {1}}};""".format(c['name'], iterator_generators)
> +
> +  outputClassDef(Definition, c['name'], c['using'])
>
>  for c in using_containers:
> -  print """
> +  Definition = """
>  template <typename T>
>  class {0} : internal::iterator_provider<{0}<T> > {{
>  public:
> @@ -93,6 +181,8 @@ public:
>    using typename internal::iterator_provider<{0}<T> >::const_reverse_iterator;
>
>    {0}() {{}}
> -  {1}}};""".format(c, iterator_generators)
> +  {1}}};""".format(c['name'], iterator_generators)
> +
> +  outputClassDef(Definition, c['name'], c['using'])
>
>  print "} // namespace std"
>
> Modified: clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/gen_basic_std_iterator_tests.cpp.py
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/gen_basic_std_iterator_tests.cpp.py?rev=176266&r1=176265&r2=176266&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/gen_basic_std_iterator_tests.cpp.py (original)
> +++ clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/gen_basic_std_iterator_tests.cpp.py Thu Feb 28 10:29:24 2013
> @@ -19,13 +19,26 @@ containers = [
>      "stack"
>  ]
>
> -print """// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
> -// RUN: cpp11-migrate -use-auto %t.cpp -- --std=c++11 -I %S/Inputs
> +print """
> +//===----------------------------------------------------------------------===//
> +//
> +// This file was automatically generated from
> +// gen_basic_std_iterator_tests.cpp.py by the build system as a dependency for
> +// cpp11-migrate's test suite.
> +//
> +// This file contains basic positive tests for the use-auto transform's ability
> +// to replace standard iterators. Variables considered:
> +// * All std container names
> +// * All std iterator names
> +//
> +//===----------------------------------------------------------------------===//
> +
> +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
> +// RUN: cpp11-migrate -use-auto %t.cpp -- -I %S/Inputs
>  // RUN: FileCheck -input-file=%t.cpp %s
> -// XFAIL: *
>  #include "my_std.h"
>
> -int main(int argc, char **argv) {"""
> +int main(int argc, char **argv) {""".lstrip() # Strip leading newline
>
>  for c in containers:
>    print """
>
> Added: clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/iterator.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/iterator.cpp?rev=176266&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/iterator.cpp (added)
> +++ clang-tools-extra/trunk/test/cpp11-migrate/UseAuto/iterator.cpp Thu Feb 28 10:29:24 2013
> @@ -0,0 +1,139 @@
> +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
> +// RUN: cpp11-migrate -use-auto %t.cpp -- --std=c++11 -I %gen_root/UseAuto/Inputs
> +// RUN: FileCheck -input-file=%t.cpp %s
> +#include "my_std.h"
> +
> +typedef std::vector<int>::iterator int_iterator;
> +
> +namespace foo {
> +  template <typename T>
> +  class vector {
> +  public:
> +    class iterator {};
> +
> +    iterator begin() { return iterator(); }
> +  };
> +} // namespace foo
> +
> +int main(int argc, char **argv) {
> +  std::vector<int> Vec;
> +  // CHECK: std::vector<int> Vec;
> +
> +  std::unordered_map<int> Map;
> +  // CHECK: std::unordered_map<int> Map;
> +
> +  // Types with more sugar should work. Types with less should not.
> +  {
> +    int_iterator more_sugar = Vec.begin();
> +    // CHECK: auto more_sugar = Vec.begin();
> +
> +    internal::iterator_wrapper<std::vector<int>, 0> less_sugar = Vec.begin();
> +    // CHECK: internal::iterator_wrapper<std::vector<int>, 0> less_sugar = Vec.begin();
> +  }
> +
> +  // Initialization from initializer lists isn't allowed. Using 'auto'
> +  // would result in std::initializer_list being deduced for the type.
> +  {
> +    std::unordered_map<int>::iterator I{Map.begin()};
> +    // CHECK: std::unordered_map<int>::iterator I{Map.begin()};
> +
> +    std::unordered_map<int>::iterator I2 = {Map.begin()};
> +    // CHECK: std::unordered_map<int>::iterator I2 = {Map.begin()};
> +  }
> +
> +  // Various forms of construction. Default constructors and constructors with
> +  // all-default parameters shouldn't get transformed. Construction from other
> +  // types is also not allowed.
> +  {
> +    std::unordered_map<int>::iterator copy(Map.begin());
> +    // CHECK: auto copy(Map.begin());
> +
> +    std::unordered_map<int>::iterator def;
> +    // CHECK: std::unordered_map<int>::iterator def;
> +
> +    // const_iterator has no default constructor, just one that has >0 params
> +    // with defaults.
> +    std::unordered_map<int>::const_iterator constI;
> +    // CHECK: std::unordered_map<int>::const_iterator constI;
> +
> +    // Uses iterator_provider::const_iterator's conversion constructor.
> +
> +    std::unordered_map<int>::const_iterator constI2 = def;
> +    // CHECK: std::unordered_map<int>::const_iterator constI2 = def;
> +
> +    std::unordered_map<int>::const_iterator constI3(def);
> +    // CHECK: std::unordered_map<int>::const_iterator constI3(def);
> +
> +    // Explicit use of conversion constructor
> +
> +    std::unordered_map<int>::const_iterator constI4 = std::unordered_map<int>::const_iterator(def);
> +    // CHECK: auto constI4 = std::unordered_map<int>::const_iterator(def);
> +
> +    // Uses iterator_provider::iterator's const_iterator conversion operator.
> +
> +    std::unordered_map<int>::iterator I = constI;
> +    // CHECK: std::unordered_map<int>::iterator I = constI;
> +
> +    std::unordered_map<int>::iterator I2(constI);
> +    // CHECK: std::unordered_map<int>::iterator I2(constI);
> +  }
> +
> +  // Weird cases of pointers and references to iterators are not transformed.
> +  {
> +    int_iterator I = Vec.begin();
> +
> +    int_iterator *IPtr = &I;
> +    // CHECK: int_iterator *IPtr = &I;
> +
> +    int_iterator &IRef = I;
> +    // CHECK: int_iterator &IRef = I;
> +  }
> +
> +  {
> +    // Variable declarations in iteration statements.
> +    for (std::vector<int>::iterator I = Vec.begin(); I != Vec.end(); ++I) {
> +      // CHECK: for (auto I = Vec.begin(); I != Vec.end(); ++I) {
> +    }
> +
> +    // Range-based for loops.
> +    std::array<std::vector<int>::iterator> iter_arr;
> +    for (std::vector<int>::iterator I: iter_arr) {
> +      // CHECK: for (auto I: iter_arr) {
> +    }
> +
> +    // Test with init-declarator-list.
> +    for (int_iterator I = Vec.begin(),
> +         E = Vec.end(); I != E; ++I) {
> +      // CHECK:      for (auto I = Vec.begin(),
> +      // CHECK-NEXT:      E = Vec.end(); I != E; ++I) {
> +    }
> +  }
> +
> +  // Only std containers should be changed.
> +  {
> +    using namespace foo;
> +    vector<int> foo_vec;
> +    vector<int>::iterator I = foo_vec.begin();
> +    // CHECK: vector<int>::iterator I = foo_vec.begin();
> +  }
> +
> +  // Ensure using directives don't interfere with replacement.
> +  {
> +    using namespace std;
> +    vector<int> std_vec;
> +    vector<int>::iterator I = std_vec.begin();
> +    // CHECK: auto I = std_vec.begin();
> +  }
> +
> +  // Make sure references and cv qualifiers don't get removed (i.e. replaced
> +  // with just 'auto').
> +  {
> +    const auto & I = Vec.begin();
> +    // CHECK: const auto & I = Vec.begin();
> +
> +    auto && I2 = Vec.begin();
> +    // CHECK: auto && I2 = Vec.begin();
> +  }
> +
> +  return 0;
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list