Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -1,5 +1,4 @@ add_subdirectory(clang-apply-replacements) -add_subdirectory(clang-modernize) add_subdirectory(clang-rename) add_subdirectory(modularize) if(CLANG_ENABLE_STATIC_ANALYZER) Index: Makefile =================================================================== --- Makefile +++ Makefile @@ -12,8 +12,7 @@ include $(CLANG_LEVEL)/../../Makefile.config PARALLEL_DIRS := tool-template modularize pp-trace -DIRS := clang-apply-replacements clang-modernize clang-rename clang-tidy \ - clang-query unittests +DIRS := clang-apply-replacements clang-rename clang-tidy clang-query unittests include $(CLANG_LEVEL)/Makefile Index: clang-modernize/AddOverride/AddOverride.h =================================================================== --- clang-modernize/AddOverride/AddOverride.h +++ /dev/null @@ -1,44 +0,0 @@ -//===-- AddOverride/AddOverride.h - add C++11 override ----------*- 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 AddOverrideTransform -/// class which is the main interface to the transform that tries to add the -/// override keyword to declarations of member function that override virtual -/// functions in a base class. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_ADD_OVERRIDE_H -#define CLANG_MODERNIZE_ADD_OVERRIDE_H - -#include "Core/Transform.h" -#include "llvm/Support/Compiler.h" - -class AddOverrideFixer; - -/// \brief Subclass of Transform that adds the C++11 override keyword to -/// member functions overriding base class virtual functions. -class AddOverrideTransform : public Transform { -public: - AddOverrideTransform(const TransformOptions &Options) - : Transform("AddOverride", Options) {} - - /// \see Transform::run(). - int apply(const clang::tooling::CompilationDatabase &Database, - const std::vector &SourcePaths) override; - - bool handleBeginSource(clang::CompilerInstance &CI, - llvm::StringRef Filename) override; - -private: - AddOverrideFixer *Fixer; -}; - -#endif // CLANG_MODERNIZE_ADD_OVERRIDE_H Index: clang-modernize/AddOverride/AddOverride.cpp =================================================================== --- clang-modernize/AddOverride/AddOverride.cpp +++ /dev/null @@ -1,85 +0,0 @@ -//===-- AddOverride/AddOverride.cpp - add C++11 override ------------------===// -// -// 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 AddOverrideTransform -/// class. -/// -//===----------------------------------------------------------------------===// - -#include "AddOverride.h" -#include "AddOverrideActions.h" -#include "AddOverrideMatchers.h" -#include "clang/Frontend/CompilerInstance.h" - -using clang::ast_matchers::MatchFinder; -using namespace clang::tooling; -using namespace clang; -namespace cl = llvm::cl; - -static cl::opt DetectMacros( - "override-macros", - cl::desc("Detect and use macros that expand to the 'override' keyword."), - cl::cat(TransformsOptionsCategory)); - -int AddOverrideTransform::apply(const CompilationDatabase &Database, - const std::vector &SourcePaths) { - ClangTool AddOverrideTool(Database, SourcePaths); - unsigned AcceptedChanges = 0; - MatchFinder Finder; - AddOverrideFixer Fixer(AcceptedChanges, DetectMacros, - /*Owner=*/ *this); - Finder.addMatcher(makeCandidateForOverrideAttrMatcher(), &Fixer); - - // Make Fixer available to handleBeginSource(). - this->Fixer = &Fixer; - - if (int result = AddOverrideTool.run(createActionFactory(Finder).get())) { - llvm::errs() << "Error encountered during translation.\n"; - return result; - } - - setAcceptedChanges(AcceptedChanges); - return 0; -} - -bool AddOverrideTransform::handleBeginSource(clang::CompilerInstance &CI, - llvm::StringRef Filename) { - assert(Fixer != nullptr && "Fixer must be set"); - Fixer->setPreprocessor(CI.getPreprocessor()); - return Transform::handleBeginSource(CI, Filename); -} - -namespace { -struct AddOverrideFactory : TransformFactory { - AddOverrideFactory() { - // if detecting macros is enabled, do not impose requirements on the - // compiler. It is assumed that the macros use is "C++11-aware", meaning it - // won't expand to override if the compiler doesn't support the specifier. - if (!DetectMacros) { - Since.Clang = Version(3, 0); - Since.Gcc = Version(4, 7); - Since.Icc = Version(14); - Since.Msvc = Version(8); - } - } - - Transform *createTransform(const TransformOptions &Opts) override { - return new AddOverrideTransform(Opts); - } -}; -} // namespace - -// Register the factory using this statically initialized variable. -static TransformFactoryRegistry::Add -X("add-override", "Make use of override specifier where possible"); - -// This anchor is used to force the linker to link in the generated object file -// and thus register the factory. -volatile int AddOverrideTransformAnchorSource = 0; Index: clang-modernize/AddOverride/AddOverrideActions.h =================================================================== --- clang-modernize/AddOverride/AddOverrideActions.h +++ /dev/null @@ -1,46 +0,0 @@ -//===-- AddOverride/AddOverrideActions.h - add C++11 override ---*- 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 AddOverrideFixer class -/// which is used as a ASTMatcher callback. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_ADD_OVERRIDE_ACTIONS_H -#define CLANG_MODERNIZE_ADD_OVERRIDE_ACTIONS_H - -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Tooling/Refactoring.h" - -class Transform; - -/// \brief The callback to be used for add-override migration matchers. -/// -class AddOverrideFixer : public clang::ast_matchers::MatchFinder::MatchCallback { -public: - AddOverrideFixer(unsigned &AcceptedChanges, bool DetectMacros, - Transform &Owner) - : AcceptedChanges(AcceptedChanges), DetectMacros(DetectMacros), - Owner(Owner) {} - - /// \brief Entry point to the callback called when matches are made. - void - run(const clang::ast_matchers::MatchFinder::MatchResult &Result) override; - - void setPreprocessor(clang::Preprocessor &PP) { this->PP = &PP; } - -private: - clang::Preprocessor *PP; - unsigned &AcceptedChanges; - bool DetectMacros; - Transform &Owner; -}; - -#endif // CLANG_MODERNIZE_ADD_OVERRIDE_ACTIONS_H Index: clang-modernize/AddOverride/AddOverrideActions.cpp =================================================================== --- clang-modernize/AddOverride/AddOverrideActions.cpp +++ /dev/null @@ -1,100 +0,0 @@ -//===-- AddOverride/AddOverrideActions.cpp - add C++11 override -----------===// -// -// 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 definition of the AddOverrideFixer class -/// which is used as an ASTMatcher callback. -/// -//===----------------------------------------------------------------------===// - -#include "AddOverrideActions.h" -#include "AddOverrideMatchers.h" -#include "Core/Transform.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Attr.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/Basic/CharInfo.h" -#include "clang/Lex/Lexer.h" -#include "clang/Lex/Preprocessor.h" - -using namespace clang::ast_matchers; -using namespace clang::tooling; -using namespace clang; - -namespace { - -SourceLocation -backwardSkipWhitespacesAndComments(const SourceManager &SM, - const clang::ASTContext &Context, - SourceLocation Loc) { - for (;;) { - do { - Loc = Loc.getLocWithOffset(-1); - } while (isWhitespace(*FullSourceLoc(Loc, SM).getCharacterData())); - - Token Tok; - SourceLocation Beginning = - Lexer::GetBeginningOfToken(Loc, SM, Context.getLangOpts()); - const bool Invalid = - Lexer::getRawToken(Beginning, Tok, SM, Context.getLangOpts()); - - assert(!Invalid && "Expected a valid token."); - if (Invalid || Tok.getKind() != tok::comment) - return Loc.getLocWithOffset(1); - } -} - -} // end anonymous namespace - -void AddOverrideFixer::run(const MatchFinder::MatchResult &Result) { - SourceManager &SM = *Result.SourceManager; - - const CXXMethodDecl *M = Result.Nodes.getDeclAs(MethodId); - assert(M && "Bad Callback. No node provided"); - - if (const FunctionDecl *TemplateMethod = M->getTemplateInstantiationPattern()) - M = cast(TemplateMethod); - - if (!Owner.isFileModifiable(SM, M->getLocStart())) - return; - - // First check that there isn't already an override attribute. - if (M->hasAttr()) - return; - - // FIXME: Pure methods are not supported yet as it is difficult to track down - // the location of '= 0'. - if (M->isPure()) - return; - - if (M->getParent()->hasAnyDependentBases()) - return; - - SourceLocation StartLoc; - if (M->hasInlineBody()) { - // Insert the override specifier before the function body. - StartLoc = backwardSkipWhitespacesAndComments(SM, *Result.Context, - M->getBody()->getLocStart()); - } else { - StartLoc = SM.getSpellingLoc(M->getLocEnd()); - StartLoc = Lexer::getLocForEndOfToken(StartLoc, 0, SM, LangOptions()); - } - - std::string ReplacementText = " override"; - if (DetectMacros) { - assert(PP && "No access to Preprocessor object for macro detection"); - clang::TokenValue Tokens[] = { PP->getIdentifierInfo("override") }; - llvm::StringRef MacroName = PP->getLastMacroWithSpelling(StartLoc, Tokens); - if (!MacroName.empty()) - ReplacementText = (" " + MacroName).str(); - } - Owner.addReplacementForCurrentTU( - tooling::Replacement(SM, StartLoc, 0, ReplacementText)); - ++AcceptedChanges; -} Index: clang-modernize/AddOverride/AddOverrideMatchers.h =================================================================== --- clang-modernize/AddOverride/AddOverrideMatchers.h +++ /dev/null @@ -1,28 +0,0 @@ -//===-- AddOverride/AddOverrideMatchers.h - add C++11 override --*- 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 CLANG_MODERNIZE_ADD_OVERRIDE_MATCHERS_H -#define CLANG_MODERNIZE_ADD_OVERRIDE_MATCHERS_H - -#include "clang/ASTMatchers/ASTMatchers.h" - -/// Name to bind with matched expressions. -extern const char *MethodId; - -/// \brief Create a matcher that finds member function declarations that are -/// candidates for adding the override attribute. -clang::ast_matchers::DeclarationMatcher makeCandidateForOverrideAttrMatcher(); - -#endif // CLANG_MODERNIZE_ADD_OVERRIDE_MATCHERS_H Index: clang-modernize/AddOverride/AddOverrideMatchers.cpp =================================================================== --- clang-modernize/AddOverride/AddOverrideMatchers.cpp +++ /dev/null @@ -1,29 +0,0 @@ -//===-- AddOverride/AddOverrideMatchers.cpp - C++11 override --------------===// -// -// 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 definitions for matcher-generating functions -/// and a custom AST_MATCHER for identifying casts of type CK_NullTo*. -/// -//===----------------------------------------------------------------------===// - -#include "AddOverrideMatchers.h" -#include "clang/AST/ASTContext.h" - -using namespace clang::ast_matchers; -using namespace clang; - -const char *MethodId = "method"; - -DeclarationMatcher makeCandidateForOverrideAttrMatcher() { - return cxxMethodDecl(hasParent(recordDecl()), - isOverride(), - unless(cxxDestructorDecl())).bind(MethodId); -} - Index: clang-modernize/CMakeLists.txt =================================================================== --- clang-modernize/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${ClangReplaceLocation} - ) - -add_subdirectory(tool) -add_subdirectory(Core) Index: clang-modernize/Core/CMakeLists.txt =================================================================== --- clang-modernize/Core/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -set(LLVM_LINK_COMPONENTS support) - -add_clang_library(modernizeCore - ReplacementHandling.cpp - Transforms.cpp - Transform.cpp - IncludeExcludeInfo.cpp - PerfSupport.cpp - IncludeDirectives.cpp - - LINK_LIBS - clangAST - clangASTMatchers - clangBasic - clangFrontend - clangLex - clangTooling - clangToolingCore - ) Index: clang-modernize/Core/CustomMatchers.h =================================================================== --- clang-modernize/Core/CustomMatchers.h +++ /dev/null @@ -1,59 +0,0 @@ -//===-- Core/CustomMatchers.h - Perf measurement helpers -----------*- 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 custom matchers to be used by different -/// transforms that requier the same matchers. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_CUSTOMMATCHERS_H -#define CLANG_MODERNIZE_CUSTOMMATCHERS_H - -#include "clang/ASTMatchers/ASTMatchers.h" - -namespace clang { -namespace ast_matchers { - -/// \brief Matches declarations whose declaration context is the C++ standard -/// library namespace \c std. -/// -/// Note that inline namespaces are silently ignored during the lookup since -/// both libstdc++ and libc++ are known to use them for versioning purposes. -/// -/// Given -/// \code -/// namespace ns { -/// struct my_type {}; -/// using namespace std; -/// } -/// -/// using std::vector; -/// using ns::my_type; -/// using ns::list; -/// \endcode -/// usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(isFromStdNamespace()))) -/// matches "using std::vector" and "using ns::list". -AST_MATCHER(Decl, isFromStdNamespace) { - const DeclContext *D = Node.getDeclContext(); - - while (D->isInlineNamespace()) - D = D->getParent(); - - if (!D->isNamespace() || !D->getParent()->isTranslationUnit()) - return false; - - const IdentifierInfo *Info = cast(D)->getIdentifier(); - - return Info && Info->isStr("std"); -} -} // namespace ast_matchers -} // namespace clang - -#endif // CLANG_MODERNIZE_CUSTOMMATCHERS_H Index: clang-modernize/Core/IncludeDirectives.h =================================================================== --- clang-modernize/Core/IncludeDirectives.h +++ /dev/null @@ -1,141 +0,0 @@ -//===-- Core/IncludeDirectives.h - Include directives handling --*- 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 declares the IncludeDirectives class that helps with -/// detecting and modifying \#include directives. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_INCLUDE_DIRECTIVES_H -#define CLANG_MODERNIZE_INCLUDE_DIRECTIVES_H - -#include "clang/Basic/SourceLocation.h" -#include "clang/Tooling/Refactoring.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringRef.h" -#include - -namespace clang { -class Preprocessor; -} // namespace clang - -/// \brief Support for include directives handling. -/// -/// This class should be created with a \c clang::CompilerInstance before the -/// file is preprocessed in order to collect the inclusion information. It can -/// be queried as long as the compiler instance is valid. -class IncludeDirectives { -public: - IncludeDirectives(clang::CompilerInstance &CI); - - /// \brief Add an angled include to a the given file. - /// - /// \param File A file accessible by a SourceManager - /// \param Include The include file as it should be written in the code. - /// - /// \returns \parblock - /// \li A null Replacement (check using \c Replacement::isApplicable()), if - /// the \c Include is already visible from \c File. - /// \li Otherwise, a non-null Replacement that, when applied, inserts an - /// \c \#include into \c File. - clang::tooling::Replacement addAngledInclude(llvm::StringRef File, - llvm::StringRef Include); - clang::tooling::Replacement addAngledInclude(const clang::FileEntry *File, - llvm::StringRef Include); - - /// \brief Check if \p Include is included by \p File or any of the files - /// \p File includes. - bool hasInclude(const clang::FileEntry *File, llvm::StringRef Include) const; - -private: - friend class IncludeDirectivesPPCallback; - - /// \brief Contains information about an inclusion. - class Entry { - public: - Entry(clang::SourceLocation HashLoc, const clang::FileEntry *IncludedFile, - bool Angled) - : HashLoc(HashLoc), IncludedFile(IncludedFile), Angled(Angled) {} - - /// \brief The location of the '#'. - clang::SourceLocation getHashLocation() const { return HashLoc; } - - /// \brief The file included by this include directive. - const clang::FileEntry *getIncludedFile() const { return IncludedFile; } - - /// \brief \c true if the include use angle brackets, \c false otherwise - /// when using of quotes. - bool isAngled() const { return Angled; } - - private: - clang::SourceLocation HashLoc; - const clang::FileEntry *IncludedFile; - bool Angled; - }; - - // A list of entries. - typedef std::vector EntryVec; - - // A list of source locations. - typedef std::vector LocationVec; - - // Associates files to their includes. - typedef llvm::DenseMap FileToEntriesMap; - - // Associates headers to their include guards if any. The location is the - // location of the hash from the #define. - typedef llvm::DenseMap - HeaderToGuardMap; - - /// \brief Type used by \c lookForInclude() to keep track of the files that - /// have already been processed. - typedef llvm::SmallPtrSet SeenFilesSet; - - /// \brief Recursively look if an include is included by \p File or any of the - /// headers \p File includes. - /// - /// \param File The file where to start the search. - /// \param IncludeLocs These are the hash locations of the \#include - /// directives we are looking for. - /// \param Seen Used to avoid visiting a same file more than once during the - /// recursion. - bool lookForInclude(const clang::FileEntry *File, - const LocationVec &IncludeLocs, SeenFilesSet &Seen) const; - - /// \brief Find the end of a file header and returns a pair (FileOffset, - /// NewLineFlags). - /// - /// Source files often contain a file header (copyright, license, explanation - /// of the file content). An \#include should preferably be put after this. - std::pair - findFileHeaderEndOffset(clang::FileID FID) const; - - /// \brief Finds the offset where an angled include should be added and - /// returns a pair (FileOffset, NewLineFlags). - std::pair - angledIncludeInsertionOffset(clang::FileID FID) const; - - /// \brief Find the location of an include directive that can be used to - /// insert an inclusion after. - /// - /// If no such include exists returns a null SourceLocation. - clang::SourceLocation angledIncludeHintLoc(clang::FileID FID) const; - - clang::CompilerInstance &CI; - clang::SourceManager &Sources; - FileToEntriesMap FileToEntries; - // maps include filename as written in the source code to the source locations - // where it appears - llvm::StringMap IncludeAsWrittenToLocationsMap; - HeaderToGuardMap HeaderToGuard; -}; - -#endif // CLANG_MODERNIZE_INCLUDE_DIRECTIVES_H Index: clang-modernize/Core/IncludeDirectives.cpp =================================================================== --- clang-modernize/Core/IncludeDirectives.cpp +++ /dev/null @@ -1,480 +0,0 @@ -//===-- Core/IncludeDirectives.cpp - Include directives handling ----------===// -// -// 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 defines the IncludeDirectives class that helps with -/// detecting and modifying \#include directives. -/// -//===----------------------------------------------------------------------===// - -#include "IncludeDirectives.h" -#include "clang/Basic/CharInfo.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/Preprocessor.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include - -using namespace clang; -using namespace clang::tooling; -using llvm::StringRef; - -/// \brief PPCallbacks that fills-in the include information in the given -/// \c IncludeDirectives. -class IncludeDirectivesPPCallback : public clang::PPCallbacks { - // Struct helping the detection of header guards in the various callbacks - struct GuardDetection { - GuardDetection(FileID FID) - : FID(FID), Count(0), TheMacro(nullptr), CountAtEndif(0) {} - - FileID FID; - // count for relevant preprocessor directives - unsigned Count; - // the macro that is tested in the top most ifndef for the header guard - // (e.g: GUARD_H) - const IdentifierInfo *TheMacro; - // the hash locations of #ifndef, #define, #endif - SourceLocation IfndefLoc, DefineLoc, EndifLoc; - // the value of Count once the #endif is reached - unsigned CountAtEndif; - - /// \brief Check that with all the information gathered if this is a - /// potential header guard. - /// - /// Meaning a top-most \#ifndef has been found, followed by a define and the - /// last preprocessor directive was the terminating \#endif. - /// - /// FIXME: accept the \#if !defined identifier form too. - bool isPotentialHeaderGuard() const { - return Count == CountAtEndif && DefineLoc.isValid(); - } - }; - -public: - IncludeDirectivesPPCallback(IncludeDirectives *Self) - : Self(Self), Guard(nullptr) {} - ~IncludeDirectivesPPCallback() override {} - -private: - void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, - StringRef FileName, bool IsAngled, - CharSourceRange FilenameRange, const FileEntry *File, - StringRef SearchPath, StringRef RelativePath, - const Module *Imported) override { - SourceManager &SM = Self->Sources; - const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(HashLoc)); - assert(FE && "Valid file expected."); - - IncludeDirectives::Entry E(HashLoc, File, IsAngled); - Self->FileToEntries[FE].push_back(E); - Self->IncludeAsWrittenToLocationsMap[FileName].push_back(HashLoc); - } - - // Keep track of the current file in the stack - void FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType, - FileID PrevFID) override { - SourceManager &SM = Self->Sources; - switch (Reason) { - case EnterFile: - Files.push(GuardDetection(SM.getFileID(Loc))); - Guard = &Files.top(); - break; - - case ExitFile: - if (Guard->isPotentialHeaderGuard()) - handlePotentialHeaderGuard(*Guard); - Files.pop(); - Guard = &Files.top(); - break; - - default: - break; - } - } - - /// \brief Mark this header as guarded in the IncludeDirectives if it's a - /// proper header guard. - void handlePotentialHeaderGuard(const GuardDetection &Guard) { - SourceManager &SM = Self->Sources; - const FileEntry *File = SM.getFileEntryForID(Guard.FID); - const LangOptions &LangOpts = Self->CI.getLangOpts(); - - // Null file can happen for the buffer for example. They - // shouldn't have header guards though... - if (!File) - return; - - // The #ifndef should be the next thing after the preamble. We aren't - // checking for equality because it can also be part of the preamble if the - // preamble is the whole file. - unsigned Preamble = - Lexer::ComputePreamble(SM.getBuffer(Guard.FID)->getBuffer(), LangOpts) - .first; - unsigned IfndefOffset = SM.getFileOffset(Guard.IfndefLoc); - if (IfndefOffset > (Preamble + 1)) - return; - - // No code is allowed in the code remaining after the #endif. - const llvm::MemoryBuffer *Buffer = SM.getBuffer(Guard.FID); - Lexer Lex(SM.getLocForStartOfFile(Guard.FID), LangOpts, - Buffer->getBufferStart(), - Buffer->getBufferStart() + SM.getFileOffset(Guard.EndifLoc), - Buffer->getBufferEnd()); - - // Find the first newline not part of a multi-line comment. - Token Tok; - Lex.LexFromRawLexer(Tok); // skip endif - Lex.LexFromRawLexer(Tok); - - // Not a proper header guard, the remainder of the file contains something - // else than comments or whitespaces. - if (Tok.isNot(tok::eof)) - return; - - // Add to the location of the define to the IncludeDirectives for this file. - Self->HeaderToGuard[File] = Guard.DefineLoc; - } - - void Ifndef(SourceLocation Loc, const Token &MacroNameTok, - const MacroDefinition &MD) override { - Guard->Count++; - - // If this #ifndef is the top-most directive and the symbol isn't defined - // store those information in the guard detection, the next step will be to - // check for the define. - if (Guard->Count == 1 && !MD) { - IdentifierInfo *MII = MacroNameTok.getIdentifierInfo(); - - Guard->IfndefLoc = Loc; - Guard->TheMacro = MII; - } - } - - void MacroDefined(const Token &MacroNameTok, - const MacroDirective *MD) override { - Guard->Count++; - - // If this #define is the second directive of the file and the symbol - // defined is the same as the one checked in the #ifndef then store the - // information about this define. - if (Guard->Count == 2 && Guard->TheMacro != nullptr) { - IdentifierInfo *MII = MacroNameTok.getIdentifierInfo(); - - // macro unrelated to the ifndef, doesn't look like a proper header guard - if (MII->getName() != Guard->TheMacro->getName()) - return; - - Guard->DefineLoc = MacroNameTok.getLocation(); - } - } - - void Endif(SourceLocation Loc, SourceLocation IfLoc) override { - Guard->Count++; - - // If it's the #endif corresponding to the top-most #ifndef - if (Self->Sources.getDecomposedLoc(Guard->IfndefLoc) != - Self->Sources.getDecomposedLoc(IfLoc)) - return; - - // And that the top-most #ifndef was followed by the right #define - if (Guard->DefineLoc.isInvalid()) - return; - - // Then save the information about this #endif. Once the file is exited we - // will check if it was the final preprocessor directive. - Guard->CountAtEndif = Guard->Count; - Guard->EndifLoc = Loc; - } - - void MacroExpands(const Token &, const MacroDefinition &, SourceRange, - const MacroArgs *) override { - Guard->Count++; - } - void MacroUndefined(const Token &, const MacroDefinition &) override { - Guard->Count++; - } - void Defined(const Token &, const MacroDefinition &, SourceRange) override { - Guard->Count++; - } - void If(SourceLocation, SourceRange, ConditionValueKind) override { - Guard->Count++; - } - void Elif(SourceLocation, SourceRange, ConditionValueKind, - SourceLocation) override { - Guard->Count++; - } - void Ifdef(SourceLocation, const Token &, const MacroDefinition &) override { - Guard->Count++; - } - void Else(SourceLocation, SourceLocation) override { - Guard->Count++; - } - - IncludeDirectives *Self; - // keep track of the guard info through the include stack - std::stack Files; - // convenience field pointing to Files.top().second - GuardDetection *Guard; -}; - -// Flags that describes where to insert newlines. -enum NewLineFlags { - // Prepend a newline at the beginning of the insertion. - NL_Prepend = 0x1, - - // Prepend another newline at the end of the insertion. - NL_PrependAnother = 0x2, - - // Add two newlines at the end of the insertion. - NL_AppendTwice = 0x4, - - // Convenience value to enable both \c NL_Prepend and \c NL_PrependAnother. - NL_PrependTwice = NL_Prepend | NL_PrependAnother -}; - -/// \brief Guess the end-of-line sequence used in the given FileID. If the -/// sequence can't be guessed return an Unix-style newline. -static StringRef guessEOL(SourceManager &SM, FileID ID) { - StringRef Content = SM.getBufferData(ID); - StringRef Buffer = Content.substr(Content.find_first_of("\r\n")); - - return llvm::StringSwitch(Buffer) - .StartsWith("\r\n", "\r\n") - .StartsWith("\n\r", "\n\r") - .StartsWith("\r", "\r") - .Default("\n"); -} - -/// \brief Find the end of the end of the directive, either the beginning of a -/// newline or the end of file. -// -// \return The offset into the file where the directive ends along with a -// boolean value indicating whether the directive ends because the end of file -// was reached or not. -static std::pair findDirectiveEnd(SourceLocation HashLoc, - SourceManager &SM, - const LangOptions &LangOpts) { - FileID FID = SM.getFileID(HashLoc); - unsigned Offset = SM.getFileOffset(HashLoc); - StringRef Content = SM.getBufferData(FID); - Lexer Lex(SM.getLocForStartOfFile(FID), LangOpts, Content.begin(), - Content.begin() + Offset, Content.end()); - Lex.SetCommentRetentionState(true); - Token Tok; - - // This loop look for the newline after our directive but avoids the ones part - // of a multi-line comments: - // - // #include /* long \n comment */\n - // ~~ no ~~ yes - for (;;) { - // find the beginning of the end-of-line sequence - StringRef::size_type EOLOffset = Content.find_first_of("\r\n", Offset); - // ends because EOF was reached - if (EOLOffset == StringRef::npos) - return std::make_pair(Content.size(), true); - - // find the token that contains our end-of-line - unsigned TokEnd = 0; - do { - Lex.LexFromRawLexer(Tok); - TokEnd = SM.getFileOffset(Tok.getLocation()) + Tok.getLength(); - - // happens when the whitespaces are eaten after a multiline comment - if (Tok.is(tok::eof)) - return std::make_pair(EOLOffset, false); - } while (TokEnd < EOLOffset); - - // the end-of-line is not part of a multi-line comment, return its location - if (Tok.isNot(tok::comment)) - return std::make_pair(EOLOffset, false); - - // for the next search to start after the end of this token - Offset = TokEnd; - } -} - -IncludeDirectives::IncludeDirectives(clang::CompilerInstance &CI) - : CI(CI), Sources(CI.getSourceManager()) { - // addPPCallbacks takes ownership of the callback - CI.getPreprocessor().addPPCallbacks( - llvm::make_unique(this)); -} - -bool IncludeDirectives::lookForInclude(const FileEntry *File, - const LocationVec &IncludeLocs, - SeenFilesSet &Seen) const { - // mark this file as visited - Seen.insert(File); - - // First check if included directly in this file - for (LocationVec::const_iterator I = IncludeLocs.begin(), - E = IncludeLocs.end(); - I != E; ++I) - if (Sources.getFileEntryForID(Sources.getFileID(*I)) == File) - return true; - - // Otherwise look recursively all the included files - FileToEntriesMap::const_iterator EntriesIt = FileToEntries.find(File); - if (EntriesIt == FileToEntries.end()) - return false; - for (EntryVec::const_iterator I = EntriesIt->second.begin(), - E = EntriesIt->second.end(); - I != E; ++I) { - // skip if this header has already been checked before - if (Seen.count(I->getIncludedFile())) - continue; - if (lookForInclude(I->getIncludedFile(), IncludeLocs, Seen)) - return true; - } - return false; -} - -bool IncludeDirectives::hasInclude(const FileEntry *File, - StringRef Include) const { - llvm::StringMap::const_iterator It = - IncludeAsWrittenToLocationsMap.find(Include); - - // Include isn't included in any file - if (It == IncludeAsWrittenToLocationsMap.end()) - return false; - - SeenFilesSet Seen; - return lookForInclude(File, It->getValue(), Seen); -} - -Replacement IncludeDirectives::addAngledInclude(const clang::FileEntry *File, - llvm::StringRef Include) { - FileID FID = Sources.translateFile(File); - assert(FID.isValid() && "Invalid file entry given!"); - - if (hasInclude(File, Include)) - return Replacement(); - - unsigned Offset, NLFlags; - std::tie(Offset, NLFlags) = angledIncludeInsertionOffset(FID); - - StringRef EOL = guessEOL(Sources, FID); - llvm::SmallString<32> InsertionText; - if (NLFlags & NL_Prepend) - InsertionText += EOL; - if (NLFlags & NL_PrependAnother) - InsertionText += EOL; - InsertionText += "#include <"; - InsertionText += Include; - InsertionText += ">"; - if (NLFlags & NL_AppendTwice) { - InsertionText += EOL; - InsertionText += EOL; - } - return Replacement(File->getName(), Offset, 0, InsertionText); -} - -Replacement IncludeDirectives::addAngledInclude(llvm::StringRef File, - llvm::StringRef Include) { - const FileEntry *Entry = Sources.getFileManager().getFile(File); - assert(Entry && "Invalid file given!"); - return addAngledInclude(Entry, Include); -} - -std::pair -IncludeDirectives::findFileHeaderEndOffset(FileID FID) const { - unsigned NLFlags = NL_Prepend; - StringRef Content = Sources.getBufferData(FID); - Lexer Lex(Sources.getLocForStartOfFile(FID), CI.getLangOpts(), - Content.begin(), Content.begin(), Content.end()); - Lex.SetCommentRetentionState(true); - Lex.SetKeepWhitespaceMode(true); - - // find the first newline not part of a multi-line comment - Token Tok; - do { - Lex.LexFromRawLexer(Tok); - unsigned Offset = Sources.getFileOffset(Tok.getLocation()); - // allow one newline between the comments - if (Tok.is(tok::unknown) && isWhitespace(Content[Offset])) { - StringRef Whitespaces(Content.substr(Offset, Tok.getLength())); - if (Whitespaces.count('\n') == 1 || Whitespaces.count('\r') == 1) - Lex.LexFromRawLexer(Tok); - else { - // add an empty line to separate the file header and the inclusion - NLFlags = NL_PrependTwice; - } - } - } while (Tok.is(tok::comment)); - - // apparently there is no header, insertion point is the beginning of the file - if (Tok.isNot(tok::unknown)) - return std::make_pair(0, NL_AppendTwice); - return std::make_pair(Sources.getFileOffset(Tok.getLocation()), NLFlags); -} - -SourceLocation -IncludeDirectives::angledIncludeHintLoc(FileID FID) const { - FileToEntriesMap::const_iterator EntriesIt = - FileToEntries.find(Sources.getFileEntryForID(FID)); - - if (EntriesIt == FileToEntries.end()) - return SourceLocation(); - - HeaderSearch &HeaderInfo = CI.getPreprocessor().getHeaderSearchInfo(); - const EntryVec &Entries = EntriesIt->second; - EntryVec::const_reverse_iterator QuotedCandidate = Entries.rend(); - for (EntryVec::const_reverse_iterator I = Entries.rbegin(), - E = Entries.rend(); - I != E; ++I) { - // Headers meant for multiple inclusion can potentially appears in the - // middle of the code thus making them a poor choice for an insertion point. - if (!HeaderInfo.isFileMultipleIncludeGuarded(I->getIncludedFile())) - continue; - - // return preferably the last angled include - if (I->isAngled()) - return I->getHashLocation(); - - // keep track of the last quoted include that is guarded - if (QuotedCandidate == Entries.rend()) - QuotedCandidate = I; - } - - if (QuotedCandidate == Entries.rend()) - return SourceLocation(); - - // return the last quoted-include if we couldn't find an angled one - return QuotedCandidate->getHashLocation(); -} - -std::pair -IncludeDirectives::angledIncludeInsertionOffset(FileID FID) const { - SourceLocation Hint = angledIncludeHintLoc(FID); - unsigned NL_Flags = NL_Prepend; - - // If we can't find a similar include and we are in a header check if it's a - // guarded header. If so the hint will be the location of the #define from the - // guard. - if (Hint.isInvalid()) { - const FileEntry *File = Sources.getFileEntryForID(FID); - HeaderToGuardMap::const_iterator GuardIt = HeaderToGuard.find(File); - if (GuardIt != HeaderToGuard.end()) { - // get the hash location from the #define - Hint = GuardIt->second; - // we want a blank line between the #define and the #include - NL_Flags = NL_PrependTwice; - } - } - - // no hints, insertion is done after the file header - if (Hint.isInvalid()) - return findFileHeaderEndOffset(FID); - - unsigned Offset = findDirectiveEnd(Hint, Sources, CI.getLangOpts()).first; - return std::make_pair(Offset, NL_Flags); -} Index: clang-modernize/Core/IncludeExcludeInfo.h =================================================================== --- clang-modernize/Core/IncludeExcludeInfo.h +++ /dev/null @@ -1,62 +0,0 @@ -//===-- Core/IncludeExcludeInfo.h - IncludeExclude class def'n --*- 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 for the IncludeExcludeInfo class -/// to handle the include and exclude command line options. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_INCLUDEEXCLUDEINFO_H -#define CLANG_MODERNIZE_INCLUDEEXCLUDEINFO_H - -#include "llvm/ADT/StringRef.h" -#include -#include - -/// \brief Class encapsulating the handling of include and exclude paths -/// provided by the user through command line options. -class IncludeExcludeInfo { -public: - /// \brief Read and parse a comma-separated lists of paths from - /// \a IncludeString and \a ExcludeString. - /// - /// Returns error_code::success() on successful parse of the strings or - /// an error_code indicating the encountered error. - std::error_code readListFromString(llvm::StringRef IncludeString, - llvm::StringRef ExcludeString); - - /// \brief Read and parse the lists of paths from \a IncludeListFile - /// and \a ExcludeListFile. Each file should contain one path per line. - /// - /// Returns error_code::success() on successful read and parse of both files - /// or an error_code indicating the encountered error. - std::error_code readListFromFile(llvm::StringRef IncludeListFile, - llvm::StringRef ExcludeListFile); - - /// \brief Determine if the given path is in the list of include paths but - /// not in the list of exclude paths. - /// - /// \a FilePath shouldn't contain relative operators i.e. ".." or "." since - /// Path comes from the include/exclude list of paths in which relative - /// operators were removed. - bool isFileIncluded(llvm::StringRef FilePath) const; - - /// \brief Determine if a file path was explicitly excluded. - bool isFileExplicitlyExcluded(llvm::StringRef FilePath) const; - - /// \brief Determine if a list of include paths was provided. - bool isIncludeListEmpty() const { return IncludeList.empty(); } - -private: - std::vector IncludeList; - std::vector ExcludeList; -}; - -#endif // CLANG_MODERNIZE_INCLUDEEXCLUDEINFO_H Index: clang-modernize/Core/IncludeExcludeInfo.cpp =================================================================== --- clang-modernize/Core/IncludeExcludeInfo.cpp +++ /dev/null @@ -1,179 +0,0 @@ -//===-- Core/IncludeExcludeInfo.cpp - IncludeExclude class 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 provides the implementation of the IncludeExcludeInfo class -/// to handle the include and exclude command line options. -/// -//===----------------------------------------------------------------------===// - -#include "IncludeExcludeInfo.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; - -/// A string type to represent paths. -typedef SmallString<64> PathString; - -namespace { -/// \brief Helper function to determine whether a file has the same path -/// prefix as \a Path. -/// -/// \a Path must be an absolute path. -bool fileHasPathPrefix(StringRef File, StringRef Path) { - // Converts File to its absolute path. - PathString AbsoluteFile = File; - sys::fs::make_absolute(AbsoluteFile); - - // Convert path strings to sys::path to iterate over each of its directories. - sys::path::const_iterator FileI = sys::path::begin(AbsoluteFile), - FileE = sys::path::end(AbsoluteFile), - PathI = sys::path::begin(Path), - PathE = sys::path::end(Path); - while (FileI != FileE && PathI != PathE) { - // If the strings aren't equal then the two paths aren't contained within - // each other. - bool IsSeparator = ((FileI->size() == 1) && (PathI->size() == 1) && - sys::path::is_separator((*FileI)[0]) && - sys::path::is_separator((*PathI)[0])); - if (!FileI->equals(*PathI) && !IsSeparator) - return false; - ++FileI; - ++PathI; - } - return true; -} - -/// \brief Helper function for removing relative operators from a given -/// path i.e. "..", ".". -/// \a Path must be a absolute path. -std::string removeRelativeOperators(StringRef Path) { - sys::path::const_iterator PathI = sys::path::begin(Path); - sys::path::const_iterator PathE = sys::path::end(Path); - SmallVector PathT; - while (PathI != PathE) { - if (PathI->equals("..")) { - // Test if we have reached the root then Path is invalid. - if (PathT.empty()) - return ""; - PathT.pop_back(); - } else if (!PathI->equals(".")) - PathT.push_back(*PathI); - ++PathI; - } - // Rebuild the new path. - PathString NewPath; - for (SmallVectorImpl::iterator I = PathT.begin(), E = PathT.end(); - I != E; ++I) { - llvm::sys::path::append(NewPath, *I); - } - return NewPath.str(); -} - -/// \brief Helper function to tokenize a string of paths and populate -/// the vector. -std::error_code parseCLInput(StringRef Line, std::vector &List, - StringRef Separator) { - SmallVector Tokens; - Line.split(Tokens, Separator, /*MaxSplit=*/ -1, /*KeepEmpty=*/ false); - for (SmallVectorImpl::iterator I = Tokens.begin(), - E = Tokens.end(); - I != E; ++I) { - // Convert each path to its absolute path. - PathString Path = I->rtrim(); - if (std::error_code Err = sys::fs::make_absolute(Path)) - return Err; - // Remove relative operators from the path. - std::string AbsPath = removeRelativeOperators(Path); - // Add only non-empty paths to the list. - if (!AbsPath.empty()) - List.push_back(AbsPath); - else - llvm::errs() << "Unable to parse input path: " << *I << "\n"; - - llvm::errs() << "Parse: " <> FileBuf = - MemoryBuffer::getFile(IncludeListFile); - if (std::error_code Err = FileBuf.getError()) { - errs() << "Unable to read from include file.\n"; - return Err; - } - if (std::error_code Err = - parseCLInput(FileBuf.get()->getBuffer(), IncludeList, - /*Separator=*/"\n")) - return Err; - } - if (!ExcludeListFile.empty()) { - ErrorOr> FileBuf = - MemoryBuffer::getFile(ExcludeListFile); - if (std::error_code Err = FileBuf.getError()) { - errs() << "Unable to read from exclude file.\n"; - return Err; - } - if (std::error_code Err = - parseCLInput(FileBuf.get()->getBuffer(), ExcludeList, - /*Separator=*/"\n")) - return Err; - } - return std::error_code(); -} - -bool IncludeExcludeInfo::isFileIncluded(StringRef FilePath) const { - bool InIncludeList = false; - - for (std::vector::const_iterator I = IncludeList.begin(), - E = IncludeList.end(); - I != E; ++I) - if ((InIncludeList = fileHasPathPrefix(FilePath, *I))) - break; - - // If file is not in the list of included paths then it is not necessary - // to check the excluded path list. - if (!InIncludeList) - return false; - - // If the file is in the included list but not is not explicitly excluded, - // then it is safe to transform. - return !isFileExplicitlyExcluded(FilePath); -} - -bool IncludeExcludeInfo::isFileExplicitlyExcluded(StringRef FilePath) const { - for (std::vector::const_iterator I = ExcludeList.begin(), - E = ExcludeList.end(); - I != E; ++I) - if (fileHasPathPrefix(FilePath, *I)) - return true; - - return false; -} Index: clang-modernize/Core/Makefile =================================================================== --- clang-modernize/Core/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- clang-modernize/Core/Makefile -----------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -CLANG_LEVEL := ../../../.. -LIBRARYNAME := modernizeCore - -include $(CLANG_LEVEL)/Makefile - -CPP.Flags += -I$(PROJ_SRC_DIR)/.. -I$(PROJ_SRC_DIR)/../../clang-apply-replacements/include Index: clang-modernize/Core/PerfSupport.h =================================================================== --- clang-modernize/Core/PerfSupport.h +++ /dev/null @@ -1,56 +0,0 @@ -//===-- Core/PerfSupport.h - Perf measurement helpers -----------*- 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 helper functionality for measuring performance and -/// recording data to file. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_PERFSUPPORT_H -#define CLANG_MODERNIZE_PERFSUPPORT_H - -#include "Transform.h" -#include "llvm/ADT/StringRef.h" -#include -#include - -/// \brief A single piece of performance data: a duration in milliseconds and a -/// label for that duration. -struct PerfItem { - PerfItem(const llvm::StringRef Label, float Duration) - : Label(Label), Duration(Duration) {} - - /// Label for this performance measurement. - std::string Label; - - /// Duration in milliseconds. - float Duration; -}; - -/// Maps source file names to a vector of durations/labels. -typedef std::map > SourcePerfData; - -/// Extracts durations collected by a Transform for all sources and adds them -/// to a SourcePerfData map where data is organized by source file. -extern void collectSourcePerfData(const Transform &T, SourcePerfData &Data); - -/// Write timing results to a JSON formatted file. -/// -/// File is placed in the directory given by \p DirectoryName. File is named in -/// a unique way with time and process ID to avoid naming collisions with -/// existing files or files being generated by other migrator processes. -void writePerfDataJSON( - const llvm::StringRef DirectoryName, - const SourcePerfData &TimingResults); - -/// Dump a SourcePerfData map to llvm::errs(). -extern void dumpPerfData(const SourcePerfData &Data); - -#endif // CLANG_MODERNIZE_PERFSUPPORT_H Index: clang-modernize/Core/PerfSupport.cpp =================================================================== --- clang-modernize/Core/PerfSupport.cpp +++ /dev/null @@ -1,101 +0,0 @@ -//===-- Core/PerfSupport.cpp - Perf measurement helpers -------------------===// -// -// 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 implementations for performance measuring helpers. -/// -//===----------------------------------------------------------------------===// - -#include "PerfSupport.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/raw_ostream.h" - -void collectSourcePerfData(const Transform &T, SourcePerfData &Data) { - for (Transform::TimingVec::const_iterator I = T.timing_begin(), - E = T.timing_end(); - I != E; ++I) { - SourcePerfData::iterator DataI = Data.insert( - SourcePerfData::value_type(I->first, std::vector())).first; - DataI->second - .push_back(PerfItem(T.getName(), I->second.getProcessTime() * 1000.0)); - } -} - -void writePerfDataJSON( - const llvm::StringRef DirectoryName, - const SourcePerfData &TimingResults) { - // Create directory path if it doesn't exist - llvm::sys::fs::create_directories(DirectoryName); - - // Get PID and current time. - // FIXME: id_type on Windows is NOT a process id despite the function name. - // Need to call GetProcessId() providing it what get_id() returns. For now - // disabling PID-based file names until this is fixed properly. - //llvm::sys::self_process *SP = llvm::sys::process::get_self(); - //id_type Pid = SP->get_id(); - unsigned Pid = 0; - llvm::TimeRecord T = llvm::TimeRecord::getCurrentTime(); - - std::string FileName; - llvm::raw_string_ostream SS(FileName); - SS << DirectoryName << "/" << static_cast(T.getWallTime()) << "_" << Pid - << ".json"; - - std::error_code EC; - llvm::raw_fd_ostream FileStream(SS.str(), EC, llvm::sys::fs::F_Text); - FileStream << "{\n"; - FileStream << " \"Sources\" : [\n"; - for (SourcePerfData::const_iterator I = TimingResults.begin(), - E = TimingResults.end(); - I != E; ++I) { - // Terminate the last source with a comma before continuing to the next one. - if (I != TimingResults.begin()) - FileStream << ",\n"; - - FileStream << " {\n"; - FileStream << " \"Source \" : \"" << I->first << "\",\n"; - FileStream << " \"Data\" : [\n"; - for (std::vector::const_iterator IE = I->second.begin(), - EE = I->second.end(); - IE != EE; ++IE) { - // Terminate the last perf item with a comma before continuing to the next - // one. - if (IE != I->second.begin()) - FileStream << ",\n"; - - FileStream << " {\n"; - FileStream << " \"TimerId\" : \"" << IE->Label << "\",\n"; - FileStream << " \"Time\" : " << llvm::format("%.2f", IE->Duration) - << "\n"; - - FileStream << " }"; - - } - FileStream << "\n ]\n"; - FileStream << " }"; - } - FileStream << "\n ]\n"; - FileStream << "}"; -} - -void dumpPerfData(const SourcePerfData &Data) { - for (SourcePerfData::const_iterator I = Data.begin(), E = Data.end(); I != E; - ++I) { - llvm::errs() << I->first << ":\n"; - for (std::vector::const_iterator VecI = I->second.begin(), - VecE = I->second.end(); - VecI != VecE; ++VecI) { - llvm::errs() << " " << VecI->Label << ": " - << llvm::format("%.1f", VecI->Duration) << "ms\n"; - } - } -} Index: clang-modernize/Core/Refactoring.h =================================================================== --- clang-modernize/Core/Refactoring.h +++ /dev/null @@ -1,31 +0,0 @@ -//===-- Core/Refactoring.h - Stand-in for Tooling/Refactoring.h -*- 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 is meant to be used instead of clang/Tooling/Refactoring.h -/// until such time as clang::tooling::Replacements is re-implemented as a -/// vector instead of a set. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_REPLACEMENTS_VEC_H -#define CLANG_MODERNIZE_REPLACEMENTS_VEC_H - -#include "clang/Tooling/Refactoring.h" - -// FIXME: Remove this file when clang::tooling::Replacements becomes a vector -// instead of a set. - -namespace clang { -namespace tooling { -typedef std::vector ReplacementsVec; -} -} - -#endif // CLANG_MODERNIZE_REPLACEMENTS_VEC_H Index: clang-modernize/Core/ReplacementHandling.h =================================================================== --- clang-modernize/Core/ReplacementHandling.h +++ /dev/null @@ -1,127 +0,0 @@ -//===-- Core/ReplacementHandling.h ------------------------------*- 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 defines the ReplacementHandling class which abstracts -/// serialization and application of serialized replacements. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_REPLACEMENTHANDLING_H -#define CLANG_MODERNIZE_REPLACEMENTHANDLING_H - -#include "Core/Transform.h" -#include "llvm/ADT/StringRef.h" - -class ReplacementHandling { -public: - - ReplacementHandling() : DoFormat(false) {} - - /// \brief Finds the path to the executable 'clang-apply-replacements'. - /// - /// The executable is searched for on the PATH. If not found, looks in the - /// same directory as the image used to start the current executable. - /// - /// \param[in] Argv0 argv[0] as passed to main(). - /// - /// \returns \parblock - /// \li true if clang-apply-replacements was found. - /// \li false otherwise. - bool findClangApplyReplacements(const char *Argv0); - - /// \brief Set the name of the directory in which replacements will be - /// serialized. - /// - /// \param[in] Dir Destination directory name - void setDestinationDir(llvm::StringRef Dir) { DestinationDir = Dir; } - - /// \brief Create a new temporary directory to serialize replacements into. - /// - /// \returns The name of the directory createdy. - llvm::StringRef useTempDestinationDir(); - - /// \brief Enable clang-apply-replacements do code reformatting when applying - /// serialized replacements. - /// - /// \param[in] Style Value to pass to clang-apply-replacement's --style - /// option. - /// \param[in] StyleConfigDir If non-empty, value to pass to - /// clang-apply-replacement's --style-config option. - void enableFormatting(llvm::StringRef Style, - llvm::StringRef StyleConfigDir = ""); - - /// \brief Write all TranslationUnitReplacements stored in \c Replacements - /// to disk. - /// - /// \pre Destination directory must have been previously set by calling - /// setDestiantionDir() or useTempDestinationDir(). - /// \pre Destination dir must exist. - /// - /// \param[in] Replacements Container of replacements to serialize. - /// - /// \returns \parblock - /// \li true if all replacements were serialized successfully to - /// disk. - /// \li false otherwise. - bool serializeReplacements(const TUReplacementsMap &Replacements); - - /// \brief Invoke clang-apply-replacements to apply all serialized - /// replacements stored in the destination directory. - /// - /// \pre Destination directory must have been previously set by calling - /// setDestiantionDir() or useTempDestinationDir(). - /// - /// \returns \parblock - /// \li true if clang-apply-replacements was successfully launched - /// and successfully completed. - /// \li false otherwise. - bool applyReplacements(); - - /// \brief Generate a unique filename to store the replacements. - /// - /// Generates a unique filename in \c DestinationDir. The filename is generated - /// following this pattern: - /// - /// DestinationDir/Prefix_%%_%%_%%_%%_%%_%%.yaml - /// - /// where Prefix := llvm::sys::path::filename(MainSourceFile) and all '%' will - /// be replaced by a randomly chosen hex digit. - /// - /// \param[in] DestinationDir Directory the unique file should be placed in. - /// \param[in] MainSourceFile Full path to the source file. - /// \param[out] Result The resulting unique filename. - /// \param[out] Error If an error occurs a description of that error is - /// placed in this string. - /// - /// \returns \parblock - /// \li true on success - /// \li false if a unique file name could not be created. - static bool generateReplacementsFileName(llvm::StringRef DestinationDir, - llvm::StringRef MainSourceFile, - llvm::SmallVectorImpl &Result, - llvm::SmallVectorImpl &Error); - - /// \brief Helper to create a temporary directory name. - /// - /// \post The directory named by the returned string exists. - /// - /// \returns A temp directory name. - static std::string generateTempDir(); - -private: - - std::string CARPath; - std::string DestinationDir; - bool DoFormat; - std::string FormatStyle; - std::string StyleConfigDir; -}; - -#endif // CLANG_MODERNIZE_REPLACEMENTHANDLING_H Index: clang-modernize/Core/ReplacementHandling.cpp =================================================================== --- clang-modernize/Core/ReplacementHandling.cpp +++ /dev/null @@ -1,155 +0,0 @@ -//===-- Core/ReplacementHandling.cpp --------------------------------------===// -// -// 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 implementations for the ReplacementHandling class. -/// -//===----------------------------------------------------------------------===// - -#include "Core/ReplacementHandling.h" -#include "clang/Tooling/ReplacementsYaml.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Program.h" -#include - -using namespace llvm; -using namespace llvm::sys; -using namespace clang::tooling; - -bool ReplacementHandling::findClangApplyReplacements(const char *Argv0) { - ErrorOr CARPathOrErr = - findProgramByName("clang-apply-replacements"); - if (!CARPathOrErr) - return true; - - CARPath = *CARPathOrErr; - static int StaticSymbol; - std::string ClangModernizePath = fs::getMainExecutable(Argv0, &StaticSymbol); - SmallString<128> TestPath = path::parent_path(ClangModernizePath); - path::append(TestPath, "clang-apply-replacements"); - if (fs::can_execute(Twine(TestPath))) - CARPath = TestPath.str(); - - return !CARPath.empty(); -} - -StringRef ReplacementHandling::useTempDestinationDir() { - DestinationDir = generateTempDir(); - return DestinationDir; -} - -void ReplacementHandling::enableFormatting(StringRef Style, - StringRef StyleConfigDir) { - DoFormat = true; - FormatStyle = Style; - this->StyleConfigDir = StyleConfigDir; -} - -bool ReplacementHandling::serializeReplacements( - const TUReplacementsMap &Replacements) { - assert(!DestinationDir.empty() && "Destination directory not set"); - - bool Errors = false; - - for (TUReplacementsMap::const_iterator I = Replacements.begin(), - E = Replacements.end(); - I != E; ++I) { - SmallString<128> ReplacementsFileName; - SmallString<64> Error; - bool Result = generateReplacementsFileName(DestinationDir, - I->getValue().MainSourceFile, - ReplacementsFileName, Error); - if (!Result) { - errs() << "Failed to generate replacements filename:" << Error << "\n"; - Errors = true; - continue; - } - - std::error_code EC; - raw_fd_ostream ReplacementsFile(ReplacementsFileName, EC, fs::F_None); - if (EC) { - errs() << "Error opening file: " << EC.message() << "\n"; - Errors = true; - continue; - } - yaml::Output YAML(ReplacementsFile); - YAML << const_cast(I->getValue()); - } - return !Errors; -} - -bool ReplacementHandling::applyReplacements() { - SmallVector Argv; - Argv.push_back(CARPath.c_str()); - std::string Style = "--style=" + FormatStyle; - std::string StyleConfig = "--style-config=" + StyleConfigDir; - if (DoFormat) { - Argv.push_back("--format"); - Argv.push_back(Style.c_str()); - if (!StyleConfigDir.empty()) - Argv.push_back(StyleConfig.c_str()); - } - Argv.push_back("--remove-change-desc-files"); - Argv.push_back(DestinationDir.c_str()); - - // Argv array needs to be null terminated. - Argv.push_back(nullptr); - - std::string ErrorMsg; - bool ExecutionFailed = false; - int ReturnCode = ExecuteAndWait(CARPath.c_str(), Argv.data(), - /* env */ nullptr, /* redirects */ nullptr, - /* secondsToWait */ 0, /* memoryLimit */ 0, - &ErrorMsg, &ExecutionFailed); - if (ExecutionFailed || !ErrorMsg.empty()) { - errs() << "Failed to launch clang-apply-replacements: " << ErrorMsg << "\n"; - errs() << "Command Line:\n"; - for (const char **I = Argv.begin(), **E = Argv.end(); I != E; ++I) { - if (*I) - errs() << *I << "\n"; - } - return false; - } - - if (ReturnCode != 0) { - errs() << "clang-apply-replacements failed with return code " << ReturnCode - << "\n"; - return false; - } - - return true; -} - -std::string ReplacementHandling::generateTempDir() { - SmallString<128> Prefix; - path::system_temp_directory(true, Prefix); - path::append(Prefix, "clang-modernize"); - SmallString<128> Result; - fs::createUniqueDirectory(Twine(Prefix), Result); - return Result.str(); -} - -bool ReplacementHandling::generateReplacementsFileName( - StringRef DestinationDir, StringRef MainSourceFile, - SmallVectorImpl &Result, SmallVectorImpl &Error) { - - Error.clear(); - SmallString<128> Prefix = DestinationDir; - path::append(Prefix, path::filename(MainSourceFile)); - if (std::error_code EC = - fs::createUniqueFile(Prefix + "_%%_%%_%%_%%_%%_%%.yaml", Result)) { - const std::string &Msg = EC.message(); - Error.append(Msg.begin(), Msg.end()); - return false; - } - - return true; -} Index: clang-modernize/Core/Transform.h =================================================================== --- clang-modernize/Core/Transform.h +++ /dev/null @@ -1,329 +0,0 @@ -//===-- Core/Transform.h - Transform Base Class Def'n -----------*- 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 declaration for the base Transform class from -/// which all transforms must subclass. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_TRANSFORM_H -#define CLANG_MODERNIZE_TRANSFORM_H - -#include "Core/IncludeExcludeInfo.h" -#include "Core/Refactoring.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Registry.h" -#include "llvm/Support/Timer.h" -#include -#include - -/// \brief Description of the riskiness of actions that can be taken by -/// transforms. -enum RiskLevel { - /// Transformations that will not change semantics. - RL_Safe, - - /// Transformations that might change semantics. - RL_Reasonable, - - /// Transformations that are likely to change semantics. - RL_Risky -}; - -// Forward declarations -namespace clang { -class CompilerInstance; -namespace tooling { -class CompilationDatabase; -class FrontendActionFactory; -} // namespace tooling -namespace ast_matchers { -class MatchFinder; -} // namespace ast_matchers -} // namespace clang - -// \brief Maps main source file names to a TranslationUnitReplacements -// structure storing replacements for that translation unit. -typedef llvm::StringMap -TUReplacementsMap; - -/// \brief To group transforms' options together when printing the help. -extern llvm::cl::OptionCategory TransformsOptionsCategory; - -/// \brief Container for global options affecting all transforms. -struct TransformOptions { - /// \brief Enable the use of performance timers. - bool EnableTiming; - - /// \brief Contains information on which files are safe to transform and - /// which aren't. - IncludeExcludeInfo ModifiableFiles; - - /// \brief Maximum allowed level of risk. - RiskLevel MaxRiskLevel; -}; - -/// \brief Abstract base class for all C++11 migration transforms. -/// -/// Subclasses must call createActionFactory() to create a -/// FrontendActionFactory to pass to ClangTool::run(). Subclasses are also -/// responsible for calling setOverrides() before calling ClangTool::run(). -/// -/// If timing is enabled (see TransformOptions), per-source performance timing -/// is recorded and stored in a TimingVec for later access with timing_begin() -/// and timing_end(). -class Transform { -public: - /// \brief Constructor - /// \param Name Name of the transform for human-readable purposes (e.g. -help - /// text) - /// \param Options Global options that affect all Transforms. - Transform(llvm::StringRef Name, const TransformOptions &Options); - - virtual ~Transform(); - - /// \brief Apply a transform to all files listed in \p SourcePaths. - /// - /// \param[in] Database Contains information for how to compile all files in - /// \p SourcePaths. - /// \param[in] SourcePaths list of sources to transform. - /// - /// \returns \parblock - /// \li 0 if successful - /// \li 1 otherwise - virtual int apply(const clang::tooling::CompilationDatabase &Database, - const std::vector &SourcePaths) = 0; - - /// \brief Query if changes were made during the last call to apply(). - bool getChangesMade() const { return AcceptedChanges > 0; } - - /// \brief Query if changes were not made due to conflicts with other changes - /// made during the last call to apply() or if changes were too risky for the - /// requested risk level. - bool getChangesNotMade() const { - return RejectedChanges > 0 || DeferredChanges > 0; - } - - /// \brief Query the number of accepted changes. - unsigned getAcceptedChanges() const { return AcceptedChanges; } - /// \brief Query the number of changes considered too risky. - unsigned getRejectedChanges() const { return RejectedChanges; } - /// \brief Query the number of changes not made because they conflicted with - /// early changes. - unsigned getDeferredChanges() const { return DeferredChanges; } - - /// \brief Query transform name. - llvm::StringRef getName() const { return Name; } - - /// \brief Reset internal state of the transform. - /// - /// Useful if calling apply() several times with one instantiation of a - /// transform. - void Reset() { - AcceptedChanges = 0; - RejectedChanges = 0; - DeferredChanges = 0; - } - - /// \brief Tests if the file containing \a Loc is allowed to be modified by - /// the Modernizer. - bool isFileModifiable(const clang::SourceManager &SM, - clang::SourceLocation Loc) const; - - /// \brief Whether a transformation with a risk level of \p RiskLevel is - /// acceptable or not. - bool isAcceptableRiskLevel(RiskLevel RiskLevel) const { - return RiskLevel <= GlobalOptions.MaxRiskLevel; - } - - /// \brief Called before parsing a translation unit for a FrontendAction. - /// - /// Transform uses this function to apply file overrides and start - /// performance timers. Subclasses overriding this function must call it - /// before returning. - virtual bool handleBeginSource(clang::CompilerInstance &CI, - llvm::StringRef Filename); - - /// \brief Called after FrontendAction has been run over a translation unit. - /// - /// Transform uses this function to stop performance timers. Subclasses - /// overriding this function must call it before returning. A call to - /// handleEndSource() for a given translation unit is expected to be called - /// immediately after the corresponding handleBeginSource() call. - virtual void handleEndSource(); - - /// \brief Performance timing data is stored as a vector of pairs. Pairs are - /// formed of: - /// \li Name of source file. - /// \li Elapsed time. - typedef std::vector > TimingVec; - - /// \brief Return an iterator to the start of collected timing data. - TimingVec::const_iterator timing_begin() const { return Timings.begin(); } - /// \brief Return an iterator to the start of collected timing data. - TimingVec::const_iterator timing_end() const { return Timings.end(); } - - /// \brief Add a Replacement to the list for the current translation unit. - /// - /// \returns \parblock - /// \li true on success - /// \li false if there is no current translation unit - bool addReplacementForCurrentTU(const clang::tooling::Replacement &R); - - /// \brief Accessor to Replacements across all transformed translation units. - const TUReplacementsMap &getAllReplacements() const { - return Replacements; - } - -protected: - - void setAcceptedChanges(unsigned Changes) { - AcceptedChanges = Changes; - } - void setRejectedChanges(unsigned Changes) { - RejectedChanges = Changes; - } - void setDeferredChanges(unsigned Changes) { - DeferredChanges = Changes; - } - - /// \brief Allows subclasses to manually add performance timer data. - /// - /// \p Label should probably include the source file name somehow as the - /// duration info is simply added to the vector of timing data which holds - /// data for all sources processed by this transform. - void addTiming(llvm::StringRef Label, llvm::TimeRecord Duration); - - /// \brief Provide access for subclasses to the TransformOptions they were - /// created with. - const TransformOptions &Options() { return GlobalOptions; } - - /// \brief Subclasses must call this function to create a - /// FrontendActionFactory to pass to ClangTool. - /// - /// The factory returned by this function is responsible for calling back to - /// Transform to call handleBeginSource() and handleEndSource(). - std::unique_ptr - createActionFactory(clang::ast_matchers::MatchFinder &Finder); - -private: - const std::string Name; - const TransformOptions &GlobalOptions; - TUReplacementsMap Replacements; - std::string CurrentSource; - TimingVec Timings; - unsigned AcceptedChanges; - unsigned RejectedChanges; - unsigned DeferredChanges; -}; - -/// \brief Describes a version number of the form major[.minor] (minor being -/// optional). -struct Version { - explicit Version(unsigned Major = 0, unsigned Minor = 0) - : Major(Major), Minor(Minor) {} - - bool operator<(Version RHS) const { - if (Major < RHS.Major) - return true; - if (Major == RHS.Major) - return Minor < RHS.Minor; - return false; - } - - bool operator==(Version RHS) const { - return Major == RHS.Major && Minor == RHS.Minor; - } - - bool operator!=(Version RHS) const { return !(*this == RHS); } - bool operator>(Version RHS) const { return RHS < *this; } - bool operator<=(Version RHS) const { return !(*this > RHS); } - bool operator>=(Version RHS) const { return !(*this < RHS); } - - bool isNull() const { return Minor == 0 && Major == 0; } - unsigned getMajor() const { return Major; } - unsigned getMinor() const { return Minor; } - - /// \brief Creates a version from a string of the form \c major[.minor]. - /// - /// Note that any version component after \c minor is ignored. - /// - /// \return A null version is returned on error. - static Version getFromString(llvm::StringRef VersionStr); - -private: - unsigned Major; - unsigned Minor; -}; - -/// \brief Convenience structure to store the version of some compilers. -struct CompilerVersions { - Version Clang, Gcc, Icc, Msvc; -}; - -/// \brief A factory that can instantiate a specific transform. -/// -/// Each transform should subclass this class and implement -/// \c createTransform(). -/// -/// In the sub-classed factory constructor, specify the earliest versions since -/// the compilers in \c CompilerVersions support the feature introduced by the -/// transform. See the example below. -/// -/// Note that you should use \c TransformFactoryRegistry to register the -/// transform globally. -/// -/// Example: -/// \code -/// class MyTransform : public Transform { ... }; -/// -/// struct MyFactory : TransformFactory { -/// MyFactory() { -/// Since.Clang = Version(3, 0); -/// Since.Gcc = Version(4, 7); -/// Since.Icc = Version(12); -/// Since.Msvc = Version(10); -/// } -/// -/// Transform *createTransform(const TransformOptions &Opts) override { -/// return new MyTransform(Opts); -/// } -/// }; -/// -/// // Register the factory using this statically initialized variable. -/// static TransformFactoryRegistry::Add -/// X("my-transform", ""); -/// -/// // This anchor is used to force the linker to link in the generated object -/// // file and thus register the factory. -/// volatile int MyTransformAnchorSource = 0; -/// \endcode -class TransformFactory { -public: - virtual ~TransformFactory(); - virtual Transform *createTransform(const TransformOptions &) = 0; - - /// \brief Whether the transform is supported by the required compilers or - /// not. - bool supportsCompilers(CompilerVersions Required) const; - -protected: - /// \brief Since when the C++11 feature introduced by this transform has been - /// available. - /// - /// Can be set by the sub-class in the constructor body. - CompilerVersions Since; -}; - -typedef llvm::Registry TransformFactoryRegistry; - -extern template class llvm::Registry; - -#endif // CLANG_MODERNIZE_TRANSFORM_H Index: clang-modernize/Core/Transform.cpp =================================================================== --- clang-modernize/Core/Transform.cpp +++ /dev/null @@ -1,169 +0,0 @@ -//===-- Core/Transform.cpp - Transform Base Class Def'n -------------------===// -// -// 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 for the base Transform class from -/// which all transforms must subclass. -/// -//===----------------------------------------------------------------------===// - -#include "Core/Transform.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Basic/LangOptions.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Tooling/Tooling.h" -#include "llvm/ADT/STLExtras.h" - -template class llvm::Registry; - -using namespace clang; - -llvm::cl::OptionCategory TransformsOptionsCategory("Transforms' options"); - -namespace { - -using namespace tooling; -using namespace ast_matchers; - -/// \brief Custom FrontendActionFactory to produce FrontendActions that simply -/// forward (Begin|End)SourceFileAction calls to a given Transform. -class ActionFactory : public clang::tooling::FrontendActionFactory { -public: - ActionFactory(MatchFinder &Finder, Transform &Owner) - : Finder(Finder), Owner(Owner) {} - - FrontendAction *create() override { - return new FactoryAdaptor(Finder, Owner); - } - -private: - class FactoryAdaptor : public ASTFrontendAction { - public: - FactoryAdaptor(MatchFinder &Finder, Transform &Owner) - : Finder(Finder), Owner(Owner) {} - - std::unique_ptr CreateASTConsumer(CompilerInstance &, - StringRef) override { - return Finder.newASTConsumer(); - } - - bool BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) override { - if (!ASTFrontendAction::BeginSourceFileAction(CI, Filename)) - return false; - - return Owner.handleBeginSource(CI, Filename); - } - - void EndSourceFileAction() override { - Owner.handleEndSource(); - return ASTFrontendAction::EndSourceFileAction(); - } - - private: - MatchFinder &Finder; - Transform &Owner; - }; - - MatchFinder &Finder; - Transform &Owner; -}; -} // namespace - -Transform::Transform(llvm::StringRef Name, const TransformOptions &Options) - : Name(Name), GlobalOptions(Options) { - Reset(); -} - -Transform::~Transform() {} - -bool Transform::isFileModifiable(const SourceManager &SM, - SourceLocation Loc) const { - if (SM.isWrittenInMainFile(Loc)) - return true; - - const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Loc)); - if (!FE) - return false; - - return GlobalOptions.ModifiableFiles.isFileIncluded(FE->getName()); -} - -bool Transform::handleBeginSource(CompilerInstance &CI, StringRef Filename) { - CurrentSource = Filename; - - if (Options().EnableTiming) { - Timings.push_back(std::make_pair(Filename.str(), llvm::TimeRecord())); - Timings.back().second -= llvm::TimeRecord::getCurrentTime(true); - } - return true; -} - -void Transform::handleEndSource() { - CurrentSource.clear(); - if (Options().EnableTiming) - Timings.back().second += llvm::TimeRecord::getCurrentTime(false); -} - -void Transform::addTiming(llvm::StringRef Label, llvm::TimeRecord Duration) { - Timings.push_back(std::make_pair(Label.str(), Duration)); -} - -bool -Transform::addReplacementForCurrentTU(const clang::tooling::Replacement &R) { - if (CurrentSource.empty()) - return false; - - TranslationUnitReplacements &TU = Replacements[CurrentSource]; - if (TU.MainSourceFile.empty()) - TU.MainSourceFile = CurrentSource; - TU.Replacements.push_back(R); - - return true; -} - -std::unique_ptr -Transform::createActionFactory(MatchFinder &Finder) { - return llvm::make_unique(Finder, /*Owner=*/*this); -} - -Version Version::getFromString(llvm::StringRef VersionStr) { - llvm::StringRef MajorStr, MinorStr; - Version V; - - std::tie(MajorStr, MinorStr) = VersionStr.split('.'); - if (!MinorStr.empty()) { - llvm::StringRef Ignore; - std::tie(MinorStr, Ignore) = MinorStr.split('.'); - if (MinorStr.getAsInteger(10, V.Minor)) - return Version(); - } - if (MajorStr.getAsInteger(10, V.Major)) - return Version(); - return V; -} - -TransformFactory::~TransformFactory() {} - -namespace { -bool versionSupported(Version Required, Version AvailableSince) { - // null version, means no requirements, means supported - if (Required.isNull()) - return true; - return Required >= AvailableSince; -} -} // end anonymous namespace - -bool TransformFactory::supportsCompilers(CompilerVersions Required) const { - return versionSupported(Required.Clang, Since.Clang) && - versionSupported(Required.Gcc, Since.Gcc) && - versionSupported(Required.Icc, Since.Icc) && - versionSupported(Required.Msvc, Since.Msvc); -} Index: clang-modernize/Core/Transforms.h =================================================================== --- clang-modernize/Core/Transforms.h +++ /dev/null @@ -1,84 +0,0 @@ -//===-- Core/Transforms.h - class Transforms Def'n --------------*- 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 for class Transforms which is -/// responsible for defining the command-line arguments exposing -/// transformations to the user and applying requested transforms. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_TRANSFORMS_H -#define CLANG_MODERNIZE_TRANSFORMS_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/CommandLine.h" -#include - -// Forward declarations -namespace llvm { -namespace cl { -class Option; -} // namespace cl -} // namespace llvm -class Transform; -struct TransformOptions; -struct CompilerVersions; - -typedef Transform *(*TransformCreator)(const TransformOptions &); -template -Transform *ConstructTransform(const TransformOptions &Options) { - return new T(Options); -} - -/// \brief To group transforms together when printing the help. -extern llvm::cl::OptionCategory TransformCategory; - -/// \brief Class encapsulating the creation of command line bool options -/// for each transform and instantiating transforms chosen by the user. -class Transforms { -public: - typedef std::vector TransformVec; - typedef TransformVec::const_iterator const_iterator; - -public: - - ~Transforms(); - - /// \brief Registers all available transforms causing them to be made - /// available on the command line. - /// - /// Be sure to register all transforms *before* parsing command line options. - void registerTransforms(); - - /// \brief Instantiate all transforms that were selected on the command line. - /// - /// Call *after* parsing options. - void createSelectedTransforms(const TransformOptions &Options, - const CompilerVersions &RequiredVersions); - - /// \brief Return an iterator to the start of a container of instantiated - /// transforms. - const_iterator begin() const { return ChosenTransforms.begin(); } - - /// \brief Return an iterator to the end of a container of instantiated - /// transforms. - const_iterator end() const { return ChosenTransforms.end(); } - -private: - bool hasAnyExplicitOption() const; - - typedef llvm::StringMap *> OptionMap; - -private: - TransformVec ChosenTransforms; - OptionMap Options; -}; - -#endif // CLANG_MODERNIZE_TRANSFORMS_H Index: clang-modernize/Core/Transforms.cpp =================================================================== --- clang-modernize/Core/Transforms.cpp +++ /dev/null @@ -1,71 +0,0 @@ -//===-- Core/Transforms.cpp - class Transforms 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 provides the implementation for class Transforms. -/// -//===----------------------------------------------------------------------===// - -#include "Core/Transforms.h" -#include "Core/Transform.h" - -namespace cl = llvm::cl; - -cl::OptionCategory TransformCategory("Transforms"); - -Transforms::~Transforms() { - for (std::vector::iterator I = ChosenTransforms.begin(), - E = ChosenTransforms.end(); - I != E; ++I) - delete *I; - - for (OptionMap::iterator I = Options.begin(), E = Options.end(); I != E; ++I) - delete I->getValue(); -} - -void Transforms::registerTransforms() { - for (TransformFactoryRegistry::iterator I = TransformFactoryRegistry::begin(), - E = TransformFactoryRegistry::end(); - I != E; ++I) - Options[I->getName()] = new cl::opt( - I->getName(), cl::desc(I->getDesc()), cl::cat(TransformCategory)); -} - -bool Transforms::hasAnyExplicitOption() const { - for (OptionMap::const_iterator I = Options.begin(), E = Options.end(); I != E; - ++I) - if (*I->second) - return true; - return false; -} - -void -Transforms::createSelectedTransforms(const TransformOptions &GlobalOptions, - const CompilerVersions &RequiredVersions) { - // if at least one transform is set explicitly on the command line, do not - // enable non-explicit ones - bool EnableAllTransformsByDefault = !hasAnyExplicitOption(); - - for (TransformFactoryRegistry::iterator I = TransformFactoryRegistry::begin(), - E = TransformFactoryRegistry::end(); - I != E; ++I) { - bool ExplicitlyEnabled = *Options[I->getName()]; - bool OptionEnabled = EnableAllTransformsByDefault || ExplicitlyEnabled; - - if (!OptionEnabled) - continue; - - std::unique_ptr Factory(I->instantiate()); - if (Factory->supportsCompilers(RequiredVersions)) - ChosenTransforms.push_back(Factory->createTransform(GlobalOptions)); - else if (ExplicitlyEnabled) - llvm::errs() << "note: " << '-' << I->getName() - << ": transform not available for specified compilers\n"; - } -} Index: clang-modernize/LoopConvert/LoopActions.h =================================================================== --- clang-modernize/LoopConvert/LoopActions.h +++ /dev/null @@ -1,116 +0,0 @@ -//===-- LoopConvert/LoopActions.h - C++11 For loop migration ----*- 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 declares matchers and callbacks for use in migrating C++ -/// for loops. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_LOOP_ACTIONS_H -#define CLANG_MODERNIZE_LOOP_ACTIONS_H - -#include "Core/Transform.h" -#include "StmtAncestor.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Tooling/Refactoring.h" - -struct Usage; -class Confidence; -// The main computational result of ForLoopIndexUseVisitor. -typedef llvm::SmallVector UsageResult; - -enum LoopFixerKind { - LFK_Array, - LFK_Iterator, - LFK_PseudoArray -}; - -struct TUTrackingInfo { - - /// \brief Reset and initialize per-TU tracking information. - /// - /// Must be called before using container accessors. - void reset() { - ParentFinder.reset(new StmtAncestorASTVisitor); - GeneratedDecls.clear(); - ReplacedVars.clear(); - } - - /// \name Accessors - /// \{ - StmtAncestorASTVisitor &getParentFinder() { return *ParentFinder; } - StmtGeneratedVarNameMap &getGeneratedDecls() { return GeneratedDecls; } - ReplacedVarsMap &getReplacedVars() { return ReplacedVars; } - /// \} - -private: - std::unique_ptr ParentFinder; - StmtGeneratedVarNameMap GeneratedDecls; - ReplacedVarsMap ReplacedVars; -}; - -/// \brief The callback to be used for loop migration matchers. -/// -/// The callback does extra checking not possible in matchers, and attempts to -/// convert the for loop, if possible. -class LoopFixer : public clang::ast_matchers::MatchFinder::MatchCallback { -public: - LoopFixer(TUTrackingInfo &TUInfo, unsigned *AcceptedChanges, - unsigned *DeferredChanges, unsigned *RejectedChanges, - RiskLevel MaxRisk, LoopFixerKind FixerKind, Transform &Owner) - : TUInfo(TUInfo), AcceptedChanges(AcceptedChanges), - DeferredChanges(DeferredChanges), RejectedChanges(RejectedChanges), - MaxRisk(MaxRisk), FixerKind(FixerKind), Owner(Owner) {} - - void - run(const clang::ast_matchers::MatchFinder::MatchResult &Result) override; - -private: - TUTrackingInfo &TUInfo; - unsigned *AcceptedChanges; - unsigned *DeferredChanges; - unsigned *RejectedChanges; - RiskLevel MaxRisk; - LoopFixerKind FixerKind; - Transform &Owner; - - /// \brief Computes the changes needed to convert a given for loop, and - /// applies it. - void doConversion(clang::ASTContext *Context, const clang::VarDecl *IndexVar, - const clang::VarDecl *MaybeContainer, - llvm::StringRef ContainerString, const UsageResult &Usages, - const clang::DeclStmt *AliasDecl, bool AliasUseRequired, - bool AliasFromForInit, const clang::ForStmt *TheLoop, - bool ContainerNeedsDereference, bool DerefByValue, - bool DerefByConstRef); - - /// \brief Given a loop header that would be convertible, discover all usages - /// of the index variable and convert the loop if possible. - void findAndVerifyUsages(clang::ASTContext *Context, - const clang::VarDecl *LoopVar, - const clang::VarDecl *EndVar, - const clang::Expr *ContainerExpr, - const clang::Expr *BoundExpr, - bool ContainerNeedsDereference, bool DerefByValue, - bool DerefByConstRef, const clang::ForStmt *TheLoop, - Confidence ConfidenceLevel); - - /// \brief Determine if the change should be deferred or rejected, returning - /// text which refers to the container iterated over if the change should - /// proceed. - llvm::StringRef checkDeferralsAndRejections(clang::ASTContext *Context, - const clang::Expr *ContainerExpr, - Confidence ConfidenceLevel, - const clang::ForStmt *TheLoop); -}; - -#endif // CLANG_MODERNIZE_LOOP_ACTIONS_H Index: clang-modernize/LoopConvert/LoopActions.cpp =================================================================== --- clang-modernize/LoopConvert/LoopActions.cpp +++ /dev/null @@ -1,1143 +0,0 @@ -//===-- LoopConvert/LoopActions.cpp - C++11 For loop migration ------------===// -// -// 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 defines matchers and callbacks for use in migrating C++ -/// for loops. -/// -//===----------------------------------------------------------------------===// - -#include "LoopActions.h" -#include "LoopMatchers.h" -#include "VariableNaming.h" -#include "clang/Lex/Lexer.h" - -using namespace clang::ast_matchers; -using namespace clang::tooling; -using namespace clang; - -/// \brief The information needed to describe a valid convertible usage -/// of an array index or iterator. -struct Usage { - const Expr *E; - bool IsArrow; - SourceRange Range; - - explicit Usage(const Expr *E) - : E(E), IsArrow(false), Range(E->getSourceRange()) { } - Usage(const Expr *E, bool IsArrow, SourceRange Range) - : E(E), IsArrow(IsArrow), Range(Range) { } -}; - -/// \brief A class to encapsulate lowering of the tool's confidence level. -/// -/// Confidence is a quantity opposite in meaning to Risk. Since clang-modernize -/// uses risk, this class reverses the meaning for the legacy loop convert -/// code. -class Confidence { -public: - /// \brief Initialize confidence level. - explicit Confidence(RiskLevel Level) : - CurrentLevel(Level) {} - - /// \brief Lower the internal confidence level to Level, but do not raise it. - void lowerTo(RiskLevel Level) { - CurrentLevel = std::max(Level, CurrentLevel); - } - - /// \brief Return the internal confidence level. - RiskLevel getRiskLevel() const { return CurrentLevel; } - -private: - RiskLevel CurrentLevel; -}; - -/// \brief Discover usages of expressions consisting of index or iterator -/// access. -/// -/// Given an index variable, recursively crawls a for loop to discover if the -/// index variable is used in a way consistent with range-based for loop access. -class ForLoopIndexUseVisitor - : public RecursiveASTVisitor { - public: - ForLoopIndexUseVisitor(ASTContext *Context, const VarDecl *IndexVar, - const VarDecl *EndVar, const Expr *ContainerExpr, - const Expr *ArrayBoundExpr, - bool ContainerNeedsDereference) : - Context(Context), IndexVar(IndexVar), EndVar(EndVar), - ContainerExpr(ContainerExpr), ArrayBoundExpr(ArrayBoundExpr), - ContainerNeedsDereference(ContainerNeedsDereference), - OnlyUsedAsIndex(true), AliasDecl(nullptr), ConfidenceLevel(RL_Safe), - NextStmtParent(nullptr), CurrStmtParent(nullptr), - ReplaceWithAliasUse(false), AliasFromForInit(false) { - if (ContainerExpr) { - addComponent(ContainerExpr); - llvm::FoldingSetNodeID ID; - const Expr *E = ContainerExpr->IgnoreParenImpCasts(); - E->Profile(ID, *Context, true); - } - } - - /// \brief Finds all uses of IndexVar in Body, placing all usages in Usages, - /// and returns true if IndexVar was only used in a way consistent with a - /// range-based for loop. - /// - /// The general strategy is to reject any DeclRefExprs referencing IndexVar, - /// with the exception of certain acceptable patterns. - /// For arrays, the DeclRefExpr for IndexVar must appear as the index of an - /// ArraySubscriptExpression. Iterator-based loops may dereference - /// IndexVar or call methods through operator-> (builtin or overloaded). - /// Array-like containers may use IndexVar as a parameter to the at() member - /// function and in overloaded operator[]. - bool findAndVerifyUsages(const Stmt *Body) { - TraverseStmt(const_cast(Body)); - return OnlyUsedAsIndex && ContainerExpr; - } - - /// \brief Add a set of components that we should consider relevant to the - /// container. - void addComponents(const ComponentVector &Components) { - // FIXME: add sort(on ID)+unique to avoid extra work. - for (ComponentVector::const_iterator I = Components.begin(), - E = Components.end(); I != E; ++I) - addComponent(*I); - } - - /// \brief Accessor for Usages. - const UsageResult &getUsages() const { return Usages; } - - /// \brief Get the container indexed by IndexVar, if any. - const Expr *getContainerIndexed() const { - return ContainerExpr; - } - - /// \brief Returns the statement declaring the variable created as an alias - /// for the loop element, if any. - const DeclStmt *getAliasDecl() const { return AliasDecl; } - - /// \brief Accessor for ConfidenceLevel. - RiskLevel getRiskLevel() const { - return ConfidenceLevel.getRiskLevel(); - } - - /// \brief Indicates if the alias declaration was in a place where it cannot - /// simply be removed but rather replaced with a use of the alias variable. - /// For example, variables declared in the condition of an if, switch, or for - /// stmt. - bool aliasUseRequired() const { return ReplaceWithAliasUse; } - - /// \brief Indicates if the alias declaration came from the init clause of a - /// nested for loop. SourceRanges provided by Clang for DeclStmts in this - /// case need to be adjusted. - bool aliasFromForInit() const { return AliasFromForInit; } - - private: - /// Typedef used in CRTP functions. - typedef RecursiveASTVisitor VisitorBase; - friend class RecursiveASTVisitor; - - /// Overriden methods for RecursiveASTVisitor's traversal. - bool TraverseArraySubscriptExpr(ArraySubscriptExpr *E); - bool TraverseCXXMemberCallExpr(CXXMemberCallExpr *MemberCall); - bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *OpCall); - bool TraverseMemberExpr(MemberExpr *Member); - bool TraverseUnaryDeref(UnaryOperator *Uop); - bool VisitDeclRefExpr(DeclRefExpr *E); - bool VisitDeclStmt(DeclStmt *S); - bool TraverseStmt(Stmt *S); - - /// \brief Add an expression to the list of expressions on which the container - /// expression depends. - void addComponent(const Expr *E) { - llvm::FoldingSetNodeID ID; - const Expr *Node = E->IgnoreParenImpCasts(); - Node->Profile(ID, *Context, true); - DependentExprs.push_back(std::make_pair(Node, ID)); - } - - // Input member variables: - ASTContext *Context; - /// The index variable's VarDecl. - const VarDecl *IndexVar; - /// The loop's 'end' variable, which cannot be mentioned at all. - const VarDecl *EndVar; - /// The Expr which refers to the container. - const Expr *ContainerExpr; - /// The Expr which refers to the terminating condition for array-based loops. - const Expr *ArrayBoundExpr; - bool ContainerNeedsDereference; - - // Output member variables: - /// A container which holds all usages of IndexVar as the index of - /// ArraySubscriptExpressions. - UsageResult Usages; - bool OnlyUsedAsIndex; - /// The DeclStmt for an alias to the container element. - const DeclStmt *AliasDecl; - Confidence ConfidenceLevel; - /// \brief A list of expressions on which ContainerExpr depends. - /// - /// If any of these expressions are encountered outside of an acceptable usage - /// of the loop element, lower our confidence level. - llvm::SmallVector< - std::pair, 16> DependentExprs; - - /// The parent-in-waiting. Will become the real parent once we traverse down - /// one level in the AST. - const Stmt *NextStmtParent; - /// The actual parent of a node when Visit*() calls are made. Only the - /// parentage of DeclStmt's to possible iteration/selection statements is of - /// importance. - const Stmt *CurrStmtParent; - - /// \see aliasUseRequired(). - bool ReplaceWithAliasUse; - /// \see aliasFromForInit(). - bool AliasFromForInit; -}; - -/// \brief Obtain the original source code text from a SourceRange. -static StringRef getStringFromRange(SourceManager &SourceMgr, - const LangOptions &LangOpts, - SourceRange Range) { - if (SourceMgr.getFileID(Range.getBegin()) != - SourceMgr.getFileID(Range.getEnd())) - return nullptr; - - CharSourceRange SourceChars(Range, true); - return Lexer::getSourceText(SourceChars, SourceMgr, LangOpts); -} - -/// \brief Returns the DeclRefExpr represented by E, or NULL if there isn't one. -static const DeclRefExpr *getDeclRef(const Expr *E) { - return dyn_cast(E->IgnoreParenImpCasts()); -} - -/// \brief If the given expression is actually a DeclRefExpr, find and return -/// the underlying VarDecl; otherwise, return NULL. -static const VarDecl *getReferencedVariable(const Expr *E) { - if (const DeclRefExpr *DRE = getDeclRef(E)) - return dyn_cast(DRE->getDecl()); - return nullptr; -} - -/// \brief Returns true when the given expression is a member expression -/// whose base is `this` (implicitly or not). -static bool isDirectMemberExpr(const Expr *E) { - if (const MemberExpr *Member = dyn_cast(E->IgnoreParenImpCasts())) - return isa(Member->getBase()->IgnoreParenImpCasts()); - return false; -} - -/// \brief Returns true when two ValueDecls are the same variable. -static bool areSameVariable(const ValueDecl *First, const ValueDecl *Second) { - return First && Second && - First->getCanonicalDecl() == Second->getCanonicalDecl(); -} - -/// \brief Determines if an expression is a declaration reference to a -/// particular variable. -static bool exprReferencesVariable(const ValueDecl *Target, const Expr *E) { - if (!Target || !E) - return false; - const DeclRefExpr *Decl = getDeclRef(E); - return Decl && areSameVariable(Target, Decl->getDecl()); -} - -/// \brief Returns true when two Exprs are equivalent. -static bool areSameExpr(ASTContext *Context, const Expr *First, - const Expr *Second) { - if (!First || !Second) - return false; - - llvm::FoldingSetNodeID FirstID, SecondID; - First->Profile(FirstID, *Context, true); - Second->Profile(SecondID, *Context, true); - return FirstID == SecondID; -} - -/// \brief Look through conversion/copy constructors to find the explicit -/// initialization expression, returning it is found. -/// -/// The main idea is that given -/// vector v; -/// we consider either of these initializations -/// vector::iterator it = v.begin(); -/// vector::iterator it(v.begin()); -/// and retrieve `v.begin()` as the expression used to initialize `it` but do -/// not include -/// vector::iterator it; -/// vector::iterator it(v.begin(), 0); // if this constructor existed -/// as being initialized from `v.begin()` -static const Expr *digThroughConstructors(const Expr *E) { - if (!E) - return nullptr; - E = E->IgnoreParenImpCasts(); - if (const CXXConstructExpr *ConstructExpr = dyn_cast(E)) { - // The initial constructor must take exactly one parameter, but base class - // and deferred constructors can take more. - if (ConstructExpr->getNumArgs() != 1 || - ConstructExpr->getConstructionKind() != CXXConstructExpr::CK_Complete) - return nullptr; - E = ConstructExpr->getArg(0); - if (const MaterializeTemporaryExpr *Temp = - dyn_cast(E)) - E = Temp->GetTemporaryExpr(); - return digThroughConstructors(E); - } - return E; -} - -/// \brief If the expression is a dereference or call to operator*(), return the -/// operand. Otherwise, return NULL. -static const Expr *getDereferenceOperand(const Expr *E) { - if (const UnaryOperator *Uop = dyn_cast(E)) - return Uop->getOpcode() == UO_Deref ? Uop->getSubExpr() : nullptr; - - if (const CXXOperatorCallExpr *OpCall = dyn_cast(E)) - return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1 ? - OpCall->getArg(0) : nullptr; - - return nullptr; -} - -/// \brief Returns true when the Container contains an Expr equivalent to E. -template -static bool containsExpr(ASTContext *Context, const ContainerT *Container, - const Expr *E) { - llvm::FoldingSetNodeID ID; - E->Profile(ID, *Context, true); - for (typename ContainerT::const_iterator I = Container->begin(), - End = Container->end(); I != End; ++I) - if (ID == I->second) - return true; - return false; -} - -/// \brief Returns true when the index expression is a declaration reference to -/// IndexVar. -/// -/// If the index variable is `index`, this function returns true on -/// arrayExpression[index]; -/// containerExpression[index]; -/// but not -/// containerExpression[notIndex]; -static bool isIndexInSubscriptExpr(const Expr *IndexExpr, - const VarDecl *IndexVar) { - const DeclRefExpr *Idx = getDeclRef(IndexExpr); - return Idx && Idx->getType()->isIntegerType() - && areSameVariable(IndexVar, Idx->getDecl()); -} - -/// \brief Returns true when the index expression is a declaration reference to -/// IndexVar, Obj is the same expression as SourceExpr after all parens and -/// implicit casts are stripped off. -/// -/// If PermitDeref is true, IndexExpression may -/// be a dereference (overloaded or builtin operator*). -/// -/// This function is intended for array-like containers, as it makes sure that -/// both the container and the index match. -/// If the loop has index variable `index` and iterates over `container`, then -/// isIndexInSubscriptExpr returns true for -/// \code -/// container[index] -/// container.at(index) -/// container->at(index) -/// \endcode -/// but not for -/// \code -/// container[notIndex] -/// notContainer[index] -/// \endcode -/// If PermitDeref is true, then isIndexInSubscriptExpr additionally returns -/// true on these expressions: -/// \code -/// (*container)[index] -/// (*container).at(index) -/// \endcode -static bool isIndexInSubscriptExpr(ASTContext *Context, const Expr *IndexExpr, - const VarDecl *IndexVar, const Expr *Obj, - const Expr *SourceExpr, bool PermitDeref) { - if (!SourceExpr || !Obj || !isIndexInSubscriptExpr(IndexExpr, IndexVar)) - return false; - - if (areSameExpr(Context, SourceExpr->IgnoreParenImpCasts(), - Obj->IgnoreParenImpCasts())) - return true; - - if (const Expr *InnerObj = getDereferenceOperand(Obj->IgnoreParenImpCasts())) - if (PermitDeref && areSameExpr(Context, SourceExpr->IgnoreParenImpCasts(), - InnerObj->IgnoreParenImpCasts())) - return true; - - return false; -} - -/// \brief Returns true when Opcall is a call a one-parameter dereference of -/// IndexVar. -/// -/// For example, if the index variable is `index`, returns true for -/// *index -/// but not -/// index -/// *notIndex -static bool isDereferenceOfOpCall(const CXXOperatorCallExpr *OpCall, - const VarDecl *IndexVar) { - return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1 && - exprReferencesVariable(IndexVar, OpCall->getArg(0)); -} - -/// \brief Returns true when Uop is a dereference of IndexVar. -/// -/// For example, if the index variable is `index`, returns true for -/// *index -/// but not -/// index -/// *notIndex -static bool isDereferenceOfUop(const UnaryOperator *Uop, - const VarDecl *IndexVar) { - return Uop->getOpcode() == UO_Deref && - exprReferencesVariable(IndexVar, Uop->getSubExpr()); -} - -/// \brief Determines whether the given Decl defines a variable initialized to -/// the loop object. -/// -/// This is intended to find cases such as -/// \code -/// for (int i = 0; i < arraySize(arr); ++i) { -/// T t = arr[i]; -/// // use t, do not use i -/// } -/// \endcode -/// and -/// \code -/// for (iterator i = container.begin(), e = container.end(); i != e; ++i) { -/// T t = *i; -/// // use t, do not use i -/// } -/// \endcode -static bool isAliasDecl(const Decl *TheDecl, const VarDecl *IndexVar) { - const VarDecl *VDecl = dyn_cast(TheDecl); - if (!VDecl) - return false; - if (!VDecl->hasInit()) - return false; - const Expr *Init = - digThroughConstructors(VDecl->getInit()->IgnoreParenImpCasts()); - if (!Init) - return false; - - switch (Init->getStmtClass()) { - case Stmt::ArraySubscriptExprClass: { - const ArraySubscriptExpr *E = cast(Init); - // We don't really care which array is used here. We check to make sure - // it was the correct one later, since the AST will traverse it next. - return isIndexInSubscriptExpr(E->getIdx(), IndexVar); - } - - case Stmt::UnaryOperatorClass: - return isDereferenceOfUop(cast(Init), IndexVar); - - case Stmt::CXXOperatorCallExprClass: { - const CXXOperatorCallExpr *OpCall = cast(Init); - if (OpCall->getOperator() == OO_Star) - return isDereferenceOfOpCall(OpCall, IndexVar); - if (OpCall->getOperator() == OO_Subscript) { - assert(OpCall->getNumArgs() == 2); - return true; - } - break; - } - - case Stmt::CXXMemberCallExprClass: - return true; - - default: - break; - } - return false; -} - -/// \brief Determines whether the bound of a for loop condition expression is -/// the same as the statically computable size of ArrayType. -/// -/// Given -/// \code -/// const int N = 5; -/// int arr[N]; -/// \endcode -/// This is intended to permit -/// \code -/// for (int i = 0; i < N; ++i) { /* use arr[i] */ } -/// for (int i = 0; i < arraysize(arr); ++i) { /* use arr[i] */ } -/// \endcode -static bool arrayMatchesBoundExpr(ASTContext *Context, - const QualType &ArrayType, - const Expr *ConditionExpr) { - if (!ConditionExpr || ConditionExpr->isValueDependent()) - return false; - const ConstantArrayType *ConstType = - Context->getAsConstantArrayType(ArrayType); - if (!ConstType) - return false; - llvm::APSInt ConditionSize; - if (!ConditionExpr->isIntegerConstantExpr(ConditionSize, *Context)) - return false; - llvm::APSInt ArraySize(ConstType->getSize()); - return llvm::APSInt::isSameValue(ConditionSize, ArraySize); -} - -/// \brief If the unary operator is a dereference of IndexVar, include it -/// as a valid usage and prune the traversal. -/// -/// For example, if container.begin() and container.end() both return pointers -/// to int, this makes sure that the initialization for `k` is not counted as an -/// unconvertible use of the iterator `i`. -/// \code -/// for (int *i = container.begin(), *e = container.end(); i != e; ++i) { -/// int k = *i + 2; -/// } -/// \endcode -bool ForLoopIndexUseVisitor::TraverseUnaryDeref(UnaryOperator *Uop) { - // If we dereference an iterator that's actually a pointer, count the - // occurrence. - if (isDereferenceOfUop(Uop, IndexVar)) { - Usages.push_back(Usage(Uop)); - return true; - } - - return VisitorBase::TraverseUnaryOperator(Uop); -} - -/// \brief If the member expression is operator-> (overloaded or not) on -/// IndexVar, include it as a valid usage and prune the traversal. -/// -/// For example, given -/// \code -/// struct Foo { int bar(); int x; }; -/// vector v; -/// \endcode -/// the following uses will be considered convertible: -/// \code -/// for (vector::iterator i = v.begin(), e = v.end(); i != e; ++i) { -/// int b = i->bar(); -/// int k = i->x + 1; -/// } -/// \endcode -/// though -/// \code -/// for (vector::iterator i = v.begin(), e = v.end(); i != e; ++i) { -/// int k = i.insert(1); -/// } -/// for (vector::iterator i = v.begin(), e = v.end(); i != e; ++i) { -/// int b = e->bar(); -/// } -/// \endcode -/// will not. -bool ForLoopIndexUseVisitor::TraverseMemberExpr(MemberExpr *Member) { - const Expr *Base = Member->getBase(); - const DeclRefExpr *Obj = getDeclRef(Base); - const Expr *ResultExpr = Member; - QualType ExprType; - if (const CXXOperatorCallExpr *Call = - dyn_cast(Base->IgnoreParenImpCasts())) { - // If operator->() is a MemberExpr containing a CXXOperatorCallExpr, then - // the MemberExpr does not have the expression we want. We therefore catch - // that instance here. - // For example, if vector::iterator defines operator->(), then the - // example `i->bar()` at the top of this function is a CXXMemberCallExpr - // referring to `i->` as the member function called. We want just `i`, so - // we take the argument to operator->() as the base object. - if(Call->getOperator() == OO_Arrow) { - assert(Call->getNumArgs() == 1 && - "Operator-> takes more than one argument"); - Obj = getDeclRef(Call->getArg(0)); - ResultExpr = Obj; - ExprType = Call->getCallReturnType(*Context); - } - } - - if (Member->isArrow() && Obj && exprReferencesVariable(IndexVar, Obj)) { - if (ExprType.isNull()) - ExprType = Obj->getType(); - - assert(ExprType->isPointerType() && "Operator-> returned non-pointer type"); - // FIXME: This works around not having the location of the arrow operator. - // Consider adding OperatorLoc to MemberExpr? - SourceLocation ArrowLoc = - Lexer::getLocForEndOfToken(Base->getExprLoc(), 0, - Context->getSourceManager(), - Context->getLangOpts()); - // If something complicated is happening (i.e. the next token isn't an - // arrow), give up on making this work. - if (ArrowLoc.isValid()) { - Usages.push_back(Usage(ResultExpr, /*IsArrow=*/true, - SourceRange(Base->getExprLoc(), ArrowLoc))); - return true; - } - } - return TraverseStmt(Member->getBase()); -} - -/// \brief If a member function call is the at() accessor on the container with -/// IndexVar as the single argument, include it as a valid usage and prune -/// the traversal. -/// -/// Member calls on other objects will not be permitted. -/// Calls on the iterator object are not permitted, unless done through -/// operator->(). The one exception is allowing vector::at() for pseudoarrays. -bool ForLoopIndexUseVisitor::TraverseCXXMemberCallExpr( - CXXMemberCallExpr *MemberCall) { - MemberExpr *Member = - dyn_cast(MemberCall->getCallee()->IgnoreParenImpCasts()); - if (!Member) - return VisitorBase::TraverseCXXMemberCallExpr(MemberCall); - // We specifically allow an accessor named "at" to let STL in, though - // this is restricted to pseudo-arrays by requiring a single, integer - // argument. - const IdentifierInfo *Ident = Member->getMemberDecl()->getIdentifier(); - if (Ident && Ident->isStr("at") && MemberCall->getNumArgs() == 1) { - if (isIndexInSubscriptExpr(Context, MemberCall->getArg(0), IndexVar, - Member->getBase(), ContainerExpr, - ContainerNeedsDereference)) { - Usages.push_back(Usage(MemberCall)); - return true; - } - } - - if (containsExpr(Context, &DependentExprs, Member->getBase())) - ConfidenceLevel.lowerTo(RL_Risky); - - return VisitorBase::TraverseCXXMemberCallExpr(MemberCall); -} - -/// \brief If an overloaded operator call is a dereference of IndexVar or -/// a subscript of a the container with IndexVar as the single argument, -/// include it as a valid usage and prune the traversal. -/// -/// For example, given -/// \code -/// struct Foo { int bar(); int x; }; -/// vector v; -/// void f(Foo); -/// \endcode -/// the following uses will be considered convertible: -/// \code -/// for (vector::iterator i = v.begin(), e = v.end(); i != e; ++i) { -/// f(*i); -/// } -/// for (int i = 0; i < v.size(); ++i) { -/// int i = v[i] + 1; -/// } -/// \endcode -bool ForLoopIndexUseVisitor::TraverseCXXOperatorCallExpr( - CXXOperatorCallExpr *OpCall) { - switch (OpCall->getOperator()) { - case OO_Star: - if (isDereferenceOfOpCall(OpCall, IndexVar)) { - Usages.push_back(Usage(OpCall)); - return true; - } - break; - - case OO_Subscript: - if (OpCall->getNumArgs() != 2) - break; - if (isIndexInSubscriptExpr(Context, OpCall->getArg(1), IndexVar, - OpCall->getArg(0), ContainerExpr, - ContainerNeedsDereference)) { - Usages.push_back(Usage(OpCall)); - return true; - } - break; - - default: - break; - } - return VisitorBase::TraverseCXXOperatorCallExpr(OpCall); -} - -/// \brief If we encounter an array with IndexVar as the index of an -/// ArraySubsriptExpression, note it as a consistent usage and prune the -/// AST traversal. -/// -/// For example, given -/// \code -/// const int N = 5; -/// int arr[N]; -/// \endcode -/// This is intended to permit -/// \code -/// for (int i = 0; i < N; ++i) { /* use arr[i] */ } -/// \endcode -/// but not -/// \code -/// for (int i = 0; i < N; ++i) { /* use notArr[i] */ } -/// \endcode -/// and further checking needs to be done later to ensure that exactly one array -/// is referenced. -bool ForLoopIndexUseVisitor::TraverseArraySubscriptExpr( - ArraySubscriptExpr *E) { - Expr *Arr = E->getBase(); - if (!isIndexInSubscriptExpr(E->getIdx(), IndexVar)) - return VisitorBase::TraverseArraySubscriptExpr(E); - - if ((ContainerExpr && !areSameExpr(Context, Arr->IgnoreParenImpCasts(), - ContainerExpr->IgnoreParenImpCasts())) - || !arrayMatchesBoundExpr(Context, Arr->IgnoreImpCasts()->getType(), - ArrayBoundExpr)) { - // If we have already discovered the array being indexed and this isn't it - // or this array doesn't match, mark this loop as unconvertible. - OnlyUsedAsIndex = false; - return VisitorBase::TraverseArraySubscriptExpr(E); - } - - if (!ContainerExpr) - ContainerExpr = Arr; - - Usages.push_back(Usage(E)); - return true; -} - -/// \brief If we encounter a reference to IndexVar in an unpruned branch of the -/// traversal, mark this loop as unconvertible. -/// -/// This implements the whitelist for convertible loops: any usages of IndexVar -/// not explicitly considered convertible by this traversal will be caught by -/// this function. -/// -/// Additionally, if the container expression is more complex than just a -/// DeclRefExpr, and some part of it is appears elsewhere in the loop, lower -/// our confidence in the transformation. -/// -/// For example, these are not permitted: -/// \code -/// for (int i = 0; i < N; ++i) { printf("arr[%d] = %d", i, arr[i]); } -/// for (vector::iterator i = container.begin(), e = container.end(); -/// i != e; ++i) -/// i.insert(0); -/// for (vector::iterator i = container.begin(), e = container.end(); -/// i != e; ++i) -/// i.insert(0); -/// for (vector::iterator i = container.begin(), e = container.end(); -/// i != e; ++i) -/// if (i + 1 != e) -/// printf("%d", *i); -/// \endcode -/// -/// And these will raise the risk level: -/// \code -/// int arr[10][20]; -/// int l = 5; -/// for (int j = 0; j < 20; ++j) -/// int k = arr[l][j] + l; // using l outside arr[l] is considered risky -/// for (int i = 0; i < obj.getVector().size(); ++i) -/// obj.foo(10); // using `obj` is considered risky -/// \endcode -bool ForLoopIndexUseVisitor::VisitDeclRefExpr(DeclRefExpr *E) { - const ValueDecl *TheDecl = E->getDecl(); - if (areSameVariable(IndexVar, TheDecl) || areSameVariable(EndVar, TheDecl)) - OnlyUsedAsIndex = false; - if (containsExpr(Context, &DependentExprs, E)) - ConfidenceLevel.lowerTo(RL_Risky); - return true; -} - -/// \brief If we find that another variable is created just to refer to the loop -/// element, note it for reuse as the loop variable. -/// -/// See the comments for isAliasDecl. -bool ForLoopIndexUseVisitor::VisitDeclStmt(DeclStmt *S) { - if (!AliasDecl && S->isSingleDecl() && - isAliasDecl(S->getSingleDecl(), IndexVar)) { - AliasDecl = S; - if (CurrStmtParent) { - if (isa(CurrStmtParent) || - isa(CurrStmtParent) || - isa(CurrStmtParent)) - ReplaceWithAliasUse = true; - else if (isa(CurrStmtParent)) { - if (cast(CurrStmtParent)->getConditionVariableDeclStmt() == S) - ReplaceWithAliasUse = true; - else - // It's assumed S came the for loop's init clause. - AliasFromForInit = true; - } - } - } - - return true; -} - -bool ForLoopIndexUseVisitor::TraverseStmt(Stmt *S) { - // All this pointer swapping is a mechanism for tracking immediate parentage - // of Stmts. - const Stmt *OldNextParent = NextStmtParent; - CurrStmtParent = NextStmtParent; - NextStmtParent = S; - bool Result = VisitorBase::TraverseStmt(S); - NextStmtParent = OldNextParent; - return Result; -} - -//// \brief Apply the source transformations necessary to migrate the loop! -void LoopFixer::doConversion(ASTContext *Context, - const VarDecl *IndexVar, - const VarDecl *MaybeContainer, - StringRef ContainerString, - const UsageResult &Usages, - const DeclStmt *AliasDecl, - bool AliasUseRequired, - bool AliasFromForInit, - const ForStmt *TheLoop, - bool ContainerNeedsDereference, - bool DerefByValue, - bool DerefByConstRef) { - std::string VarName; - bool VarNameFromAlias = Usages.size() == 1 && AliasDecl; - bool AliasVarIsRef = false; - - if (VarNameFromAlias) { - const VarDecl *AliasVar = cast(AliasDecl->getSingleDecl()); - VarName = AliasVar->getName().str(); - AliasVarIsRef = AliasVar->getType()->isReferenceType(); - - // We keep along the entire DeclStmt to keep the correct range here. - SourceRange ReplaceRange = AliasDecl->getSourceRange(); - - std::string ReplacementText; - if (AliasUseRequired) - ReplacementText = VarName; - else if (AliasFromForInit) - // FIXME: Clang includes the location of the ';' but only for DeclStmt's - // in a for loop's init clause. Need to put this ';' back while removing - // the declaration of the alias variable. This is probably a bug. - ReplacementText = ";"; - - Owner.addReplacementForCurrentTU(Replacement( - Context->getSourceManager(), - CharSourceRange::getTokenRange(ReplaceRange), ReplacementText)); - // No further replacements are made to the loop, since the iterator or index - // was used exactly once - in the initialization of AliasVar. - } else { - VariableNamer Namer(&TUInfo.getGeneratedDecls(), - &TUInfo.getParentFinder().getStmtToParentStmtMap(), - TheLoop, IndexVar, MaybeContainer, Context); - VarName = Namer.createIndexName(); - // First, replace all usages of the array subscript expression with our new - // variable. - for (UsageResult::const_iterator I = Usages.begin(), E = Usages.end(); - I != E; ++I) { - std::string ReplaceText = I->IsArrow ? VarName + "." : VarName; - TUInfo.getReplacedVars().insert(std::make_pair(TheLoop, IndexVar)); - Owner.addReplacementForCurrentTU( - Replacement(Context->getSourceManager(), - CharSourceRange::getTokenRange(I->Range), ReplaceText)); - } - } - - // Now, we need to construct the new range expresion. - SourceRange ParenRange(TheLoop->getLParenLoc(), TheLoop->getRParenLoc()); - - QualType AutoRefType = Context->getAutoDeductType(); - - // If the new variable name is from the aliased variable, then the reference - // type for the new variable should only be used if the aliased variable was - // declared as a reference. - if (!VarNameFromAlias || AliasVarIsRef) { - // If an iterator's operator*() returns a 'T&' we can bind that to 'auto&'. - // If operator*() returns 'T' we can bind that to 'auto&&' which will deduce - // to 'T&&'. - if (DerefByValue) - AutoRefType = Context->getRValueReferenceType(AutoRefType); - else { - if (DerefByConstRef) - AutoRefType = Context->getConstType(AutoRefType); - AutoRefType = Context->getLValueReferenceType(AutoRefType); - } - } - - std::string MaybeDereference = ContainerNeedsDereference ? "*" : ""; - std::string TypeString = AutoRefType.getAsString(); - std::string Range = ("(" + TypeString + " " + VarName + " : " - + MaybeDereference + ContainerString + ")").str(); - Owner.addReplacementForCurrentTU( - Replacement(Context->getSourceManager(), - CharSourceRange::getTokenRange(ParenRange), Range)); - TUInfo.getGeneratedDecls().insert(make_pair(TheLoop, VarName)); -} - -/// \brief Determine whether Init appears to be an initializing an iterator. -/// -/// If it is, returns the object whose begin() or end() method is called, and -/// the output parameter isArrow is set to indicate whether the initialization -/// is called via . or ->. -static const Expr *getContainerFromBeginEndCall(const Expr *Init, bool IsBegin, - bool *IsArrow) { - // FIXME: Maybe allow declaration/initialization outside of the for loop? - const CXXMemberCallExpr *TheCall = - dyn_cast_or_null(digThroughConstructors(Init)); - if (!TheCall || TheCall->getNumArgs() != 0) - return nullptr; - - const MemberExpr *Member = dyn_cast(TheCall->getCallee()); - if (!Member) - return nullptr; - const std::string Name = Member->getMemberDecl()->getName(); - const std::string TargetName = IsBegin ? "begin" : "end"; - if (Name != TargetName) - return nullptr; - - const Expr *SourceExpr = Member->getBase(); - if (!SourceExpr) - return nullptr; - - *IsArrow = Member->isArrow(); - return SourceExpr; -} - -/// \brief Determines the container whose begin() and end() functions are called -/// for an iterator-based loop. -/// -/// BeginExpr must be a member call to a function named "begin()", and EndExpr -/// must be a member . -static const Expr *findContainer(ASTContext *Context, const Expr *BeginExpr, - const Expr *EndExpr, - bool *ContainerNeedsDereference) { - // Now that we know the loop variable and test expression, make sure they are - // valid. - bool BeginIsArrow = false; - bool EndIsArrow = false; - const Expr *BeginContainerExpr = - getContainerFromBeginEndCall(BeginExpr, /*IsBegin=*/true, &BeginIsArrow); - if (!BeginContainerExpr) - return nullptr; - - const Expr *EndContainerExpr = - getContainerFromBeginEndCall(EndExpr, /*IsBegin=*/false, &EndIsArrow); - // Disallow loops that try evil things like this (note the dot and arrow): - // for (IteratorType It = Obj.begin(), E = Obj->end(); It != E; ++It) { } - if (!EndContainerExpr || BeginIsArrow != EndIsArrow || - !areSameExpr(Context, EndContainerExpr, BeginContainerExpr)) - return nullptr; - - *ContainerNeedsDereference = BeginIsArrow; - return BeginContainerExpr; -} - -StringRef LoopFixer::checkDeferralsAndRejections(ASTContext *Context, - const Expr *ContainerExpr, - Confidence ConfidenceLevel, - const ForStmt *TheLoop) { - // If we already modified the range of this for loop, don't do any further - // updates on this iteration. - // FIXME: Once Replacements can detect conflicting edits, replace this - // implementation and rely on conflicting edit detection instead. - if (TUInfo.getReplacedVars().count(TheLoop)) { - ++*DeferredChanges; - return ""; - } - - TUInfo.getParentFinder().gatherAncestors(Context->getTranslationUnitDecl()); - // Ensure that we do not try to move an expression dependent on a local - // variable declared inside the loop outside of it! - DependencyFinderASTVisitor DependencyFinder( - &TUInfo.getParentFinder().getStmtToParentStmtMap(), - &TUInfo.getParentFinder().getDeclToParentStmtMap(), - &TUInfo.getReplacedVars(), TheLoop); - - // Not all of these are actually deferred changes. - // FIXME: Determine when the external dependency isn't an expression converted - // by another loop. - if (DependencyFinder.dependsOnInsideVariable(ContainerExpr)) { - ++*DeferredChanges; - return ""; - } - if (ConfidenceLevel.getRiskLevel() > MaxRisk) { - ++*RejectedChanges; - return ""; - } - - StringRef ContainerString; - if (isa(ContainerExpr->IgnoreParenImpCasts())) { - ContainerString = "this"; - } else { - ContainerString = getStringFromRange(Context->getSourceManager(), - Context->getLangOpts(), - ContainerExpr->getSourceRange()); - } - - // In case someone is using an evil macro, reject this change. - if (ContainerString.empty()) - ++*RejectedChanges; - return ContainerString; -} - -/// \brief Given that we have verified that the loop's header appears to be -/// convertible, run the complete analysis on the loop to determine if the -/// loop's body is convertible. -void LoopFixer::findAndVerifyUsages(ASTContext *Context, - const VarDecl *LoopVar, - const VarDecl *EndVar, - const Expr *ContainerExpr, - const Expr *BoundExpr, - bool ContainerNeedsDereference, - bool DerefByValue, - bool DerefByConstRef, - const ForStmt *TheLoop, - Confidence ConfidenceLevel) { - ForLoopIndexUseVisitor Finder(Context, LoopVar, EndVar, ContainerExpr, - BoundExpr, ContainerNeedsDereference); - if (ContainerExpr) { - ComponentFinderASTVisitor ComponentFinder; - ComponentFinder.findExprComponents(ContainerExpr->IgnoreParenImpCasts()); - Finder.addComponents(ComponentFinder.getComponents()); - } - - if (!Finder.findAndVerifyUsages(TheLoop->getBody())) - return; - - ConfidenceLevel.lowerTo(Finder.getRiskLevel()); - if (FixerKind == LFK_Array) { - // The array being indexed by IndexVar was discovered during traversal. - ContainerExpr = Finder.getContainerIndexed()->IgnoreParenImpCasts(); - // Very few loops are over expressions that generate arrays rather than - // array variables. Consider loops over arrays that aren't just represented - // by a variable to be risky conversions. - if (!getReferencedVariable(ContainerExpr) && - !isDirectMemberExpr(ContainerExpr)) - ConfidenceLevel.lowerTo(RL_Risky); - } - - std::string ContainerString = - checkDeferralsAndRejections(Context, ContainerExpr, - ConfidenceLevel, TheLoop); - if (ContainerString.empty()) - return; - - doConversion(Context, LoopVar, getReferencedVariable(ContainerExpr), - ContainerString, Finder.getUsages(), Finder.getAliasDecl(), - Finder.aliasUseRequired(), Finder.aliasFromForInit(), TheLoop, - ContainerNeedsDereference, DerefByValue, DerefByConstRef); - ++*AcceptedChanges; -} - -/// \brief The LoopFixer callback, which determines if loops discovered by the -/// matchers are convertible, printing information about the loops if so. -void LoopFixer::run(const MatchFinder::MatchResult &Result) { - const BoundNodes &Nodes = Result.Nodes; - Confidence ConfidenceLevel(RL_Safe); - ASTContext *Context = Result.Context; - const ForStmt *TheLoop = Nodes.getStmtAs(LoopName); - - if (!Owner.isFileModifiable(Context->getSourceManager(),TheLoop->getForLoc())) - return; - - // Check that we have exactly one index variable and at most one end variable. - const VarDecl *LoopVar = Nodes.getDeclAs(IncrementVarName); - const VarDecl *CondVar = Nodes.getDeclAs(ConditionVarName); - const VarDecl *InitVar = Nodes.getDeclAs(InitVarName); - if (!areSameVariable(LoopVar, CondVar) || !areSameVariable(LoopVar, InitVar)) - return; - const VarDecl *EndVar = Nodes.getDeclAs(EndVarName); - const VarDecl *ConditionEndVar = - Nodes.getDeclAs(ConditionEndVarName); - if (EndVar && !areSameVariable(EndVar, ConditionEndVar)) - return; - - // If the end comparison isn't a variable, we can try to work with the - // expression the loop variable is being tested against instead. - const CXXMemberCallExpr *EndCall = - Nodes.getStmtAs(EndCallName); - const Expr *BoundExpr = Nodes.getStmtAs(ConditionBoundName); - // If the loop calls end()/size() after each iteration, lower our confidence - // level. - if (FixerKind != LFK_Array && !EndVar) - ConfidenceLevel.lowerTo(RL_Reasonable); - - const Expr *ContainerExpr = nullptr; - bool DerefByValue = false; - bool DerefByConstRef = false; - bool ContainerNeedsDereference = false; - // FIXME: Try to put most of this logic inside a matcher. Currently, matchers - // don't allow the right-recursive checks in digThroughConstructors. - if (FixerKind == LFK_Iterator) { - ContainerExpr = findContainer(Context, LoopVar->getInit(), - EndVar ? EndVar->getInit() : EndCall, - &ContainerNeedsDereference); - - QualType InitVarType = InitVar->getType(); - QualType CanonicalInitVarType = InitVarType.getCanonicalType(); - - const CXXMemberCallExpr *BeginCall = - Nodes.getNodeAs(BeginCallName); - assert(BeginCall && "Bad Callback. No begin call expression."); - QualType CanonicalBeginType = - BeginCall->getMethodDecl()->getReturnType().getCanonicalType(); - - if (CanonicalBeginType->isPointerType() && - CanonicalInitVarType->isPointerType()) { - QualType BeginPointeeType = CanonicalBeginType->getPointeeType(); - QualType InitPointeeType = CanonicalInitVarType->getPointeeType(); - // If the initializer and the variable are both pointers check if the - // un-qualified pointee types match otherwise we don't use auto. - if (!Context->hasSameUnqualifiedType(InitPointeeType, BeginPointeeType)) - return; - } else { - // Check for qualified types to avoid conversions from non-const to const - // iterator types. - if (!Context->hasSameType(CanonicalInitVarType, CanonicalBeginType)) - return; - } - - DerefByValue = Nodes.getNodeAs(DerefByValueResultName) != nullptr; - if (!DerefByValue) { - if (const QualType *DerefType = - Nodes.getNodeAs(DerefByRefResultName)) { - // A node will only be bound with DerefByRefResultName if we're dealing - // with a user-defined iterator type. Test the const qualification of - // the reference type. - DerefByConstRef = (*DerefType)->getAs()->getPointeeType() - .isConstQualified(); - } else { - // By nature of the matcher this case is triggered only for built-in - // iterator types (i.e. pointers). - assert(isa(CanonicalInitVarType) && - "Non-class iterator type is not a pointer type"); - QualType InitPointeeType = CanonicalInitVarType->getPointeeType(); - QualType BeginPointeeType = CanonicalBeginType->getPointeeType(); - // If the initializer and variable have both the same type just use auto - // otherwise we test for const qualification of the pointed-at type. - if (!Context->hasSameType(InitPointeeType, BeginPointeeType)) - DerefByConstRef = InitPointeeType.isConstQualified(); - } - } else { - // If the dereference operator returns by value then test for the - // canonical const qualification of the init variable type. - DerefByConstRef = CanonicalInitVarType.isConstQualified(); - } - } else if (FixerKind == LFK_PseudoArray) { - if (!EndCall) - return; - ContainerExpr = EndCall->getImplicitObjectArgument(); - const MemberExpr *Member = dyn_cast(EndCall->getCallee()); - if (!Member) - return; - ContainerNeedsDereference = Member->isArrow(); - } - // We must know the container or an array length bound. - if (!ContainerExpr && !BoundExpr) - return; - - findAndVerifyUsages(Context, LoopVar, EndVar, ContainerExpr, BoundExpr, - ContainerNeedsDereference, DerefByValue, DerefByConstRef, - TheLoop, ConfidenceLevel); -} Index: clang-modernize/LoopConvert/LoopConvert.h =================================================================== --- clang-modernize/LoopConvert/LoopConvert.h +++ /dev/null @@ -1,44 +0,0 @@ -//===-- LoopConvert/LoopConvert.h - C++11 for-loop migration ----*- 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 LoopConvertTransform -/// class which is the main interface to the loop-convert transform that tries -/// to make use of range-based for loops where possible. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_LOOP_CONVERT_H -#define CLANG_MODERNIZE_LOOP_CONVERT_H - -#include "Core/Transform.h" -#include "llvm/Support/Compiler.h" // For override - -// Forward decl for private implementation. -struct TUTrackingInfo; - -/// \brief Subclass of Transform that transforms for-loops into range-based -/// for-loops where possible. -class LoopConvertTransform : public Transform { -public: - LoopConvertTransform(const TransformOptions &Options) - : Transform("LoopConvert", Options) {} - - /// \see Transform::run(). - int apply(const clang::tooling::CompilationDatabase &Database, - const std::vector &SourcePaths) override; - - bool handleBeginSource(clang::CompilerInstance &CI, - llvm::StringRef Filename) override; - -private: - std::unique_ptr TUInfo; -}; - -#endif // CLANG_MODERNIZE_LOOP_CONVERT_H Index: clang-modernize/LoopConvert/LoopConvert.cpp =================================================================== --- clang-modernize/LoopConvert/LoopConvert.cpp +++ /dev/null @@ -1,93 +0,0 @@ -//===-- LoopConvert/LoopConvert.cpp - C++11 for-loop migration ------------===// -// -// 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 LoopConvertTransform -/// class. -/// -//===----------------------------------------------------------------------===// - -#include "LoopConvert.h" -#include "LoopActions.h" -#include "LoopMatchers.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Tooling/Refactoring.h" -#include "clang/Tooling/Tooling.h" - -using clang::ast_matchers::MatchFinder; -using namespace clang::tooling; -using namespace clang; - -int LoopConvertTransform::apply(const CompilationDatabase &Database, - const std::vector &SourcePaths) { - ClangTool LoopTool(Database, SourcePaths); - - unsigned AcceptedChanges = 0; - unsigned DeferredChanges = 0; - unsigned RejectedChanges = 0; - - TUInfo.reset(new TUTrackingInfo); - - MatchFinder Finder; - LoopFixer ArrayLoopFixer(*TUInfo, &AcceptedChanges, &DeferredChanges, - &RejectedChanges, Options().MaxRiskLevel, LFK_Array, - /*Owner=*/ *this); - Finder.addMatcher(makeArrayLoopMatcher(), &ArrayLoopFixer); - LoopFixer IteratorLoopFixer(*TUInfo, &AcceptedChanges, &DeferredChanges, - &RejectedChanges, Options().MaxRiskLevel, - LFK_Iterator, /*Owner=*/ *this); - Finder.addMatcher(makeIteratorLoopMatcher(), &IteratorLoopFixer); - LoopFixer PseudoarrrayLoopFixer(*TUInfo, &AcceptedChanges, &DeferredChanges, - &RejectedChanges, Options().MaxRiskLevel, - LFK_PseudoArray, /*Owner=*/ *this); - Finder.addMatcher(makePseudoArrayLoopMatcher(), &PseudoarrrayLoopFixer); - - if (int result = LoopTool.run(createActionFactory(Finder).get())) { - llvm::errs() << "Error encountered during translation.\n"; - return result; - } - - setAcceptedChanges(AcceptedChanges); - setRejectedChanges(RejectedChanges); - setDeferredChanges(DeferredChanges); - - return 0; -} - -bool -LoopConvertTransform::handleBeginSource(clang::CompilerInstance &CI, - llvm::StringRef Filename) { - // Reset and initialize per-TU tracking structures. - TUInfo->reset(); - - return Transform::handleBeginSource(CI, Filename); -} - -namespace { -struct LoopConvertFactory : TransformFactory { - LoopConvertFactory() { - Since.Clang = Version(3, 0); - Since.Gcc = Version(4, 6); - Since.Icc = Version(13); - Since.Msvc = Version(11); - } - - Transform *createTransform(const TransformOptions &Opts) override { - return new LoopConvertTransform(Opts); - } -}; -} // namespace - -// Register the factory using this statically initialized variable. -static TransformFactoryRegistry::Add -X("loop-convert", "Make use of range-based for loops where possible"); - -// This anchor is used to force the linker to link in the generated object file -// and thus register the factory. -volatile int LoopConvertTransformAnchorSource = 0; Index: clang-modernize/LoopConvert/LoopMatchers.h =================================================================== --- clang-modernize/LoopConvert/LoopMatchers.h +++ /dev/null @@ -1,42 +0,0 @@ -//===-- LoopConvert/LoopMatchers.h - Matchers for for loops -----*- 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 declarations of the matchers for use in migrating -/// C++ for loops. The matchers are responsible for checking the general shape -/// of the for loop, namely the init, condition, and increment portions. -/// Further analysis will be needed to confirm that the loop is in fact -/// convertible in the matcher callback. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_LOOP_MATCHERS_H -#define CLANG_MODERNIZE_LOOP_MATCHERS_H - -#include "clang/ASTMatchers/ASTMatchers.h" - -// Constants used for matcher name bindings -extern const char LoopName[]; -extern const char ConditionBoundName[]; -extern const char ConditionVarName[]; -extern const char ConditionEndVarName[]; -extern const char IncrementVarName[]; -extern const char InitVarName[]; -extern const char BeginCallName[]; -extern const char EndExprName[]; -extern const char EndCallName[]; -extern const char EndVarName[]; -extern const char DerefByValueResultName[]; -extern const char DerefByRefResultName[]; - -clang::ast_matchers::StatementMatcher makeArrayLoopMatcher(); -clang::ast_matchers::StatementMatcher makeIteratorLoopMatcher(); -clang::ast_matchers::StatementMatcher makePseudoArrayLoopMatcher(); - -#endif // CLANG_MODERNIZE_LOOP_MATCHERS_H Index: clang-modernize/LoopConvert/LoopMatchers.cpp =================================================================== --- clang-modernize/LoopConvert/LoopMatchers.cpp +++ /dev/null @@ -1,345 +0,0 @@ -//===-- LoopConvert/LoopMatchers.cpp - Matchers for for loops -------------===// -// -// 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 definitions of the matchers for use in migrating -/// C++ for loops. -/// -//===----------------------------------------------------------------------===// - -#include "LoopMatchers.h" - -using namespace clang::ast_matchers; -using namespace clang; - -const char LoopName[] = "forLoop"; -const char ConditionBoundName[] = "conditionBound"; -const char ConditionVarName[] = "conditionVar"; -const char IncrementVarName[] = "incrementVar"; -const char InitVarName[] = "initVar"; -const char BeginCallName[] = "beginCall"; -const char EndCallName[] = "endCall"; -const char ConditionEndVarName[] = "conditionEndVar"; -const char EndVarName[] = "endVar"; -const char DerefByValueResultName[] = "derefByValueResult"; -const char DerefByRefResultName[] = "derefByRefResult"; - -// shared matchers -static const TypeMatcher AnyType = anything(); - -static const StatementMatcher IntegerComparisonMatcher = - expr(ignoringParenImpCasts(declRefExpr(to( - varDecl(hasType(isInteger())).bind(ConditionVarName))))); - -static const DeclarationMatcher InitToZeroMatcher = - varDecl(hasInitializer(ignoringParenImpCasts( - integerLiteral(equals(0))))).bind(InitVarName); - -static const StatementMatcher IncrementVarMatcher = - declRefExpr(to( - varDecl(hasType(isInteger())).bind(IncrementVarName))); - -// FIXME: How best to document complicated matcher expressions? They're fairly -// self-documenting...but there may be some unintuitive parts. - -/// \brief The matcher for loops over arrays. -/// -/// In this general example, assuming 'j' and 'k' are of integral type: -/// \code -/// for (int i = 0; j < 3 + 2; ++k) { ... } -/// \endcode -/// The following string identifiers are bound to these parts of the AST: -/// ConditionVarName: 'j' (as a VarDecl) -/// ConditionBoundName: '3 + 2' (as an Expr) -/// InitVarName: 'i' (as a VarDecl) -/// IncrementVarName: 'k' (as a VarDecl) -/// LoopName: The entire for loop (as a ForStmt) -/// -/// Client code will need to make sure that: -/// - The three index variables identified by the matcher are the same -/// VarDecl. -/// - The index variable is only used as an array index. -/// - All arrays indexed by the loop are the same. -StatementMatcher makeArrayLoopMatcher() { - StatementMatcher ArrayBoundMatcher = - expr(hasType(isInteger())).bind(ConditionBoundName); - - return forStmt( - hasLoopInit(declStmt(hasSingleDecl(InitToZeroMatcher))), - hasCondition(anyOf(binaryOperator(hasOperatorName("<"), - hasLHS(IntegerComparisonMatcher), - hasRHS(ArrayBoundMatcher)), - binaryOperator(hasOperatorName(">"), - hasLHS(ArrayBoundMatcher), - hasRHS(IntegerComparisonMatcher)))), - hasIncrement(unaryOperator(hasOperatorName("++"), - hasUnaryOperand(IncrementVarMatcher)))) - .bind(LoopName); -} - -/// \brief The matcher used for iterator-based for loops. -/// -/// This matcher is more flexible than array-based loops. It will match -/// catch loops of the following textual forms (regardless of whether the -/// iterator type is actually a pointer type or a class type): -/// -/// Assuming f, g, and h are of type containerType::iterator, -/// \code -/// for (containerType::iterator it = container.begin(), -/// e = createIterator(); f != g; ++h) { ... } -/// for (containerType::iterator it = container.begin(); -/// f != anotherContainer.end(); ++h) { ... } -/// \endcode -/// The following string identifiers are bound to the parts of the AST: -/// InitVarName: 'it' (as a VarDecl) -/// ConditionVarName: 'f' (as a VarDecl) -/// LoopName: The entire for loop (as a ForStmt) -/// In the first example only: -/// EndVarName: 'e' (as a VarDecl) -/// ConditionEndVarName: 'g' (as a VarDecl) -/// In the second example only: -/// EndCallName: 'container.end()' (as a CXXMemberCallExpr) -/// -/// Client code will need to make sure that: -/// - The iterator variables 'it', 'f', and 'h' are the same -/// - The two containers on which 'begin' and 'end' are called are the same -/// - If the end iterator variable 'g' is defined, it is the same as 'f' -StatementMatcher makeIteratorLoopMatcher() { - StatementMatcher BeginCallMatcher = - cxxMemberCallExpr( - argumentCountIs(0), - callee( - cxxMethodDecl(hasName("begin")) - ) - ).bind(BeginCallName); - - DeclarationMatcher InitDeclMatcher = - varDecl( - hasInitializer( - anyOf( - ignoringParenImpCasts(BeginCallMatcher), - materializeTemporaryExpr(ignoringParenImpCasts(BeginCallMatcher)), - hasDescendant(BeginCallMatcher) - ) - ) - ).bind(InitVarName); - - DeclarationMatcher EndDeclMatcher = - varDecl(hasInitializer(anything())).bind(EndVarName); - - StatementMatcher EndCallMatcher = cxxMemberCallExpr( - argumentCountIs(0), callee(cxxMethodDecl(hasName("end")))); - - StatementMatcher IteratorBoundMatcher = - expr(anyOf(ignoringParenImpCasts(declRefExpr(to( - varDecl().bind(ConditionEndVarName)))), - ignoringParenImpCasts( - expr(EndCallMatcher).bind(EndCallName)), - materializeTemporaryExpr(ignoringParenImpCasts( - expr(EndCallMatcher).bind(EndCallName))))); - - StatementMatcher IteratorComparisonMatcher = - expr(ignoringParenImpCasts(declRefExpr(to( - varDecl().bind(ConditionVarName))))); - - StatementMatcher OverloadedNEQMatcher = cxxOperatorCallExpr( - hasOverloadedOperatorName("!="), - argumentCountIs(2), - hasArgument(0, IteratorComparisonMatcher), - hasArgument(1, IteratorBoundMatcher)); - - // This matcher tests that a declaration is a CXXRecordDecl that has an - // overloaded operator*(). If the operator*() returns by value instead of by - // reference then the return type is tagged with DerefByValueResultName. - internal::Matcher TestDerefReturnsByValue = - hasType( - cxxRecordDecl( - hasMethod( - allOf( - hasOverloadedOperatorName("*"), - anyOf( - // Tag the return type if it's by value. - returns( - qualType( - unless(hasCanonicalType(referenceType())) - ).bind(DerefByValueResultName) - ), - returns( - // Skip loops where the iterator's operator* returns an - // rvalue reference. This is just weird. - qualType( - unless( - hasCanonicalType(rValueReferenceType()) - ) - ).bind(DerefByRefResultName) - ) - ) - ) - ) - ) - ); - - - return - forStmt( - hasLoopInit(anyOf( - declStmt( - declCountIs(2), - containsDeclaration(0, InitDeclMatcher), - containsDeclaration(1, EndDeclMatcher) - ), - declStmt(hasSingleDecl(InitDeclMatcher)) - )), - hasCondition(anyOf( - binaryOperator( - hasOperatorName("!="), - hasLHS(IteratorComparisonMatcher), - hasRHS(IteratorBoundMatcher) - ), - binaryOperator( - hasOperatorName("!="), - hasLHS(IteratorBoundMatcher), - hasRHS(IteratorComparisonMatcher) - ), - OverloadedNEQMatcher - )), - hasIncrement(anyOf( - unaryOperator( - hasOperatorName("++"), - hasUnaryOperand( - declRefExpr(to( - varDecl(hasType(pointsTo(AnyType))).bind(IncrementVarName) - )) - ) - ), - cxxOperatorCallExpr( - hasOverloadedOperatorName("++"), - hasArgument(0, - declRefExpr(to( - varDecl(TestDerefReturnsByValue).bind(IncrementVarName) - )) - ) - ) - )) - ).bind(LoopName); -} - -/// \brief The matcher used for array-like containers (pseudoarrays). -/// -/// This matcher is more flexible than array-based loops. It will match -/// loops of the following textual forms (regardless of whether the -/// iterator type is actually a pointer type or a class type): -/// -/// Assuming f, g, and h are of type containerType::iterator, -/// \code -/// for (int i = 0, j = container.size(); f < g; ++h) { ... } -/// for (int i = 0; f < container.size(); ++h) { ... } -/// \endcode -/// The following string identifiers are bound to the parts of the AST: -/// InitVarName: 'i' (as a VarDecl) -/// ConditionVarName: 'f' (as a VarDecl) -/// LoopName: The entire for loop (as a ForStmt) -/// In the first example only: -/// EndVarName: 'j' (as a VarDecl) -/// ConditionEndVarName: 'g' (as a VarDecl) -/// In the second example only: -/// EndCallName: 'container.size()' (as a CXXMemberCallExpr) -/// -/// Client code will need to make sure that: -/// - The index variables 'i', 'f', and 'h' are the same -/// - The containers on which 'size()' is called is the container indexed -/// - The index variable is only used in overloaded operator[] or -/// container.at() -/// - If the end iterator variable 'g' is defined, it is the same as 'j' -/// - The container's iterators would not be invalidated during the loop -StatementMatcher makePseudoArrayLoopMatcher() { - // Test that the incoming type has a record declaration that has methods - // called 'begin' and 'end'. If the incoming type is const, then make sure - // these methods are also marked const. - // - // FIXME: To be completely thorough this matcher should also ensure the - // return type of begin/end is an iterator that dereferences to the same as - // what operator[] or at() returns. Such a test isn't likely to fail except - // for pathological cases. - // - // FIXME: Also, a record doesn't necessarily need begin() and end(). Free - // functions called begin() and end() taking the container as an argument - // are also allowed. - TypeMatcher RecordWithBeginEnd = - qualType(anyOf( - qualType( - isConstQualified(), - hasDeclaration( - cxxRecordDecl( - hasMethod( - cxxMethodDecl( - hasName("begin"), - isConst() - ) - ), - hasMethod( - cxxMethodDecl( - hasName("end"), - isConst() - ) - ) - ) - ) // hasDeclaration - ), // qualType - qualType( - unless(isConstQualified()), - hasDeclaration( - cxxRecordDecl( - hasMethod(hasName("begin")), - hasMethod(hasName("end")) - ) - ) - ) // qualType - ) - ); - - StatementMatcher SizeCallMatcher = cxxMemberCallExpr( - argumentCountIs(0), - callee(cxxMethodDecl(anyOf(hasName("size"), hasName("length")))), - on(anyOf(hasType(pointsTo(RecordWithBeginEnd)), - hasType(RecordWithBeginEnd)))); - - StatementMatcher EndInitMatcher = - expr(anyOf( - ignoringParenImpCasts(expr(SizeCallMatcher).bind(EndCallName)), - explicitCastExpr(hasSourceExpression(ignoringParenImpCasts( - expr(SizeCallMatcher).bind(EndCallName)))))); - - DeclarationMatcher EndDeclMatcher = - varDecl(hasInitializer(EndInitMatcher)).bind(EndVarName); - - StatementMatcher IndexBoundMatcher = - expr(anyOf( - ignoringParenImpCasts(declRefExpr(to( - varDecl(hasType(isInteger())).bind(ConditionEndVarName)))), - EndInitMatcher)); - - return forStmt( - hasLoopInit(anyOf( - declStmt(declCountIs(2), - containsDeclaration(0, InitToZeroMatcher), - containsDeclaration(1, EndDeclMatcher)), - declStmt(hasSingleDecl(InitToZeroMatcher)))), - hasCondition(anyOf( - binaryOperator(hasOperatorName("<"), - hasLHS(IntegerComparisonMatcher), - hasRHS(IndexBoundMatcher)), - binaryOperator(hasOperatorName(">"), - hasLHS(IndexBoundMatcher), - hasRHS(IntegerComparisonMatcher)))), - hasIncrement(unaryOperator( - hasOperatorName("++"), - hasUnaryOperand(IncrementVarMatcher)))) - .bind(LoopName); -} Index: clang-modernize/LoopConvert/StmtAncestor.h =================================================================== --- clang-modernize/LoopConvert/StmtAncestor.h +++ /dev/null @@ -1,201 +0,0 @@ -//===-- LoopConvert/StmtAncestor.h - AST property visitors ------*- 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 of several RecursiveASTVisitors -/// used to build and check data structures used in loop migration. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_STMT_ANCESTOR_H -#define CLANG_MODERNIZE_STMT_ANCESTOR_H - -#include "clang/AST/RecursiveASTVisitor.h" - -/// A map used to walk the AST in reverse: maps child Stmt to parent Stmt. -typedef llvm::DenseMap StmtParentMap; - -/// A map used to walk the AST in reverse: -/// maps VarDecl to the to parent DeclStmt. -typedef -llvm::DenseMap DeclParentMap; - -/// A map used to track which variables have been removed by a refactoring pass. -/// It maps the parent ForStmt to the removed index variable's VarDecl. -typedef -llvm::DenseMap ReplacedVarsMap; - -/// A map used to remember the variable names generated in a Stmt -typedef llvm::DenseMap StmtGeneratedVarNameMap; - -/// A vector used to store the AST subtrees of an Expr. -typedef llvm::SmallVector ComponentVector; - -/// \brief Class used build the reverse AST properties needed to detect -/// name conflicts and free variables. -class StmtAncestorASTVisitor : - public clang::RecursiveASTVisitor { -public: - StmtAncestorASTVisitor() { - StmtStack.push_back(nullptr); - } - - /// \brief Run the analysis on the TranslationUnitDecl. - /// - /// In case we're running this analysis multiple times, don't repeat the work. - void gatherAncestors(const clang::TranslationUnitDecl *T) { - if (StmtAncestors.empty()) - TraverseDecl(const_cast(T)); - } - - /// Accessor for StmtAncestors. - const StmtParentMap &getStmtToParentStmtMap() { - return StmtAncestors; - } - - /// Accessor for DeclParents. - const DeclParentMap &getDeclToParentStmtMap() { - return DeclParents; - } - - friend class clang::RecursiveASTVisitor; - -private: - StmtParentMap StmtAncestors; - DeclParentMap DeclParents; - llvm::SmallVector StmtStack; - - bool TraverseStmt(clang::Stmt *Statement); - bool VisitDeclStmt(clang::DeclStmt *Statement); -}; - -/// Class used to find the variables and member expressions on which an -/// arbitrary expression depends. -class ComponentFinderASTVisitor : - public clang::RecursiveASTVisitor { -public: - ComponentFinderASTVisitor() { } - - /// Find the components of an expression and place them in a ComponentVector. - void findExprComponents(const clang::Expr *SourceExpr) { - clang::Expr *E = const_cast(SourceExpr); - TraverseStmt(E); - } - - /// Accessor for Components. - const ComponentVector &getComponents() { - return Components; - } - - friend class clang::RecursiveASTVisitor; - -private: - ComponentVector Components; - - bool VisitDeclRefExpr(clang::DeclRefExpr *E); - bool VisitMemberExpr(clang::MemberExpr *Member); -}; - -/// Class used to determine if an expression is dependent on a variable declared -/// inside of the loop where it would be used. -class DependencyFinderASTVisitor : - public clang::RecursiveASTVisitor { -public: - DependencyFinderASTVisitor(const StmtParentMap *StmtParents, - const DeclParentMap *DeclParents, - const ReplacedVarsMap *ReplacedVars, - const clang::Stmt *ContainingStmt) : - StmtParents(StmtParents), DeclParents(DeclParents), - ContainingStmt(ContainingStmt), ReplacedVars(ReplacedVars) { } - - /// \brief Run the analysis on Body, and return true iff the expression - /// depends on some variable declared within ContainingStmt. - /// - /// This is intended to protect against hoisting the container expression - /// outside of an inner context if part of that expression is declared in that - /// inner context. - /// - /// For example, - /// \code - /// const int N = 10, M = 20; - /// int arr[N][M]; - /// int getRow(); - /// - /// for (int i = 0; i < M; ++i) { - /// int k = getRow(); - /// printf("%d:", arr[k][i]); - /// } - /// \endcode - /// At first glance, this loop looks like it could be changed to - /// \code - /// for (int elem : arr[k]) { - /// int k = getIndex(); - /// printf("%d:", elem); - /// } - /// \endcode - /// But this is malformed, since `k` is used before it is defined! - /// - /// In order to avoid this, this class looks at the container expression - /// `arr[k]` and decides whether or not it contains a sub-expression declared - /// within the the loop body. - bool dependsOnInsideVariable(const clang::Stmt *Body) { - DependsOnInsideVariable = false; - TraverseStmt(const_cast(Body)); - return DependsOnInsideVariable; - } - - friend class clang::RecursiveASTVisitor; - -private: - const StmtParentMap *StmtParents; - const DeclParentMap *DeclParents; - const clang::Stmt *ContainingStmt; - const ReplacedVarsMap *ReplacedVars; - bool DependsOnInsideVariable; - - bool VisitVarDecl(clang::VarDecl *V); - bool VisitDeclRefExpr(clang::DeclRefExpr *D); -}; - -/// Class used to determine if any declarations used in a Stmt would conflict -/// with a particular identifier. This search includes the names that don't -/// actually appear in the AST (i.e. created by a refactoring tool) by including -/// a map from Stmts to generated names associated with those stmts. -class DeclFinderASTVisitor : - public clang::RecursiveASTVisitor { -public: - DeclFinderASTVisitor(const std::string &Name, - const StmtGeneratedVarNameMap *GeneratedDecls) : - Name(Name), GeneratedDecls(GeneratedDecls), Found(false) { } - - /// Attempts to find any usages of variables name Name in Body, returning - /// true when it is used in Body. This includes the generated loop variables - /// of ForStmts which have already been transformed. - bool findUsages(const clang::Stmt *Body) { - Found = false; - TraverseStmt(const_cast(Body)); - return Found; - } - - friend class clang::RecursiveASTVisitor; - -private: - std::string Name; - /// GeneratedDecls keeps track of ForStmts which have been transformed, - /// mapping each modified ForStmt to the variable generated in the loop. - const StmtGeneratedVarNameMap *GeneratedDecls; - bool Found; - - bool VisitForStmt(clang::ForStmt *F); - bool VisitNamedDecl(clang::NamedDecl *D); - bool VisitDeclRefExpr(clang::DeclRefExpr *D); - bool VisitTypeLoc(clang::TypeLoc TL); -}; - -#endif // CLANG_MODERNIZE_STMT_ANCESTOR_H Index: clang-modernize/LoopConvert/StmtAncestor.cpp =================================================================== --- clang-modernize/LoopConvert/StmtAncestor.cpp +++ /dev/null @@ -1,140 +0,0 @@ -//===-- LoopConvert/StmtAncestor.cpp - AST property visitors --------------===// -// -// 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 definitions of several RecursiveASTVisitors -/// used to build and check data structures used in loop migration. -/// -//===----------------------------------------------------------------------===// - -#include "StmtAncestor.h" - -using namespace clang; - -/// \brief Tracks a stack of parent statements during traversal. -/// -/// All this really does is inject push_back() before running -/// RecursiveASTVisitor::TraverseStmt() and pop_back() afterwards. The Stmt atop -/// the stack is the parent of the current statement (NULL for the topmost -/// statement). -bool StmtAncestorASTVisitor::TraverseStmt(Stmt *Statement) { - StmtAncestors.insert(std::make_pair(Statement, StmtStack.back())); - StmtStack.push_back(Statement); - RecursiveASTVisitor::TraverseStmt(Statement); - StmtStack.pop_back(); - return true; -} - -/// \brief Keep track of the DeclStmt associated with each VarDecl. -/// -/// Combined with StmtAncestors, this provides roughly the same information as -/// Scope, as we can map a VarDecl to its DeclStmt, then walk up the parent tree -/// using StmtAncestors. -bool StmtAncestorASTVisitor::VisitDeclStmt(DeclStmt *Decls) { - for (DeclStmt::const_decl_iterator I = Decls->decl_begin(), - E = Decls->decl_end(); I != E; ++I) - if (const VarDecl *V = dyn_cast(*I)) - DeclParents.insert(std::make_pair(V, Decls)); - return true; -} - -/// \brief record the DeclRefExpr as part of the parent expression. -bool ComponentFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *E) { - Components.push_back(E); - return true; -} - -/// \brief record the MemberExpr as part of the parent expression. -bool ComponentFinderASTVisitor::VisitMemberExpr(MemberExpr *Member) { - Components.push_back(Member); - return true; -} - -/// \brief Forward any DeclRefExprs to a check on the referenced variable -/// declaration. -bool DependencyFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *DeclRef) { - if (VarDecl *V = dyn_cast_or_null(DeclRef->getDecl())) - return VisitVarDecl(V); - return true; -} - -/// \brief Determine if any this variable is declared inside the ContainingStmt. -bool DependencyFinderASTVisitor::VisitVarDecl(VarDecl *V) { - const Stmt *Curr = DeclParents->lookup(V); - // First, see if the variable was declared within an inner scope of the loop. - while (Curr != nullptr) { - if (Curr == ContainingStmt) { - DependsOnInsideVariable = true; - return false; - } - Curr = StmtParents->lookup(Curr); - } - - // Next, check if the variable was removed from existence by an earlier - // iteration. - for (ReplacedVarsMap::const_iterator I = ReplacedVars->begin(), - E = ReplacedVars->end(); I != E; ++I) - if ((*I).second == V) { - DependsOnInsideVariable = true; - return false; - } - return true; -} - -/// \brief If we already created a variable for TheLoop, check to make sure -/// that the name was not already taken. -bool DeclFinderASTVisitor::VisitForStmt(ForStmt *TheLoop) { - StmtGeneratedVarNameMap::const_iterator I = GeneratedDecls->find(TheLoop); - if (I != GeneratedDecls->end() && I->second == Name) { - Found = true; - return false; - } - return true; -} - -/// \brief If any named declaration within the AST subtree has the same name, -/// then consider Name already taken. -bool DeclFinderASTVisitor::VisitNamedDecl(NamedDecl *D) { - const IdentifierInfo *Ident = D->getIdentifier(); - if (Ident && Ident->getName() == Name) { - Found = true; - return false; - } - return true; -} - -/// \brief Forward any declaration references to the actual check on the -/// referenced declaration. -bool DeclFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *DeclRef) { - if (NamedDecl *D = dyn_cast(DeclRef->getDecl())) - return VisitNamedDecl(D); - return true; -} - -/// \brief If the new variable name conflicts with any type used in the loop, -/// then we mark that variable name as taken. -bool DeclFinderASTVisitor::VisitTypeLoc(TypeLoc TL) { - QualType QType = TL.getType(); - - // Check if our name conflicts with a type, to handle for typedefs. - if (QType.getAsString() == Name) { - Found = true; - return false; - } - // Check for base type conflicts. For example, when a struct is being - // referenced in the body of the loop, the above getAsString() will return the - // whole type (ex. "struct s"), but will be caught here. - if (const IdentifierInfo *Ident = QType.getBaseTypeIdentifier()) { - if (Ident->getName() == Name) { - Found = true; - return false; - } - } - return true; -} Index: clang-modernize/LoopConvert/VariableNaming.h =================================================================== --- clang-modernize/LoopConvert/VariableNaming.h +++ /dev/null @@ -1,59 +0,0 @@ -//===-- LoopConvert/VariableNaming.h - Gererate variable names --*- 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 VariableNamer class, which -/// is responsible for generating new variable names and ensuring that they do -/// not conflict with existing ones. -// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_VARIABLE_NAMING_H -#define CLANG_MODERNIZE_VARIABLE_NAMING_H - -#include "StmtAncestor.h" -#include "clang/AST/ASTContext.h" - -/// \brief Create names for generated variables within a particular statement. -/// -/// VariableNamer uses a DeclContext as a reference point, checking for any -/// conflicting declarations higher up in the context or within SourceStmt. -/// It creates a variable name using hints from a source container and the old -/// index, if they exist. -class VariableNamer { - public: - VariableNamer( - StmtGeneratedVarNameMap *GeneratedDecls, const StmtParentMap *ReverseAST, - const clang::Stmt *SourceStmt, const clang::VarDecl *OldIndex, - const clang::VarDecl *TheContainer, const clang::ASTContext *Context) - : GeneratedDecls(GeneratedDecls), ReverseAST(ReverseAST), - SourceStmt(SourceStmt), OldIndex(OldIndex), TheContainer(TheContainer), - Context(Context) {} - - /// \brief Generate a new index name. - /// - /// Generates the name to be used for an inserted iterator. It relies on - /// declarationExists() to determine that there are no naming conflicts, and - /// tries to use some hints from the container name and the old index name. - std::string createIndexName(); - - private: - StmtGeneratedVarNameMap *GeneratedDecls; - const StmtParentMap *ReverseAST; - const clang::Stmt *SourceStmt; - const clang::VarDecl *OldIndex; - const clang::VarDecl *TheContainer; - const clang::ASTContext *Context; - - // Determine whether or not a declaration that would conflict with Symbol - // exists in an outer context or in any statement contained in SourceStmt. - bool declarationExists(llvm::StringRef Symbol); -}; - -#endif // CLANG_MODERNIZE_VARIABLE_NAMING_H Index: clang-modernize/LoopConvert/VariableNaming.cpp =================================================================== --- clang-modernize/LoopConvert/VariableNaming.cpp +++ /dev/null @@ -1,95 +0,0 @@ -//===-- LoopConvert/VariableNaming.cpp - Gererate variable names ----------===// -// -// 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 definitino of the VariableNamer class, which -/// is responsible for generating new variable names and ensuring that they do -/// not conflict with existing ones. -/// -//===----------------------------------------------------------------------===// - -#include "VariableNaming.h" - -using namespace llvm; -using namespace clang; - -std::string VariableNamer::createIndexName() { - // FIXME: Add in naming conventions to handle: - // - Uppercase/lowercase indices - // - How to handle conflicts - // - An interactive process for naming - std::string IteratorName; - std::string ContainerName; - if (TheContainer) - ContainerName = TheContainer->getName().str(); - - size_t Len = ContainerName.length(); - if (Len > 1 && ContainerName[Len - 1] == 's') - IteratorName = ContainerName.substr(0, Len - 1); - else - IteratorName = "elem"; - - if (!declarationExists(IteratorName)) - return IteratorName; - - IteratorName = ContainerName + "_" + OldIndex->getName().str(); - if (!declarationExists(IteratorName)) - return IteratorName; - - IteratorName = ContainerName + "_elem"; - if (!declarationExists(IteratorName)) - return IteratorName; - - IteratorName += "_elem"; - if (!declarationExists(IteratorName)) - return IteratorName; - - IteratorName = "_elem_"; - - // Someone defeated my naming scheme... - while (declarationExists(IteratorName)) - IteratorName += "i"; - return IteratorName; -} - -/// \brief Determines whether or not the the name \a Symbol conflicts with -/// language keywords or defined macros. Also checks if the name exists in -/// LoopContext, any of its parent contexts, or any of its child statements. -/// -/// We also check to see if the same identifier was generated by this loop -/// converter in a loop nested within SourceStmt. -bool VariableNamer::declarationExists(StringRef Symbol) { - assert(Context != nullptr && "Expected an ASTContext"); - IdentifierInfo &Ident = Context->Idents.get(Symbol); - - // Check if the symbol is not an identifier (ie. is a keyword or alias). - if (!isAnyIdentifier(Ident.getTokenID())) - return true; - - // Check for conflicting macro definitions. - if (Ident.hasMacroDefinition()) - return true; - - // Determine if the symbol was generated in a parent context. - for (const Stmt *S = SourceStmt; S != nullptr; S = ReverseAST->lookup(S)) { - StmtGeneratedVarNameMap::const_iterator I = GeneratedDecls->find(S); - if (I != GeneratedDecls->end() && I->second == Symbol) - return true; - } - - // FIXME: Rather than detecting conflicts at their usages, we should check the - // parent context. - // For some reason, lookup() always returns the pair (NULL, NULL) because its - // StoredDeclsMap is not initialized (i.e. LookupPtr.getInt() is false inside - // of DeclContext::lookup()). Why is this? - - // Finally, determine if the symbol was used in the loop or a child context. - DeclFinderASTVisitor DeclFinder(Symbol, GeneratedDecls); - return DeclFinder.findUsages(SourceStmt); -} Index: clang-modernize/Makefile =================================================================== --- clang-modernize/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -##===- tools/extra/loop-convert/Makefile ----sssss----------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../../.. -include $(CLANG_LEVEL)/../../Makefile.config - -DIRS = Core tool - -include $(CLANG_LEVEL)/Makefile Index: clang-modernize/PassByValue/PassByValue.h =================================================================== --- clang-modernize/PassByValue/PassByValue.h +++ /dev/null @@ -1,73 +0,0 @@ -//===-- PassByValue.h -------------------------------------------*- 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 declaration of the PassByValueTransform -/// class. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_PASS_BY_VALUE_H -#define CLANG_MODERNIZE_PASS_BY_VALUE_H - -#include "Core/IncludeDirectives.h" -#include "Core/Transform.h" - -class ConstructorParamReplacer; - -/// \brief Subclass of Transform that uses pass-by-value semantic when move -/// constructors are available to avoid copies. -/// -/// When a class constructor accepts an object by const reference with the -/// intention of copying the object the copy can be avoided in certain -/// situations if the object has a move constructor. First, the constructor is -/// changed to accept the object by value instead. Then this argument is moved -/// instead of copied into class-local storage. If an l-value is provided to the -/// constructor, there is no difference in the number of copies made. However, -/// if an r-value is passed, the copy is avoided completely. -/// -/// For example, given: -/// \code -/// #include -/// -/// class A { -/// std::string S; -/// public: -/// A(const std::string &S) : S(S) {} -/// }; -/// \endcode -/// the code is transformed to: -/// \code -/// #include -/// -/// class A { -/// std::string S; -/// public: -/// A(std::string S) : S(std::move(S)) {} -/// }; -/// \endcode -class PassByValueTransform : public Transform { -public: - PassByValueTransform(const TransformOptions &Options) - : Transform("PassByValue", Options), Replacer(nullptr) {} - - /// \see Transform::apply(). - int apply(const clang::tooling::CompilationDatabase &Database, - const std::vector &SourcePaths) override; - -private: - /// \brief Setups the \c IncludeDirectives for the replacer. - bool handleBeginSource(clang::CompilerInstance &CI, - llvm::StringRef Filename) override; - - std::unique_ptr IncludeManager; - ConstructorParamReplacer *Replacer; -}; - -#endif // CLANG_MODERNIZE_PASS_BY_VALUE_H Index: clang-modernize/PassByValue/PassByValue.cpp =================================================================== --- clang-modernize/PassByValue/PassByValue.cpp +++ /dev/null @@ -1,78 +0,0 @@ -//===-- PassByValue.cpp ---------------------------------------------------===// -// -// 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 ReplaceAutoPtrTransform -/// class. -/// -//===----------------------------------------------------------------------===// - -#include "PassByValue.h" -#include "PassByValueActions.h" -#include "PassByValueMatchers.h" - -using namespace clang; -using namespace clang::tooling; -using namespace clang::ast_matchers; - -int PassByValueTransform::apply(const tooling::CompilationDatabase &Database, - const std::vector &SourcePaths) { - ClangTool Tool(Database, SourcePaths); - unsigned AcceptedChanges = 0; - unsigned RejectedChanges = 0; - MatchFinder Finder; - ConstructorParamReplacer Replacer(AcceptedChanges, RejectedChanges, - /*Owner=*/ *this); - - Finder.addMatcher(makePassByValueCtorParamMatcher(), &Replacer); - - // make the replacer available to handleBeginSource() - this->Replacer = &Replacer; - - if (Tool.run(createActionFactory(Finder).get())) { - llvm::errs() << "Error encountered during translation.\n"; - return 1; - } - - setAcceptedChanges(AcceptedChanges); - setRejectedChanges(RejectedChanges); - return 0; -} - -bool PassByValueTransform::handleBeginSource(CompilerInstance &CI, - llvm::StringRef Filename) { - assert(Replacer && "Replacer not set"); - IncludeManager.reset(new IncludeDirectives(CI)); - Replacer->setIncludeDirectives(IncludeManager.get()); - return Transform::handleBeginSource(CI, Filename); -} - -namespace { -struct PassByValueFactory : TransformFactory { - PassByValueFactory() { - // Based on the Replace Auto-Ptr Transform that is also using std::move(). - Since.Clang = Version(3, 0); - Since.Gcc = Version(4, 6); - Since.Icc = Version(13); - Since.Msvc = Version(11); - } - - Transform *createTransform(const TransformOptions &Opts) override { - return new PassByValueTransform(Opts); - } -}; -} // namespace - -// Register the factory using this statically initialized variable. -static TransformFactoryRegistry::Add -X("pass-by-value", "Pass parameters by value where possible"); - -// This anchor is used to force the linker to link in the generated object file -// and thus register the factory. -volatile int PassByValueTransformAnchorSource = 0; Index: clang-modernize/PassByValue/PassByValueActions.h =================================================================== --- clang-modernize/PassByValue/PassByValueActions.h +++ /dev/null @@ -1,74 +0,0 @@ -//===-- PassByValueActions.h ------------------------------------*- 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 ASTMatcher callback for the -/// PassByValue transform. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_PASS_BY_VALUE_ACTIONS_H -#define CLANG_MODERNIZE_PASS_BY_VALUE_ACTIONS_H - -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Tooling/Refactoring.h" - -class Transform; -class IncludeDirectives; - -/// \brief Callback that replaces const-ref parameters in constructors to use -/// pass-by-value semantic where applicable. -/// -/// Modifications done by the callback: -/// - \#include \ is added if necessary for the definition of -/// \c std::move() to be available. -/// - The parameter type is changed from const-ref to value-type. -/// - In the init-list the parameter is moved. -/// -/// Example: -/// \code -/// + #include -/// -/// class Foo(const std::string &S) { -/// public: -/// - Foo(const std::string &S) : S(S) {} -/// + Foo(std::string S) : S(std::move(S)) {} -/// -/// private: -/// std::string S; -/// }; -/// \endcode -/// -/// \note Since an include may be added by this matcher it's necessary to call -/// \c setIncludeDirectives() with an up-to-date \c IncludeDirectives. This is -/// typically done by overloading \c Transform::handleBeginSource(). -class ConstructorParamReplacer - : public clang::ast_matchers::MatchFinder::MatchCallback { -public: - ConstructorParamReplacer(unsigned &AcceptedChanges, unsigned &RejectedChanges, - Transform &Owner) - : AcceptedChanges(AcceptedChanges), RejectedChanges(RejectedChanges), - Owner(Owner), IncludeManager(nullptr) {} - - void setIncludeDirectives(IncludeDirectives *Includes) { - IncludeManager = Includes; - } - -private: - /// \brief Entry point to the callback called when matches are made. - void - run(const clang::ast_matchers::MatchFinder::MatchResult &Result) override; - - unsigned &AcceptedChanges; - unsigned &RejectedChanges; - Transform &Owner; - IncludeDirectives *IncludeManager; -}; - -#endif // CLANG_MODERNIZE_PASS_BY_VALUE_ACTIONS_H Index: clang-modernize/PassByValue/PassByValueActions.cpp =================================================================== --- clang-modernize/PassByValue/PassByValueActions.cpp +++ /dev/null @@ -1,175 +0,0 @@ -//===-- PassByValueActions.cpp --------------------------------------------===// -// -// 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 definition of the ASTMatcher callback for the -/// PassByValue transform. -/// -//===----------------------------------------------------------------------===// - -#include "PassByValueActions.h" -#include "Core/IncludeDirectives.h" -#include "Core/Transform.h" -#include "PassByValueMatchers.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/Lexer.h" - -using namespace clang; -using namespace clang::tooling; -using namespace clang::ast_matchers; - -namespace { -/// \brief \c clang::RecursiveASTVisitor that checks that the given -/// \c ParmVarDecl is used exactly one time. -/// -/// \see ExactlyOneUsageVisitor::hasExactlyOneUsageIn() -class ExactlyOneUsageVisitor - : public RecursiveASTVisitor { - friend class RecursiveASTVisitor; - -public: - ExactlyOneUsageVisitor(const ParmVarDecl *ParamDecl) : ParamDecl(ParamDecl) {} - - /// \brief Whether or not the parameter variable is referred only once in the - /// given constructor. - bool hasExactlyOneUsageIn(const CXXConstructorDecl *Ctor) { - Count = 0; - TraverseDecl(const_cast(Ctor)); - return Count == 1; - } - -private: - /// \brief Counts the number of references to a variable. - /// - /// Stops the AST traversal if more than one usage is found. - bool VisitDeclRefExpr(DeclRefExpr *D) { - if (const ParmVarDecl *To = llvm::dyn_cast(D->getDecl())) - if (To == ParamDecl) { - ++Count; - if (Count > 1) - // no need to look further, used more than once - return false; - } - return true; - } - - const ParmVarDecl *ParamDecl; - unsigned Count; -}; -} // end anonymous namespace - -/// \brief Whether or not \p ParamDecl is used exactly one time in \p Ctor. -/// -/// Checks both in the init-list and the body of the constructor. -static bool paramReferredExactlyOnce(const CXXConstructorDecl *Ctor, - const ParmVarDecl *ParamDecl) { - ExactlyOneUsageVisitor Visitor(ParamDecl); - return Visitor.hasExactlyOneUsageIn(Ctor); -} - -/// \brief Find all references to \p ParamDecl across all of the -/// redeclarations of \p Ctor. -static void -collectParamDecls(const CXXConstructorDecl *Ctor, const ParmVarDecl *ParamDecl, - llvm::SmallVectorImpl &Results) { - unsigned ParamIdx = ParamDecl->getFunctionScopeIndex(); - - for (CXXConstructorDecl::redecl_iterator I = Ctor->redecls_begin(), - E = Ctor->redecls_end(); - I != E; ++I) - Results.push_back((*I)->getParamDecl(ParamIdx)); -} - -void ConstructorParamReplacer::run(const MatchFinder::MatchResult &Result) { - assert(IncludeManager && "Include directives manager not set."); - SourceManager &SM = *Result.SourceManager; - const CXXConstructorDecl *Ctor = - Result.Nodes.getNodeAs(PassByValueCtorId); - const ParmVarDecl *ParamDecl = - Result.Nodes.getNodeAs(PassByValueParamId); - const CXXCtorInitializer *Initializer = - Result.Nodes.getNodeAs(PassByValueInitializerId); - assert(Ctor && ParamDecl && Initializer && "Bad Callback, missing node."); - - // Check this now to avoid unnecessary work. The param locations are checked - // later. - if (!Owner.isFileModifiable(SM, Initializer->getSourceLocation())) - return; - - // The parameter will be in an unspecified state after the move, so check if - // the parameter is used for anything else other than the copy. If so do not - // apply any changes. - if (!paramReferredExactlyOnce(Ctor, ParamDecl)) - return; - - llvm::SmallVector AllParamDecls; - collectParamDecls(Ctor, ParamDecl, AllParamDecls); - - // Generate all replacements for the params. - llvm::SmallVector ParamReplaces; - for (unsigned I = 0, E = AllParamDecls.size(); I != E; ++I) { - TypeLoc ParamTL = AllParamDecls[I]->getTypeSourceInfo()->getTypeLoc(); - ReferenceTypeLoc RefTL = ParamTL.getAs(); - SourceRange Range(AllParamDecls[I]->getLocStart(), ParamTL.getLocEnd()); - CharSourceRange CharRange = Lexer::makeFileCharRange( - CharSourceRange::getTokenRange(Range), SM, LangOptions()); - - // do not generate a replacement when the parameter is already a value - if (RefTL.isNull()) - continue; - - // transform non-value parameters (e.g: const-ref) to values - TypeLoc ValueTypeLoc = RefTL.getPointeeLoc(); - llvm::SmallString<32> ValueStr = Lexer::getSourceText( - CharSourceRange::getTokenRange(ValueTypeLoc.getSourceRange()), SM, - LangOptions()); - - // If it's impossible to change one of the parameter (e.g: comes from an - // unmodifiable header) quit the callback now, do not generate any changes. - if (CharRange.isInvalid() || ValueStr.empty() || - !Owner.isFileModifiable(SM, CharRange.getBegin())) - return; - - // 'const Foo ¶m' -> 'Foo param' - // ~~~~~~~~~~~ ~~~^ - ValueStr += ' '; - ParamReplaces.push_back(Replacement(SM, CharRange, ValueStr)); - } - - // Reject the changes if the the risk level is not acceptable. - if (!Owner.isAcceptableRiskLevel(RL_Reasonable)) { - RejectedChanges++; - return; - } - - // if needed, include in the file that uses std::move() - const FileEntry *STDMoveFile = - SM.getFileEntryForID(SM.getFileID(Initializer->getLParenLoc())); - const tooling::Replacement &IncludeReplace = - IncludeManager->addAngledInclude(STDMoveFile, "utility"); - if (IncludeReplace.isApplicable()) { - Owner.addReplacementForCurrentTU(IncludeReplace); - AcceptedChanges++; - } - - // const-ref params becomes values (const Foo & -> Foo) - for (const Replacement *I = ParamReplaces.begin(), *E = ParamReplaces.end(); - I != E; ++I) { - Owner.addReplacementForCurrentTU(*I); - } - AcceptedChanges += ParamReplaces.size(); - - // move the value in the init-list - Owner.addReplacementForCurrentTU(Replacement( - SM, Initializer->getLParenLoc().getLocWithOffset(1), 0, "std::move(")); - Owner.addReplacementForCurrentTU( - Replacement(SM, Initializer->getRParenLoc(), 0, ")")); - AcceptedChanges += 2; -} Index: clang-modernize/PassByValue/PassByValueMatchers.h =================================================================== --- clang-modernize/PassByValue/PassByValueMatchers.h +++ /dev/null @@ -1,44 +0,0 @@ -//===-- PassByValueMatchers.h -----------------------------------*- 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 CLANG_MODERNIZE_REPLACE_AUTO_PTR_MATCHERS_H -#define CLANG_MODERNIZE_REPLACE_AUTO_PTR_MATCHERS_H - -#include "clang/ASTMatchers/ASTMatchers.h" - -/// \name Names to bind with matched expressions -/// @{ -extern const char *PassByValueCtorId; -extern const char *PassByValueParamId; -extern const char *PassByValueInitializerId; -/// @} - -/// \brief Creates a matcher that finds class field initializations that can -/// benefit from using the move constructor. -/// -/// \code -/// class A { -/// public: -/// A(const std::string &S) : S(S) {} -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PassByValueCtorId -/// ~~~~~~~~~~~~~~~~~~~~ PassByValueParamId -/// ~ PassByValueInitializerId -/// private: -/// std::string S; -/// }; -/// \endcode -clang::ast_matchers::DeclarationMatcher makePassByValueCtorParamMatcher(); - -#endif // CLANG_MODERNIZE_REPLACE_AUTO_PTR_MATCHERS_H Index: clang-modernize/PassByValue/PassByValueMatchers.cpp =================================================================== --- clang-modernize/PassByValue/PassByValueMatchers.cpp +++ /dev/null @@ -1,81 +0,0 @@ -//===-- PassByValueMatchers.cpp -------------------------------------------===// -// -// 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 definitions for matcher-generating functions -/// and names for bound nodes found by AST matchers. -/// -//===----------------------------------------------------------------------===// - -#include "PassByValueMatchers.h" - -const char *PassByValueCtorId = "Ctor"; -const char *PassByValueParamId = "Param"; -const char *PassByValueInitializerId = "Initializer"; - -namespace clang { -namespace ast_matchers { - -/// \brief Matches move constructible classes. -/// -/// Given -/// \code -/// // POD types are trivially move constructible -/// struct Foo { int a; }; -/// -/// struct Bar { -/// Bar(Bar &&) = deleted; -/// int a; -/// }; -/// \endcode -/// recordDecl(isMoveConstructible()) -/// matches "Foo". -AST_MATCHER(CXXRecordDecl, isMoveConstructible) { - for (CXXRecordDecl::ctor_iterator I = Node.ctor_begin(), E = Node.ctor_end(); I != E; ++I) { - const CXXConstructorDecl *Ctor = *I; - if (Ctor->isMoveConstructor() && !Ctor->isDeleted()) - return true; - } - return false; -} -} // namespace ast_matchers -} // namespace clang - -using namespace clang; -using namespace clang::ast_matchers; - -static TypeMatcher constRefType() { - return lValueReferenceType(pointee(isConstQualified())); -} - -static TypeMatcher nonConstValueType() { - return qualType(unless(anyOf(referenceType(), isConstQualified()))); -} - -DeclarationMatcher makePassByValueCtorParamMatcher() { - return cxxConstructorDecl( - forEachConstructorInitializer(cxxCtorInitializer( - // Clang builds a CXXConstructExpr only when it knowns which - // constructor will be called. In dependent contexts a ParenListExpr - // is generated instead of a CXXConstructExpr, filtering out templates - // automatically for us. - withInitializer(cxxConstructExpr( - has(declRefExpr(to( - parmVarDecl(hasType(qualType( - // match only const-ref or a non-const value - // parameters, rvalues and const-values - // shouldn't be modified. - anyOf(constRefType(), nonConstValueType())))) - .bind(PassByValueParamId)))), - hasDeclaration(cxxConstructorDecl( - isCopyConstructor(), unless(isDeleted()), - hasDeclContext(cxxRecordDecl(isMoveConstructible()))))))) - .bind(PassByValueInitializerId))) - .bind(PassByValueCtorId); -} Index: clang-modernize/ReplaceAutoPtr/ReplaceAutoPtr.h =================================================================== --- clang-modernize/ReplaceAutoPtr/ReplaceAutoPtr.h +++ /dev/null @@ -1,54 +0,0 @@ -//===-- ReplaceAutoPtr.h ------------ std::auto_ptr replacement -*- 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 declaration of the ReplaceAutoPtrTransform -/// class. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_REPLACE_AUTO_PTR_H -#define CLANG_MODERNIZE_REPLACE_AUTO_PTR_H - -#include "Core/Transform.h" -#include "llvm/Support/Compiler.h" - -/// \brief Subclass of Transform that transforms the deprecated \c std::auto_ptr -/// into the C++11 \c std::unique_ptr. -/// -/// Note that both the \c std::auto_ptr type and the transfer of ownership are -/// transformed. \c std::auto_ptr provides two ways to transfer the ownership, -/// the copy-constructor and the assignment operator. Unlike most classes theses -/// operations do not 'copy' the resource but they 'steal' it. -/// \c std::unique_ptr uses move semantics instead, which makes the intent of -/// transferring the resource explicit. This difference between the two smart -/// pointers requires to wrap the copy-ctor and assign-operator with -/// \c std::move(). -/// -/// For example, given: -/// \code -/// std::auto_ptr i, j; -/// i = j; -/// \endcode -/// the code is transformed to: -/// \code -/// std::unique_ptr i, j; -/// i = std::move(j); -/// \endcode -class ReplaceAutoPtrTransform : public Transform { -public: - ReplaceAutoPtrTransform(const TransformOptions &Options) - : Transform("ReplaceAutoPtr", Options) {} - - /// \see Transform::run(). - int apply(const clang::tooling::CompilationDatabase &Database, - const std::vector &SourcePaths) override; -}; - -#endif // CLANG_MODERNIZE_REPLACE_AUTO_PTR_H Index: clang-modernize/ReplaceAutoPtr/ReplaceAutoPtr.cpp =================================================================== --- clang-modernize/ReplaceAutoPtr/ReplaceAutoPtr.cpp +++ /dev/null @@ -1,67 +0,0 @@ -//===-- ReplaceAutoPtr.cpp ---------- std::auto_ptr replacement -----------===// -// -// 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 ReplaceAutoPtrTransform -/// class. -/// -//===----------------------------------------------------------------------===// - -#include "ReplaceAutoPtr.h" -#include "ReplaceAutoPtrActions.h" -#include "ReplaceAutoPtrMatchers.h" - -using namespace clang; -using namespace clang::tooling; -using namespace clang::ast_matchers; - -int -ReplaceAutoPtrTransform::apply(const CompilationDatabase &Database, - const std::vector &SourcePaths) { - ClangTool Tool(Database, SourcePaths); - unsigned AcceptedChanges = 0; - MatchFinder Finder; - AutoPtrReplacer Replacer(AcceptedChanges, /*Owner=*/ *this); - OwnershipTransferFixer Fixer(AcceptedChanges, /*Owner=*/ *this); - - Finder.addMatcher(makeAutoPtrTypeLocMatcher(), &Replacer); - Finder.addMatcher(makeAutoPtrUsingDeclMatcher(), &Replacer); - Finder.addMatcher(makeTransferOwnershipExprMatcher(), &Fixer); - - if (Tool.run(createActionFactory(Finder).get())) { - llvm::errs() << "Error encountered during translation.\n"; - return 1; - } - - setAcceptedChanges(AcceptedChanges); - - return 0; -} - -struct ReplaceAutoPtrFactory : TransformFactory { - ReplaceAutoPtrFactory() { - Since.Clang = Version(3, 0); - Since.Gcc = Version(4, 6); - Since.Icc = Version(13); - Since.Msvc = Version(11); - } - - Transform *createTransform(const TransformOptions &Opts) override { - return new ReplaceAutoPtrTransform(Opts); - } -}; - -// Register the factory using this statically initialized variable. -static TransformFactoryRegistry::Add -X("replace-auto_ptr", "Replace std::auto_ptr (deprecated) by std::unique_ptr" - " (EXPERIMENTAL)"); - -// This anchor is used to force the linker to link in the generated object file -// and thus register the factory. -volatile int ReplaceAutoPtrTransformAnchorSource = 0; Index: clang-modernize/ReplaceAutoPtr/ReplaceAutoPtrActions.h =================================================================== --- clang-modernize/ReplaceAutoPtr/ReplaceAutoPtrActions.h +++ /dev/null @@ -1,99 +0,0 @@ -//===-- ReplaceAutoPtrActions.h ----- std::auto_ptr replacement -*- 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 ASTMatcher callback for the -/// ReplaceAutoPtr transform. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_REPLACE_AUTO_PTR_ACTIONS_H -#define CLANG_MODERNIZE_REPLACE_AUTO_PTR_ACTIONS_H - -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Tooling/Refactoring.h" - -class Transform; - -/// \brief The callback to be used when replacing the \c std::auto_ptr types and -/// using declarations. -class AutoPtrReplacer : public clang::ast_matchers::MatchFinder::MatchCallback { -public: - AutoPtrReplacer(unsigned &AcceptedChanges, Transform &Owner) - : AcceptedChanges(AcceptedChanges), Owner(Owner) {} - - /// \brief Entry point to the callback called when matches are made. - void - run(const clang::ast_matchers::MatchFinder::MatchResult &Result) override; - -private: - /// \brief Locates the \c auto_ptr token when it is referred by a \c TypeLoc. - /// - /// \code - /// std::auto_ptr i; - /// ^~~~~~~~~~~~~ - /// \endcode - /// The caret represents the location returned and the tildes cover the - /// parameter \p AutoPtrTypeLoc. - /// - /// \return An invalid \c SourceLocation if not found, otherwise the location - /// of the beginning of the \c auto_ptr token. - clang::SourceLocation locateFromTypeLoc(clang::TypeLoc AutoPtrTypeLoc, - const clang::SourceManager &SM); - - /// \brief Locates the \c auto_ptr token in using declarations. - /// - /// \code - /// using std::auto_ptr; - /// ^ - /// \endcode - /// The caret represents the location returned. - /// - /// \return An invalid \c SourceLocation if not found, otherwise the - /// location of the beginning of the \c auto_ptr token. - clang::SourceLocation - locateFromUsingDecl(const clang::UsingDecl *UsingAutoPtrDecl, - const clang::SourceManager &SM); - -private: - unsigned &AcceptedChanges; - Transform &Owner; -}; - -/// \brief The callback to be used to fix the ownership transfers of -/// \c auto_ptr, -/// -/// \c unique_ptr requires to use \c std::move() explicitly in order to transfer -/// the ownership. -/// -/// Given: -/// \code -/// std::auto_ptr a, b; -/// a = b; -/// \endcode -/// The last statement is transformed to: -/// \code -/// a = std::move(b); -/// \endcode -class OwnershipTransferFixer - : public clang::ast_matchers::MatchFinder::MatchCallback { -public: - OwnershipTransferFixer(unsigned &AcceptedChanges, Transform &Owner) - : AcceptedChanges(AcceptedChanges), Owner(Owner) {} - - /// \brief Entry point to the callback called when matches are made. - void - run(const clang::ast_matchers::MatchFinder::MatchResult &Result) override; - -private: - unsigned &AcceptedChanges; - Transform &Owner; -}; - -#endif // CLANG_MODERNIZE_REPLACE_AUTO_PTR_ACTIONS_H Index: clang-modernize/ReplaceAutoPtr/ReplaceAutoPtrActions.cpp =================================================================== --- clang-modernize/ReplaceAutoPtr/ReplaceAutoPtrActions.cpp +++ /dev/null @@ -1,107 +0,0 @@ -//===-- ReplaceAutoPtrActions.cpp --- std::auto_ptr replacement -----------===// -// -// 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 definition of the ASTMatcher callback for the -/// ReplaceAutoPtr transform. -/// -//===----------------------------------------------------------------------===// - -#include "ReplaceAutoPtrActions.h" -#include "Core/Transform.h" -#include "ReplaceAutoPtrMatchers.h" -#include "clang/AST/ASTContext.h" -#include "clang/Lex/Lexer.h" - -using namespace clang; -using namespace clang::tooling; -using namespace clang::ast_matchers; - -namespace { - -/// \brief Verifies that the token at \p BeginningOfToken is 'auto_ptr'. -bool checkTokenIsAutoPtr(clang::SourceLocation BeginningOfToken, - const clang::SourceManager &SM, - const clang::LangOptions &LangOptions) { - llvm::SmallVector Buffer; - bool Invalid = false; - llvm::StringRef Res = - Lexer::getSpelling(BeginningOfToken, Buffer, SM, LangOptions, &Invalid); - - if (Invalid) - return false; - - return Res == "auto_ptr"; -} - -} // end anonymous namespace - -void AutoPtrReplacer::run(const MatchFinder::MatchResult &Result) { - SourceManager &SM = *Result.SourceManager; - SourceLocation IdentifierLoc; - - if (const TypeLoc *TL = Result.Nodes.getNodeAs(AutoPtrTokenId)) { - IdentifierLoc = locateFromTypeLoc(*TL, SM); - } else { - const UsingDecl *D = Result.Nodes.getNodeAs(AutoPtrTokenId); - assert(D && "Bad Callback. No node provided."); - IdentifierLoc = locateFromUsingDecl(D, SM); - } - - if (IdentifierLoc.isMacroID()) - IdentifierLoc = SM.getSpellingLoc(IdentifierLoc); - - if (!Owner.isFileModifiable(SM, IdentifierLoc)) - return; - - // make sure that only the 'auto_ptr' token is replaced and not the template - // aliases [temp.alias] - if (!checkTokenIsAutoPtr(IdentifierLoc, SM, LangOptions())) - return; - - Owner.addReplacementForCurrentTU( - Replacement(SM, IdentifierLoc, strlen("auto_ptr"), "unique_ptr")); - ++AcceptedChanges; -} - -SourceLocation AutoPtrReplacer::locateFromTypeLoc(TypeLoc AutoPtrTypeLoc, - const SourceManager &SM) { - TemplateSpecializationTypeLoc TL = - AutoPtrTypeLoc.getAs(); - if (TL.isNull()) - return SourceLocation(); - - return TL.getTemplateNameLoc(); -} - -SourceLocation -AutoPtrReplacer::locateFromUsingDecl(const UsingDecl *UsingAutoPtrDecl, - const SourceManager &SM) { - return UsingAutoPtrDecl->getNameInfo().getBeginLoc(); -} - -void OwnershipTransferFixer::run(const MatchFinder::MatchResult &Result) { - SourceManager &SM = *Result.SourceManager; - const Expr *E = Result.Nodes.getNodeAs(AutoPtrOwnershipTransferId); - assert(E && "Bad Callback. No node provided."); - - CharSourceRange Range = Lexer::makeFileCharRange( - CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOptions()); - - if (Range.isInvalid()) - return; - - if (!Owner.isFileModifiable(SM, Range.getBegin())) - return; - - Owner.addReplacementForCurrentTU( - Replacement(SM, Range.getBegin(), 0, "std::move(")); - Owner.addReplacementForCurrentTU(Replacement(SM, Range.getEnd(), 0, ")")); - AcceptedChanges += 2; -} Index: clang-modernize/ReplaceAutoPtr/ReplaceAutoPtrMatchers.h =================================================================== --- clang-modernize/ReplaceAutoPtr/ReplaceAutoPtrMatchers.h +++ /dev/null @@ -1,64 +0,0 @@ -//===-- ReplaceAutoPtrMatchers.h ---- std::auto_ptr replacement -*- 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 CLANG_MODERNIZE_REPLACE_AUTO_PTR_MATCHERS_H -#define CLANG_MODERNIZE_REPLACE_AUTO_PTR_MATCHERS_H - -#include "clang/ASTMatchers/ASTMatchers.h" - -/// Names to bind with matched expressions. -extern const char *AutoPtrTokenId; -extern const char *AutoPtrOwnershipTransferId; - -/// \brief Creates a matcher that finds the locations of types referring to the -/// \c std::auto_ptr() type. -/// -/// \code -/// std::auto_ptr a; -/// ^~~~~~~~~~~~~ -/// -/// typedef std::auto_ptr int_ptr_t; -/// ^~~~~~~~~~~~~ -/// -/// std::auto_ptr fn(std::auto_ptr); -/// ^~~~~~~~~~~~~ ^~~~~~~~~~~~~ -/// -/// -/// \endcode -clang::ast_matchers::TypeLocMatcher makeAutoPtrTypeLocMatcher(); - -/// \brief Creates a matcher that finds the using declarations referring to -/// \c std::auto_ptr. -/// -/// \code -/// using std::auto_ptr; -/// ^~~~~~~~~~~~~~~~~~~ -/// \endcode -clang::ast_matchers::DeclarationMatcher makeAutoPtrUsingDeclMatcher(); - -/// \brief Creates a matcher that finds the \c std::auto_ptr copy-ctor and -/// assign-operator expressions. -/// -/// \c AutoPtrOwnershipTransferId is assigned to the argument of the expression, -/// this is the part that has to be wrapped by \c std::move(). -/// -/// \code -/// std::auto_ptr i, j; -/// i = j; -/// ~~~~^ -/// \endcode -clang::ast_matchers::StatementMatcher makeTransferOwnershipExprMatcher(); - -#endif // CLANG_MODERNIZE_REPLACE_AUTO_PTR_MATCHERS_H Index: clang-modernize/ReplaceAutoPtr/ReplaceAutoPtrMatchers.cpp =================================================================== --- clang-modernize/ReplaceAutoPtr/ReplaceAutoPtrMatchers.cpp +++ /dev/null @@ -1,81 +0,0 @@ -//===-- ReplaceAutoPtrMatchers.cpp -- std::auto_ptr replacement -----------===// -// -// 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 definitions for matcher-generating functions -/// and names for bound nodes found by AST matchers. -/// -//===----------------------------------------------------------------------===// - -#include "ReplaceAutoPtrMatchers.h" -#include "Core/CustomMatchers.h" - -const char *AutoPtrTokenId = "AutoPtrTokenId"; -const char *AutoPtrOwnershipTransferId = "AutoPtrOwnershipTransferId"; - -namespace clang { -namespace ast_matchers { - -/// \brief Matches expressions that are lvalues. -/// -/// In the following example, a[0] matches expr(isLValue()): -/// \code -/// std::string a[2]; -/// std::string b; -/// b = a[0]; -/// b = "this string won't match"; -/// \endcode -AST_MATCHER(Expr, isLValue) { - return Node.getValueKind() == VK_LValue; -} - -} // end namespace ast_matchers -} // end namespace clang - -using namespace clang; -using namespace clang::ast_matchers; - -// shared matchers -static DeclarationMatcher AutoPtrDecl = - recordDecl(hasName("auto_ptr"), isFromStdNamespace()); - -static TypeMatcher AutoPtrType = qualType(hasDeclaration(AutoPtrDecl)); - -// Matcher that finds expressions that are candidates to be wrapped with -// 'std::move()'. -// -// Binds the id \c AutoPtrOwnershipTransferId to the expression. -static StatementMatcher MovableArgumentMatcher = expr( - allOf(isLValue(), hasType(AutoPtrType))).bind(AutoPtrOwnershipTransferId); - -TypeLocMatcher makeAutoPtrTypeLocMatcher() { - // skip elaboratedType() as the named type will match soon thereafter. - return typeLoc(loc(qualType(AutoPtrType, unless(elaboratedType())))) - .bind(AutoPtrTokenId); -} - -DeclarationMatcher makeAutoPtrUsingDeclMatcher() { - return usingDecl(hasAnyUsingShadowDecl(hasTargetDecl( - allOf(hasName("auto_ptr"), isFromStdNamespace())))).bind(AutoPtrTokenId); -} - -StatementMatcher makeTransferOwnershipExprMatcher() { - StatementMatcher assignOperator = - cxxOperatorCallExpr(allOf( - hasOverloadedOperatorName("="), - callee(cxxMethodDecl(ofClass(AutoPtrDecl))), - hasArgument(1, MovableArgumentMatcher))); - - StatementMatcher copyCtor = - cxxConstructExpr(allOf(hasType(AutoPtrType), - argumentCountIs(1), - hasArgument(0, MovableArgumentMatcher))); - - return anyOf(assignOperator, copyCtor); -} Index: clang-modernize/UseAuto/UseAuto.h =================================================================== --- clang-modernize/UseAuto/UseAuto.h +++ /dev/null @@ -1,41 +0,0 @@ -//===-- 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 CLANG_MODERNIZE_USE_AUTO_H -#define CLANG_MODERNIZE_USE_AUTO_H - -#include "Core/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: - UseAutoTransform(const TransformOptions &Options) - : Transform("UseAuto", Options) {} - - /// \see Transform::run(). - int apply(const clang::tooling::CompilationDatabase &Database, - const std::vector &SourcePaths) override; -}; - -#endif // CLANG_MODERNIZE_USE_AUTO_H Index: clang-modernize/UseAuto/UseAuto.cpp =================================================================== --- clang-modernize/UseAuto/UseAuto.cpp +++ /dev/null @@ -1,70 +0,0 @@ -//===-- 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 clang::tooling::CompilationDatabase &Database, - const std::vector &SourcePaths) { - ClangTool UseAutoTool(Database, SourcePaths); - - unsigned AcceptedChanges = 0; - - MatchFinder Finder; - ReplacementsVec Replaces; - IteratorReplacer ReplaceIterators(AcceptedChanges, Options().MaxRiskLevel, - /*Owner=*/ *this); - NewReplacer ReplaceNew(AcceptedChanges, Options().MaxRiskLevel, - /*Owner=*/ *this); - - Finder.addMatcher(makeIteratorDeclMatcher(), &ReplaceIterators); - Finder.addMatcher(makeDeclWithNewMatcher(), &ReplaceNew); - - if (int Result = UseAutoTool.run(createActionFactory(Finder).get())) { - llvm::errs() << "Error encountered during translation.\n"; - return Result; - } - - setAcceptedChanges(AcceptedChanges); - - return 0; -} - -namespace { -struct UseAutoFactory : TransformFactory { - UseAutoFactory() { - Since.Clang = Version(2, 9); - Since.Gcc = Version(4, 4); - Since.Icc = Version(12); - Since.Msvc = Version(10); - } - - Transform *createTransform(const TransformOptions &Opts) override { - return new UseAutoTransform(Opts); - } -}; -} // namespace - -// Register the factory using this statically initialized variable. -static TransformFactoryRegistry::Add -X("use-auto", "Use of 'auto' type specifier"); - -// This anchor is used to force the linker to link in the generated object file -// and thus register the factory. -volatile int UseAutoTransformAnchorSource = 0; Index: clang-modernize/UseAuto/UseAutoActions.h =================================================================== --- clang-modernize/UseAuto/UseAutoActions.h +++ /dev/null @@ -1,56 +0,0 @@ -//===-- 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 declarations for callbacks used by the -/// UseAuto transform. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_USE_AUTO_ACTIONS_H -#define CLANG_MODERNIZE_USE_AUTO_ACTIONS_H - -#include "Core/Transform.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Tooling/Refactoring.h" - -/// \brief The callback to be used when replacing type specifiers of variable -/// declarations that are iterators. -class IteratorReplacer - : public clang::ast_matchers::MatchFinder::MatchCallback { -public: - IteratorReplacer(unsigned &AcceptedChanges, RiskLevel, Transform &Owner) - : AcceptedChanges(AcceptedChanges), Owner(Owner) {} - - /// \brief Entry point to the callback called when matches are made. - void - run(const clang::ast_matchers::MatchFinder::MatchResult &Result) override; - -private: - unsigned &AcceptedChanges; - Transform &Owner; -}; - -/// \brief The callback used when replacing type specifiers of variable -/// declarations initialized by a C++ new expression. -class NewReplacer : public clang::ast_matchers::MatchFinder::MatchCallback { -public: - NewReplacer(unsigned &AcceptedChanges, RiskLevel, Transform &Owner) - : AcceptedChanges(AcceptedChanges), Owner(Owner) {} - - /// \brief Entry point to the callback called when matches are made. - void - run(const clang::ast_matchers::MatchFinder::MatchResult &Result) override; - -private: - unsigned &AcceptedChanges; - Transform &Owner; -}; - -#endif // CLANG_MODERNIZE_USE_AUTO_ACTIONS_H Index: clang-modernize/UseAuto/UseAutoActions.cpp =================================================================== --- clang-modernize/UseAuto/UseAutoActions.cpp +++ /dev/null @@ -1,147 +0,0 @@ -//===-- 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 callbacks for the UseAuto -/// transform. -/// -//===----------------------------------------------------------------------===// - -#include "UseAutoActions.h" -#include "UseAutoMatchers.h" -#include "clang/AST/ASTContext.h" - -using namespace clang::ast_matchers; -using namespace clang::tooling; -using namespace clang; - -void IteratorReplacer::run(const MatchFinder::MatchResult &Result) { - const DeclStmt *D = Result.Nodes.getNodeAs(IteratorDeclStmtId); - assert(D && "Bad Callback. No node provided"); - - SourceManager &SM = *Result.SourceManager; - if (!Owner.isFileModifiable(SM, D->getLocStart())) - return; - - for (clang::DeclStmt::const_decl_iterator DI = D->decl_begin(), - DE = D->decl_end(); - DI != DE; ++DI) { - const VarDecl *V = cast(*DI); - - const Expr *ExprInit = V->getInit(); - - // Skip expressions with cleanups from the initializer expression. - if (const ExprWithCleanups *E = dyn_cast(ExprInit)) - ExprInit = E->getSubExpr(); - - const CXXConstructExpr *Construct = cast(ExprInit); - - 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(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(V->getType(), E->getType())) - return; - } - // Get the type location using the first declartion. - const VarDecl *V = cast(*D->decl_begin()); - TypeLoc TL = V->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); - Owner.addReplacementForCurrentTU(tooling::Replacement(SM, Range, "auto")); - ++AcceptedChanges; -} - -void NewReplacer::run(const MatchFinder::MatchResult &Result) { - const DeclStmt *D = Result.Nodes.getNodeAs(DeclWithNewId); - assert(D && "Bad Callback. No node provided"); - - SourceManager &SM = *Result.SourceManager; - if (!Owner.isFileModifiable(SM, D->getLocStart())) - return; - - const VarDecl *FirstDecl = cast(*D->decl_begin()); - // Ensure that there is at least one VarDecl within de DeclStmt. - assert(FirstDecl && "No VarDecl provided"); - - const QualType FirstDeclType = FirstDecl->getType().getCanonicalType(); - - std::vector StarLocations; - for (clang::DeclStmt::const_decl_iterator DI = D->decl_begin(), - DE = D->decl_end(); - DI != DE; ++DI) { - - const VarDecl *V = cast(*DI); - // Ensure that every DeclStmt child is a VarDecl. - assert(V && "No VarDecl provided"); - - const CXXNewExpr *NewExpr = - cast(V->getInit()->IgnoreParenImpCasts()); - // Ensure that every VarDecl has a CXXNewExpr initializer. - assert(NewExpr && "No CXXNewExpr provided"); - - // If VarDecl and Initializer have mismatching unqualified types. - if (!Result.Context->hasSameUnqualifiedType(V->getType(), - NewExpr->getType())) - return; - - // Remove explicitly written '*' from declarations where there's more than - // one declaration in the declaration list. - if (DI == D->decl_begin()) - continue; - - // All subsequent delcarations should match the same non-decorated type. - if (FirstDeclType != V->getType().getCanonicalType()) - return; - - PointerTypeLoc Q = - V->getTypeSourceInfo()->getTypeLoc().getAs(); - while (!Q.isNull()) { - StarLocations.push_back(Q.getStarLoc()); - Q = Q.getNextTypeLoc().getAs(); - } - } - - // Remove '*' from declarations using the saved star locations. - for (std::vector::iterator I = StarLocations.begin(), - E = StarLocations.end(); - I != E; ++I) { - Owner.addReplacementForCurrentTU(tooling::Replacement(SM, *I, 1, "")); - } - - // FIXME: There is, however, one case we can address: when the VarDecl - // pointee is the same as the initializer, just more CV-qualified. However, - // TypeLoc information is not reliable where CV qualifiers are concerned so - // we can't do anything about this case for now. - CharSourceRange Range( - FirstDecl->getTypeSourceInfo()->getTypeLoc().getSourceRange(), true); - // Space after 'auto' to handle cases where the '*' in the pointer type - // is next to the identifier. This avoids changing 'int *p' into 'autop'. - Owner.addReplacementForCurrentTU(tooling::Replacement(SM, Range, "auto ")); - ++AcceptedChanges; -} Index: clang-modernize/UseAuto/UseAutoMatchers.h =================================================================== --- clang-modernize/UseAuto/UseAutoMatchers.h +++ /dev/null @@ -1,34 +0,0 @@ -//===-- 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 CLANG_MODERNIZE_USE_AUTO_MATCHERS_H -#define CLANG_MODERNIZE_USE_AUTO_MATCHERS_H - -#include "clang/ASTMatchers/ASTMatchers.h" - -extern const char *IteratorDeclStmtId; -extern const char *DeclWithNewId; -extern const char *NewExprId; - -/// \brief Create a matcher that matches declaration staments that have -/// variable declarations where the type is an iterator for an std container -/// and has an explicit initializer of the same type. -clang::ast_matchers::StatementMatcher makeIteratorDeclMatcher(); - -/// \brief Create a matcher that matches variable declarations that are -/// initialized by a C++ new expression. -clang::ast_matchers::StatementMatcher makeDeclWithNewMatcher(); - -#endif // CLANG_MODERNIZE_USE_AUTO_MATCHERS_H Index: clang-modernize/UseAuto/UseAutoMatchers.cpp =================================================================== --- clang-modernize/UseAuto/UseAutoMatchers.cpp +++ /dev/null @@ -1,280 +0,0 @@ -//===-- 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(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, 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 *const 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 *const 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(cxxNewExpr()) - )), - // 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); -} Index: clang-modernize/UseNullptr/NullptrActions.h =================================================================== --- clang-modernize/UseNullptr/NullptrActions.h +++ /dev/null @@ -1,43 +0,0 @@ -//===-- UseNullptr/NullptrActions.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 NullptrFixer class which -/// is used as a ASTMatcher callback. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_NULLPTR_ACTIONS_H -#define CLANG_MODERNIZE_NULLPTR_ACTIONS_H - -#include "Core/Transform.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Tooling/Refactoring.h" - -// The type for user-defined macro names that behave like NULL -typedef llvm::SmallVector UserMacroNames; - -/// \brief The callback to be used for nullptr migration matchers. -/// -class NullptrFixer : public clang::ast_matchers::MatchFinder::MatchCallback { -public: - NullptrFixer(unsigned &AcceptedChanges, - llvm::ArrayRef UserMacros, Transform &Owner); - - /// \brief Entry point to the callback called when matches are made. - void - run(const clang::ast_matchers::MatchFinder::MatchResult &Result) override; - -private: - unsigned &AcceptedChanges; - UserMacroNames UserNullMacros; - Transform &Owner; -}; - -#endif // CLANG_MODERNIZE_NULLPTR_ACTIONS_H Index: clang-modernize/UseNullptr/NullptrActions.cpp =================================================================== --- clang-modernize/UseNullptr/NullptrActions.cpp +++ /dev/null @@ -1,441 +0,0 @@ -//===-- UseNullptr/NullptrActions.cpp - Matcher callback ------------------===// -// -// 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 definition of the NullptrFixer class which is -/// used as an ASTMatcher callback. Also within this file is a helper AST -/// visitor class used to identify sequences of explicit casts. -/// -//===----------------------------------------------------------------------===// - -#include "NullptrActions.h" -#include "NullptrMatchers.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/Basic/CharInfo.h" -#include "clang/Lex/Lexer.h" - -using namespace clang::ast_matchers; -using namespace clang::tooling; -using namespace clang; -namespace cl = llvm::cl; - -namespace { - -const char *NullMacroName = "NULL"; - -bool isReplaceableRange(SourceLocation StartLoc, SourceLocation EndLoc, - const SourceManager &SM, const Transform &Owner) { - return SM.isWrittenInSameFile(StartLoc, EndLoc) && - Owner.isFileModifiable(SM, StartLoc); -} - -/// \brief Replaces the provided range with the text "nullptr", but only if -/// the start and end location are both in main file. -/// Returns true if and only if a replacement was made. -void ReplaceWithNullptr(Transform &Owner, SourceManager &SM, - SourceLocation StartLoc, SourceLocation EndLoc) { - CharSourceRange Range(SourceRange(StartLoc, EndLoc), true); - // Add a space if nullptr follows an alphanumeric character. This happens - // whenever there is an c-style explicit cast to nullptr not surrounded by - // parentheses and right beside a return statement. - SourceLocation PreviousLocation = StartLoc.getLocWithOffset(-1); - if (isAlphanumeric(*FullSourceLoc(PreviousLocation, SM).getCharacterData())) - Owner.addReplacementForCurrentTU( - tooling::Replacement(SM, Range, " nullptr")); - else - Owner.addReplacementForCurrentTU( - tooling::Replacement(SM, Range, "nullptr")); -} - -/// \brief Returns the name of the outermost macro. -/// -/// Given -/// \code -/// #define MY_NULL NULL -/// \endcode -/// If \p Loc points to NULL, this function will return the name MY_NULL. -llvm::StringRef GetOutermostMacroName( - SourceLocation Loc, const SourceManager &SM, const LangOptions &LO) { - assert(Loc.isMacroID()); - SourceLocation OutermostMacroLoc; - - while (Loc.isMacroID()) { - OutermostMacroLoc = Loc; - Loc = SM.getImmediateMacroCallerLoc(Loc); - } - - return clang::Lexer::getImmediateMacroName(OutermostMacroLoc, SM, LO); -} - -/// \brief RecursiveASTVisitor for ensuring all nodes rooted at a given AST -/// subtree that have file-level source locations corresponding to a macro -/// argument have implicit NullTo(Member)Pointer nodes as ancestors. -class MacroArgUsageVisitor : public RecursiveASTVisitor { -public: - MacroArgUsageVisitor(SourceLocation CastLoc, const SourceManager &SM) - : CastLoc(CastLoc), SM(SM), Visited(false), CastFound(false), - InvalidFound(false) { - assert(CastLoc.isFileID()); - } - - bool TraverseStmt(Stmt *S) { - bool VisitedPreviously = Visited; - - if (!RecursiveASTVisitor::TraverseStmt(S)) - return false; - - // The point at which VisitedPreviously is false and Visited is true is the - // root of a subtree containing nodes whose locations match CastLoc. It's - // at this point we test that the Implicit NullTo(Member)Pointer cast was - // found or not. - if (!VisitedPreviously) { - if (Visited && !CastFound) { - // Found nodes with matching SourceLocations but didn't come across a - // cast. This is an invalid macro arg use. Can stop traversal - // completely now. - InvalidFound = true; - return false; - } - // Reset state as we unwind back up the tree. - CastFound = false; - Visited = false; - } - return true; - } - - bool VisitStmt(Stmt *S) { - if (SM.getFileLoc(S->getLocStart()) != CastLoc) - return true; - Visited = true; - - const ImplicitCastExpr *Cast = dyn_cast(S); - if (Cast && (Cast->getCastKind() == CK_NullToPointer || - Cast->getCastKind() == CK_NullToMemberPointer)) - CastFound = true; - - return true; - } - - bool foundInvalid() const { return InvalidFound; } - -private: - SourceLocation CastLoc; - const SourceManager &SM; - - bool Visited; - bool CastFound; - bool InvalidFound; -}; - -/// \brief Looks for implicit casts as well as sequences of 0 or more explicit -/// casts with an implicit null-to-pointer cast within. -/// -/// The matcher this visitor is used with will find a single implicit cast or a -/// top-most explicit cast (i.e. it has no explicit casts as an ancestor) where -/// an implicit cast is nested within. However, there is no guarantee that only -/// explicit casts exist between the found top-most explicit cast and the -/// possibly more than one nested implicit cast. This visitor finds all cast -/// sequences with an implicit cast to null within and creates a replacement -/// leaving the outermost explicit cast unchanged to avoid introducing -/// ambiguities. -class CastSequenceVisitor : public RecursiveASTVisitor { -public: - CastSequenceVisitor(ASTContext &Context, const UserMacroNames &UserNullMacros, - unsigned &AcceptedChanges, Transform &Owner) - : SM(Context.getSourceManager()), Context(Context), - UserNullMacros(UserNullMacros), AcceptedChanges(AcceptedChanges), - Owner(Owner), FirstSubExpr(nullptr), PruneSubtree(false) {} - - bool TraverseStmt(Stmt *S) { - // Stop traversing down the tree if requested. - if (PruneSubtree) { - PruneSubtree = false; - return true; - } - return RecursiveASTVisitor::TraverseStmt(S); - } - - // Only VisitStmt is overridden as we shouldn't find other base AST types - // within a cast expression. - bool VisitStmt(Stmt *S) { - CastExpr *C = dyn_cast(S); - if (!C) { - FirstSubExpr = nullptr; - return true; - } else if (!FirstSubExpr) { - FirstSubExpr = C->getSubExpr()->IgnoreParens(); - } - - if (C->getCastKind() == CK_NullToPointer || - C->getCastKind() == CK_NullToMemberPointer) { - - SourceLocation StartLoc = FirstSubExpr->getLocStart(); - SourceLocation EndLoc = FirstSubExpr->getLocEnd(); - - // If the location comes from a macro arg expansion, *all* uses of that - // arg must be checked to result in NullTo(Member)Pointer casts. - // - // If the location comes from a macro body expansion, check to see if its - // coming from one of the allowed 'NULL' macros. - if (SM.isMacroArgExpansion(StartLoc) && SM.isMacroArgExpansion(EndLoc)) { - SourceLocation FileLocStart = SM.getFileLoc(StartLoc), - FileLocEnd = SM.getFileLoc(EndLoc); - if (isReplaceableRange(FileLocStart, FileLocEnd, SM, Owner) && - allArgUsesValid(C)) { - ReplaceWithNullptr(Owner, SM, FileLocStart, FileLocEnd); - ++AcceptedChanges; - } - return skipSubTree(); - } - - if (SM.isMacroBodyExpansion(StartLoc) && - SM.isMacroBodyExpansion(EndLoc)) { - llvm::StringRef OutermostMacroName = - GetOutermostMacroName(StartLoc, SM, Context.getLangOpts()); - - // Check to see if the user wants to replace the macro being expanded. - if (std::find(UserNullMacros.begin(), UserNullMacros.end(), - OutermostMacroName) == UserNullMacros.end()) { - return skipSubTree(); - } - - StartLoc = SM.getFileLoc(StartLoc); - EndLoc = SM.getFileLoc(EndLoc); - } - - if (!isReplaceableRange(StartLoc, EndLoc, SM, Owner)) { - return skipSubTree(); - } - ReplaceWithNullptr(Owner, SM, StartLoc, EndLoc); - ++AcceptedChanges; - - return skipSubTree(); - } // If NullTo(Member)Pointer cast. - - return true; - } - -private: - bool skipSubTree() { PruneSubtree = true; return true; } - - /// \brief Tests that all expansions of a macro arg, one of which expands to - /// result in \p CE, yield NullTo(Member)Pointer casts. - bool allArgUsesValid(const CastExpr *CE) { - SourceLocation CastLoc = CE->getLocStart(); - - // Step 1: Get location of macro arg and location of the macro the arg was - // provided to. - SourceLocation ArgLoc, MacroLoc; - if (!getMacroAndArgLocations(CastLoc, ArgLoc, MacroLoc)) - return false; - - // Step 2: Find the first ancestor that doesn't expand from this macro. - ast_type_traits::DynTypedNode ContainingAncestor; - if (!findContainingAncestor( - ast_type_traits::DynTypedNode::create(*CE), MacroLoc, - ContainingAncestor)) - return false; - - // Step 3: - // Visit children of this containing parent looking for the least-descended - // nodes of the containing parent which are macro arg expansions that expand - // from the given arg location. - // Visitor needs: arg loc - MacroArgUsageVisitor ArgUsageVisitor(SM.getFileLoc(CastLoc), SM); - if (const Decl *D = ContainingAncestor.get()) - ArgUsageVisitor.TraverseDecl(const_cast(D)); - else if (const Stmt *S = ContainingAncestor.get()) - ArgUsageVisitor.TraverseStmt(const_cast(S)); - else - llvm_unreachable("Unhandled ContainingAncestor node type"); - - if (ArgUsageVisitor.foundInvalid()) - return false; - - return true; - } - - /// \brief Given the SourceLocation for a macro arg expansion, finds the - /// non-macro SourceLocation of the macro the arg was passed to and the - /// non-macro SourceLocation of the argument in the arg list to that macro. - /// These results are returned via \c MacroLoc and \c ArgLoc respectively. - /// These values are undefined if the return value is false. - /// - /// \returns false if one of the returned SourceLocations would be a - /// SourceLocation pointing within the definition of another macro. - bool getMacroAndArgLocations(SourceLocation Loc, SourceLocation &ArgLoc, - SourceLocation &MacroLoc) { - assert(Loc.isMacroID() && "Only reasonble to call this on macros"); - - ArgLoc = Loc; - - // Find the location of the immediate macro expansion. - while (1) { - std::pair LocInfo = SM.getDecomposedLoc(ArgLoc); - const SrcMgr::SLocEntry *E = &SM.getSLocEntry(LocInfo.first); - const SrcMgr::ExpansionInfo &Expansion = E->getExpansion(); - - SourceLocation OldArgLoc = ArgLoc; - ArgLoc = Expansion.getExpansionLocStart(); - if (!Expansion.isMacroArgExpansion()) { - if (!MacroLoc.isFileID()) - return false; - - StringRef Name = - Lexer::getImmediateMacroName(OldArgLoc, SM, Context.getLangOpts()); - return std::find(UserNullMacros.begin(), UserNullMacros.end(), Name) != - UserNullMacros.end(); - } - - MacroLoc = SM.getImmediateExpansionRange(ArgLoc).first; - - ArgLoc = Expansion.getSpellingLoc().getLocWithOffset(LocInfo.second); - if (ArgLoc.isFileID()) - return true; - - // If spelling location resides in the same FileID as macro expansion - // location, it means there is no inner macro. - FileID MacroFID = SM.getFileID(MacroLoc); - if (SM.isInFileID(ArgLoc, MacroFID)) - // Don't transform this case. If the characters that caused the - // null-conversion come from within a macro, they can't be changed. - return false; - } - - llvm_unreachable("getMacroAndArgLocations"); - } - - /// \brief Tests if TestMacroLoc is found while recursively unravelling - /// expansions starting at TestLoc. TestMacroLoc.isFileID() must be true. - /// Implementation is very similar to getMacroAndArgLocations() except in this - /// case, it's not assumed that TestLoc is expanded from a macro argument. - /// While unravelling expansions macro arguments are handled as with - /// getMacroAndArgLocations() but in this function macro body expansions are - /// also handled. - /// - /// False means either: - /// - TestLoc is not from a macro expansion - /// - TestLoc is from a different macro expansion - bool expandsFrom(SourceLocation TestLoc, SourceLocation TestMacroLoc) { - if (TestLoc.isFileID()) { - return false; - } - - SourceLocation Loc = TestLoc, MacroLoc; - - while (1) { - std::pair LocInfo = SM.getDecomposedLoc(Loc); - const SrcMgr::SLocEntry *E = &SM.getSLocEntry(LocInfo.first); - const SrcMgr::ExpansionInfo &Expansion = E->getExpansion(); - - Loc = Expansion.getExpansionLocStart(); - - if (!Expansion.isMacroArgExpansion()) { - if (Loc.isFileID()) { - if (Loc == TestMacroLoc) - // Match made. - return true; - return false; - } - // Since Loc is still a macro ID and it's not an argument expansion, we - // don't need to do the work of handling an argument expansion. Simply - // keep recursively expanding until we hit a FileID or a macro arg - // expansion or a macro arg expansion. - continue; - } - - MacroLoc = SM.getImmediateExpansionRange(Loc).first; - if (MacroLoc.isFileID() && MacroLoc == TestMacroLoc) - // Match made. - return true; - - Loc = Expansion.getSpellingLoc(); - Loc = Expansion.getSpellingLoc().getLocWithOffset(LocInfo.second); - if (Loc.isFileID()) - // If we made it this far without finding a match, there is no match to - // be made. - return false; - } - - llvm_unreachable("expandsFrom"); - } - - /// \brief Given a starting point \c Start in the AST, find an ancestor that - /// doesn't expand from the macro called at file location \c MacroLoc. - /// - /// \pre MacroLoc.isFileID() - /// \returns true if such an ancestor was found, false otherwise. - bool findContainingAncestor(ast_type_traits::DynTypedNode Start, - SourceLocation MacroLoc, - ast_type_traits::DynTypedNode &Result) { - // Below we're only following the first parent back up the AST. This should - // be fine since for the statements we care about there should only be one - // parent as far up as we care. If this assumption doesn't hold, need to - // revisit what to do here. - - assert(MacroLoc.isFileID()); - - do { - const auto &Parents = Context.getParents(Start); - if (Parents.empty()) - return false; - assert(Parents.size() == 1 && - "Found an ancestor with more than one parent!"); - - const ast_type_traits::DynTypedNode &Parent = Parents[0]; - - SourceLocation Loc; - if (const Decl *D = Parent.get()) - Loc = D->getLocStart(); - else if (const Stmt *S = Parent.get()) - Loc = S->getLocStart(); - else - llvm_unreachable("Expected to find Decl or Stmt containing ancestor"); - - if (!expandsFrom(Loc, MacroLoc)) { - Result = Parent; - return true; - } - Start = Parent; - } while (1); - - llvm_unreachable("findContainingAncestor"); - } - -private: - SourceManager &SM; - ASTContext &Context; - const UserMacroNames &UserNullMacros; - unsigned &AcceptedChanges; - Transform &Owner; - Expr *FirstSubExpr; - bool PruneSubtree; -}; -} // namespace - -NullptrFixer::NullptrFixer(unsigned &AcceptedChanges, - llvm::ArrayRef UserMacros, - Transform &Owner) - : AcceptedChanges(AcceptedChanges), Owner(Owner) { - UserNullMacros.insert(UserNullMacros.begin(), UserMacros.begin(), - UserMacros.end()); - UserNullMacros.insert(UserNullMacros.begin(), llvm::StringRef(NullMacroName)); -} - -void NullptrFixer::run(const ast_matchers::MatchFinder::MatchResult &Result) { - const CastExpr *NullCast = Result.Nodes.getNodeAs(CastSequence); - assert(NullCast && "Bad Callback. No node provided"); - // Given an implicit null-ptr cast or an explicit cast with an implicit - // null-to-pointer cast within use CastSequenceVisitor to identify sequences - // of explicit casts that can be converted into 'nullptr'. - CastSequenceVisitor Visitor(*Result.Context, UserNullMacros, AcceptedChanges, - Owner); - Visitor.TraverseStmt(const_cast(NullCast)); -} Index: clang-modernize/UseNullptr/NullptrMatchers.h =================================================================== --- clang-modernize/UseNullptr/NullptrMatchers.h +++ /dev/null @@ -1,31 +0,0 @@ -//===-- UseNullptr/NullptrMatchers.h - Matchers for null casts --*- 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 CLANG_MODERNIZE_USE_NULLPTR_MATCHERS_H -#define CLANG_MODERNIZE_USE_NULLPTR_MATCHERS_H - -#include "clang/ASTMatchers/ASTMatchers.h" - -// Names to bind with matched expressions. -extern const char *CastSequence; - -/// \brief Create a matcher that finds implicit casts as well as the head of a -/// sequence of zero or more nested explicit casts that have an implicit cast -/// to null within. -/// Finding sequences of explict casts is necessary so that an entire sequence -/// can be replaced instead of just the inner-most implicit cast. -clang::ast_matchers::StatementMatcher makeCastSequenceMatcher(); - -#endif // CLANG_MODERNIZE_USE_NULLPTR_MATCHERS_H Index: clang-modernize/UseNullptr/NullptrMatchers.cpp =================================================================== --- clang-modernize/UseNullptr/NullptrMatchers.cpp +++ /dev/null @@ -1,70 +0,0 @@ -//===-- UseNullptr/NullptrMatchers.cpp - Matchers for null casts ----------===// -// -// 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 definitions for matcher-generating functions -/// and a custom AST_MATCHER for identifying casts of type CK_NullTo*. -/// -//===----------------------------------------------------------------------===// - -#include "NullptrMatchers.h" -#include "clang/AST/ASTContext.h" - -using namespace clang::ast_matchers; -using namespace clang; - -const char *CastSequence = "sequence"; - -namespace clang { -namespace ast_matchers { -/// \brief Matches cast expressions that have a cast kind of CK_NullToPointer -/// or CK_NullToMemberPointer. -/// -/// Given -/// \code -/// int *p = 0; -/// \endcode -/// implicitCastExpr(isNullToPointer()) matches the implicit cast clang adds -/// around \c 0. -AST_MATCHER(CastExpr, isNullToPointer) { - return Node.getCastKind() == CK_NullToPointer || - Node.getCastKind() == CK_NullToMemberPointer; -} - -AST_MATCHER(Type, sugaredNullptrType) { - const Type *DesugaredType = Node.getUnqualifiedDesugaredType(); - if (const BuiltinType *BT = dyn_cast(DesugaredType)) - return BT->getKind() == BuiltinType::NullPtr; - return false; -} - -} // end namespace ast_matchers -} // end namespace clang - -StatementMatcher makeCastSequenceMatcher() { - StatementMatcher ImplicitCastToNull = - implicitCastExpr( - isNullToPointer(), - unless( - hasSourceExpression( - hasType(sugaredNullptrType()) - ) - ) - ); - - return castExpr( - anyOf( - ImplicitCastToNull, - explicitCastExpr( - hasDescendant(ImplicitCastToNull) - ) - ), - unless(hasAncestor(explicitCastExpr())) - ).bind(CastSequence); -} Index: clang-modernize/UseNullptr/UseNullptr.h =================================================================== --- clang-modernize/UseNullptr/UseNullptr.h +++ /dev/null @@ -1,35 +0,0 @@ -//===-- UseNullptr/UseNullptr.h - C++11 nullptr migration -------*- 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 UseNullptrTransform -/// class which is the main interface to the use-nullptr transform that tries to -/// make use of nullptr where possible. -/// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_USE_NULLPTR_H -#define CLANG_MODERNIZE_USE_NULLPTR_H - -#include "Core/Transform.h" -#include "llvm/Support/Compiler.h" // For override - -/// \brief Subclass of Transform that transforms null pointer constants into -/// C++11's nullptr keyword where possible. -class UseNullptrTransform : public Transform { -public: - UseNullptrTransform(const TransformOptions &Options) - : Transform("UseNullptr", Options) {} - - /// \see Transform::run(). - int apply(const clang::tooling::CompilationDatabase &Database, - const std::vector &SourcePaths) override; -}; - -#endif // CLANG_MODERNIZE_USE_NULLPTR_H Index: clang-modernize/UseNullptr/UseNullptr.cpp =================================================================== --- clang-modernize/UseNullptr/UseNullptr.cpp +++ /dev/null @@ -1,80 +0,0 @@ -//===-- UseNullptr/UseNullptr.cpp - C++11 nullptr migration ---------------===// -// -// 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 UseNullptrTransform -/// class. -/// -//===----------------------------------------------------------------------===// - -#include "UseNullptr.h" -#include "NullptrActions.h" -#include "NullptrMatchers.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Tooling/Refactoring.h" -#include "clang/Tooling/Tooling.h" - -using clang::ast_matchers::MatchFinder; -using namespace clang::tooling; -using namespace clang; -namespace cl = llvm::cl; - -static cl::opt -UserNullMacroNames("user-null-macros", - cl::desc("Comma-separated list of user-defined " - "macro names that behave like NULL"), - cl::cat(TransformsOptionsCategory), cl::init("")); - -int UseNullptrTransform::apply(const CompilationDatabase &Database, - const std::vector &SourcePaths) { - ClangTool UseNullptrTool(Database, SourcePaths); - - unsigned AcceptedChanges = 0; - - llvm::SmallVector MacroNames; - if (!UserNullMacroNames.empty()) { - llvm::StringRef S = UserNullMacroNames; - S.split(MacroNames, ","); - } - MatchFinder Finder; - NullptrFixer Fixer(AcceptedChanges, MacroNames, /*Owner=*/ *this); - - Finder.addMatcher(makeCastSequenceMatcher(), &Fixer); - if (int result = UseNullptrTool.run(createActionFactory(Finder).get())) { - llvm::errs() << "Error encountered during translation.\n"; - return result; - } - - setAcceptedChanges(AcceptedChanges); - - return 0; -} - -namespace { -struct UseNullptrFactory : TransformFactory { - UseNullptrFactory() { - Since.Clang = Version(3, 0); - Since.Gcc = Version(4, 6); - Since.Icc = Version(12, 1); - Since.Msvc = Version(10); - } - - Transform *createTransform(const TransformOptions &Opts) override { - return new UseNullptrTransform(Opts); - } -}; -} // namespace - -// Register the factory using this statically initialized variable. -static TransformFactoryRegistry::Add -X("use-nullptr", "Make use of nullptr keyword where possible"); - -// This anchor is used to force the linker to link in the generated object file -// and thus register the factory. -volatile int UseNullptrTransformAnchorSource = 0; Index: clang-modernize/tool/CMakeLists.txt =================================================================== --- clang-modernize/tool/CMakeLists.txt +++ /dev/null @@ -1,49 +0,0 @@ -set(LLVM_LINK_COMPONENTS support) - -set (ClangModernizeSources - ClangModernize.cpp - ) - -# FIXME: Lib-ify the transforms to simplify the build rules. - -# For each transform subdirectory. -file(GLOB_RECURSE LoopConvertSources "../LoopConvert/*.cpp") -list(APPEND ClangModernizeSources ${LoopConvertSources}) - -file(GLOB_RECURSE UseNullptrSources "../UseNullptr/*.cpp") -list(APPEND ClangModernizeSources ${UseNullptrSources}) - -file(GLOB_RECURSE UseAutoSources "../UseAuto/*.cpp") -list(APPEND ClangModernizeSources ${UseAutoSources}) - -file(GLOB_RECURSE AddOverrideSources "../AddOverride/*.cpp") -list(APPEND ClangModernizeSources ${AddOverrideSources}) - -file(GLOB_RECURSE PassByValueSources "../PassByValue/*.cpp") -list(APPEND ClangModernizeSources ${PassByValueSources}) - -file(GLOB_RECURSE ReplaceAutoPtrSources "../ReplaceAutoPtr/*.cpp") -list(APPEND ClangModernizeSources ${ReplaceAutoPtrSources}) - -add_clang_executable(clang-modernize - ${ClangModernizeSources} - ) - -add_dependencies(clang-modernize - clang-headers clang-apply-replacements - ) - -target_link_libraries(clang-modernize - clangAST - clangASTMatchers - clangBasic - clangFormat - clangFrontend - clangLex - clangTooling - clangToolingCore - modernizeCore - ) - -install(TARGETS clang-modernize - RUNTIME DESTINATION bin) Index: clang-modernize/tool/ClangModernize.cpp =================================================================== --- clang-modernize/tool/ClangModernize.cpp +++ /dev/null @@ -1,489 +0,0 @@ -//===-- ClangModernize.cpp - Main file for Clang modernization tool -------===// -// -// 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 implements the C++11 feature migration tool main function -/// and transformation framework. -/// -/// See user documentation for usage instructions. -/// -//===----------------------------------------------------------------------===// - -#include "Core/PerfSupport.h" -#include "Core/ReplacementHandling.h" -#include "Core/Transform.h" -#include "Core/Transforms.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/Version.h" -#include "clang/Format/Format.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Tooling/CommonOptionsParser.h" -#include "clang/Tooling/Tooling.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Signals.h" - -namespace cl = llvm::cl; -using namespace clang; -using namespace clang::tooling; - -static TransformOptions GlobalOptions; - -// All options must belong to locally defined categories for them to get shown -// by -help. We explicitly hide everything else (except -help and -version). -static cl::OptionCategory GeneralCategory("Modernizer Options"); -static cl::OptionCategory FormattingCategory("Formatting Options"); -static cl::OptionCategory IncludeExcludeCategory("Inclusion/Exclusion Options"); -static cl::OptionCategory SerializeCategory("Serialization Options"); - -static const cl::OptionCategory *const VisibleCategories[] = { - &GeneralCategory, &FormattingCategory, &IncludeExcludeCategory, - &SerializeCategory, &TransformCategory, &TransformsOptionsCategory, -}; - -static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); -static cl::extrahelp MoreHelp( - "EXAMPLES:\n\n" - "Apply all transforms on a file that doesn't require compilation arguments:\n\n" - " clang-modernize file.cpp\n" - "\n" - "Convert for loops to ranged-based for loops for all files in the compilation\n" - "database that belong in a project subtree and then reformat the code\n" - "automatically using the LLVM style:\n\n" - " clang-modernize -p build/path -include project/path -format -loop-convert\n" - "\n" - "Make use of both nullptr and the override specifier, using git ls-files:\n" - "\n" - " git ls-files '*.cpp' | xargs -I{} clang-modernize -p build/path \\\n" - " -use-nullptr -add-override -override-macros {}\n" - "\n" - "Apply all transforms supported by both clang >= 3.0 and gcc >= 4.7 to\n" - "foo.cpp and any included headers in bar:\n\n" - " clang-modernize -for-compilers=clang-3.0,gcc-4.7 foo.cpp \\\n" - " -include bar -- -std=c++11 -Ibar\n\n"); - -//////////////////////////////////////////////////////////////////////////////// -/// General Options - -// This is set to hidden on purpose. The actual help text for this option is -// included in CommonOptionsParser::HelpMessage. -static cl::opt BuildPath("p", cl::desc("Build Path"), cl::Optional, - cl::Hidden, cl::cat(GeneralCategory)); - -static cl::list SourcePaths(cl::Positional, - cl::desc("[...]"), - cl::ZeroOrMore, - cl::cat(GeneralCategory)); - -static cl::opt MaxRiskLevel( - "risk", cl::desc("Select a maximum risk level:"), - cl::values(clEnumValN(RL_Safe, "safe", "Only safe transformations"), - clEnumValN(RL_Reasonable, "reasonable", - "Enable transformations that might change " - "semantics (default)"), - clEnumValN(RL_Risky, "risky", - "Enable transformations that are likely to " - "change semantics"), - clEnumValEnd), - cl::location(GlobalOptions.MaxRiskLevel), cl::init(RL_Reasonable), - cl::cat(GeneralCategory)); - -static cl::opt FinalSyntaxCheck( - "final-syntax-check", - cl::desc("Check for correct syntax after applying transformations"), - cl::init(false), cl::cat(GeneralCategory)); - -static cl::opt SummaryMode("summary", cl::desc("Print transform summary"), - cl::init(false), cl::cat(GeneralCategory)); - -static cl::opt -TimingDirectoryName("perf", - cl::desc("Capture performance data and output to specified " - "directory. Default: ./migrate_perf"), - cl::ValueOptional, cl::value_desc("directory name"), - cl::cat(GeneralCategory)); - -static cl::opt SupportedCompilers( - "for-compilers", cl::value_desc("string"), - cl::desc("Select transforms targeting the intersection of\n" - "language features supported by the given compilers.\n" - "Takes a comma-separated list of -.\n" - "\t can be any of: clang, gcc, icc, msvc\n" - "\t is [.]\n"), - cl::cat(GeneralCategory)); - -//////////////////////////////////////////////////////////////////////////////// -/// Format Options -static cl::opt DoFormat( - "format", - cl::desc("Enable formatting of code changed by applying replacements.\n" - "Use -style to choose formatting style.\n"), - cl::cat(FormattingCategory)); - -static cl::opt -FormatStyleOpt("style", cl::desc(format::StyleOptionHelpDescription), - cl::init("LLVM"), cl::cat(FormattingCategory)); - -// FIXME: Consider making the default behaviour for finding a style -// configuration file to start the search anew for every file being changed to -// handle situations where the style is different for different parts of a -// project. - -static cl::opt FormatStyleConfig( - "style-config", - cl::desc("Path to a directory containing a .clang-format file\n" - "describing a formatting style to use for formatting\n" - "code when -style=file.\n"), - cl::init(""), cl::cat(FormattingCategory)); - -//////////////////////////////////////////////////////////////////////////////// -/// Include/Exclude Options -static cl::opt -IncludePaths("include", - cl::desc("Comma-separated list of paths to consider to be " - "transformed"), - cl::cat(IncludeExcludeCategory)); - -static cl::opt -ExcludePaths("exclude", cl::desc("Comma-separated list of paths that can not " - "be transformed"), - cl::cat(IncludeExcludeCategory)); - -static cl::opt -IncludeFromFile("include-from", cl::value_desc("filename"), - cl::desc("File containing a list of paths to consider to " - "be transformed"), - cl::cat(IncludeExcludeCategory)); - -static cl::opt -ExcludeFromFile("exclude-from", cl::value_desc("filename"), - cl::desc("File containing a list of paths that can not be " - "transformed"), - cl::cat(IncludeExcludeCategory)); - -//////////////////////////////////////////////////////////////////////////////// -/// Serialization Options - -static cl::opt -SerializeOnly("serialize-replacements", - cl::desc("Serialize translation unit replacements to " - "disk instead of changing files."), - cl::init(false), - cl::cat(SerializeCategory)); - -static cl::opt -SerializeLocation("serialize-dir", - cl::desc("Path to an existing directory in which to write\n" - "serialized replacements. Default behaviour is to\n" - "write to a temporary directory.\n"), - cl::cat(SerializeCategory)); - -//////////////////////////////////////////////////////////////////////////////// - -static void printVersion() { - llvm::outs() << "clang-modernizer version " CLANG_VERSION_STRING - << "\n"; -} - -/// \brief Extract the minimum compiler versions as requested on the command -/// line by the switch \c -for-compilers. -/// -/// \param ProgName The name of the program, \c argv[0], used to print errors. -/// \param Error If an error occur while parsing the versions this parameter is -/// set to \c true, otherwise it will be left untouched. -static CompilerVersions handleSupportedCompilers(const char *ProgName, - bool &Error) { - if (SupportedCompilers.getNumOccurrences() == 0) - return CompilerVersions(); - CompilerVersions RequiredVersions; - llvm::SmallVector Compilers; - - llvm::StringRef(SupportedCompilers).split(Compilers, ","); - - for (llvm::SmallVectorImpl::iterator I = Compilers.begin(), - E = Compilers.end(); - I != E; ++I) { - llvm::StringRef Compiler, VersionStr; - std::tie(Compiler, VersionStr) = I->split('-'); - Version *V = llvm::StringSwitch(Compiler) - .Case("clang", &RequiredVersions.Clang) - .Case("gcc", &RequiredVersions.Gcc).Case("icc", &RequiredVersions.Icc) - .Case("msvc", &RequiredVersions.Msvc).Default(nullptr); - - if (V == nullptr) { - llvm::errs() << ProgName << ": " << Compiler - << ": unsupported platform\n"; - Error = true; - continue; - } - if (VersionStr.empty()) { - llvm::errs() << ProgName << ": " << *I - << ": missing version number in platform\n"; - Error = true; - continue; - } - - Version Version = Version::getFromString(VersionStr); - if (Version.isNull()) { - llvm::errs() - << ProgName << ": " << *I - << ": invalid version, please use \"[.]\" instead of \"" - << VersionStr << "\"\n"; - Error = true; - continue; - } - // support the lowest version given - if (V->isNull() || Version < *V) - *V = Version; - } - return RequiredVersions; -} - -static std::unique_ptr -autoDetectCompilations(std::string &ErrorMessage) { - // Auto-detect a compilation database from BuildPath. - if (BuildPath.getNumOccurrences() > 0) - return CompilationDatabase::autoDetectFromDirectory(BuildPath, - ErrorMessage); - // Try to auto-detect a compilation database from the first source. - if (!SourcePaths.empty()) { - if (std::unique_ptr Compilations = - CompilationDatabase::autoDetectFromSource(SourcePaths[0], - ErrorMessage)) { - // FIXME: just pass SourcePaths[0] once getCompileCommands supports - // non-absolute paths. - SmallString<64> Path(SourcePaths[0]); - llvm::sys::fs::make_absolute(Path); - std::vector Commands = - Compilations->getCompileCommands(Path); - // Ignore a detected compilation database that doesn't contain source0 - // since it is probably an unrelated compilation database. - if (!Commands.empty()) - return Compilations; - } - // Reset ErrorMessage since a fix compilation database will be created if - // it fails to detect one from source. - ErrorMessage = ""; - // If no compilation database can be detected from source then we create a - // fixed compilation database with c++11 support. - std::string CommandLine[] = { "-std=c++11" }; - return llvm::make_unique(".", CommandLine); - } - - ErrorMessage = "Could not determine sources to transform"; - return nullptr; -} - -// Predicate definition for determining whether a file is not included. -static bool isFileNotIncludedPredicate(llvm::StringRef FilePath) { - return !GlobalOptions.ModifiableFiles.isFileIncluded(FilePath); -} - -// Predicate definition for determining if a file was explicitly excluded. -static bool isFileExplicitlyExcludedPredicate(llvm::StringRef FilePath) { - if (GlobalOptions.ModifiableFiles.isFileExplicitlyExcluded(FilePath)) { - llvm::errs() << "Warning \"" << FilePath << "\" will not be transformed " - << "because it's in the excluded list.\n"; - return true; - } - return false; -} - -int main(int argc, const char **argv) { - llvm::sys::PrintStackTraceOnErrorSignal(); - Transforms TransformManager; - ReplacementHandling ReplacementHandler; - - TransformManager.registerTransforms(); - - cl::HideUnrelatedOptions(llvm::makeArrayRef(VisibleCategories)); - cl::SetVersionPrinter(&printVersion); - - // Parse options and generate compilations. - std::unique_ptr Compilations( - FixedCompilationDatabase::loadFromCommandLine(argc, argv)); - cl::ParseCommandLineOptions(argc, argv); - - // Populate the ModifiableFiles structure. - GlobalOptions.ModifiableFiles.readListFromString(IncludePaths, ExcludePaths); - GlobalOptions.ModifiableFiles.readListFromFile(IncludeFromFile, - ExcludeFromFile); - - if (!Compilations) { - std::string ErrorMessage; - Compilations = autoDetectCompilations(ErrorMessage); - if (!Compilations) { - llvm::errs() << llvm::sys::path::filename(argv[0]) << ": " << ErrorMessage - << "\n"; - return 1; - } - } - - // Populate source files. - std::vector Sources; - if (!SourcePaths.empty()) { - // Use only files that are not explicitly excluded. - std::remove_copy_if(SourcePaths.begin(), SourcePaths.end(), - std::back_inserter(Sources), - isFileExplicitlyExcludedPredicate); - } else { - if (GlobalOptions.ModifiableFiles.isIncludeListEmpty()) { - llvm::errs() << llvm::sys::path::filename(argv[0]) - << ": Use -include to indicate which files of " - << "the compilatiion database to transform.\n"; - return 1; - } - // Use source paths from the compilation database. - // We only transform files that are explicitly included. - Sources = Compilations->getAllFiles(); - std::vector::iterator E = std::remove_if( - Sources.begin(), Sources.end(), isFileNotIncludedPredicate); - Sources.erase(E, Sources.end()); - } - - if (Sources.empty()) { - llvm::errs() << llvm::sys::path::filename(argv[0]) - << ": Could not determine sources to transform.\n"; - return 1; - } - - // Enable timming. - GlobalOptions.EnableTiming = TimingDirectoryName.getNumOccurrences() > 0; - - bool CmdSwitchError = false; - CompilerVersions RequiredVersions = - handleSupportedCompilers(argv[0], CmdSwitchError); - if (CmdSwitchError) - return 1; - - TransformManager.createSelectedTransforms(GlobalOptions, RequiredVersions); - - if (TransformManager.begin() == TransformManager.end()) { - if (SupportedCompilers.empty()) - llvm::errs() << llvm::sys::path::filename(argv[0]) - << ": no selected transforms\n"; - else - llvm::errs() << llvm::sys::path::filename(argv[0]) - << ": no transforms available for specified compilers\n"; - return 1; - } - - llvm::IntrusiveRefCntPtr DiagOpts( - new DiagnosticOptions()); - DiagnosticsEngine Diagnostics( - llvm::IntrusiveRefCntPtr(new DiagnosticIDs()), - DiagOpts.get()); - - // FIXME: Make this DiagnosticsEngine available to all Transforms probably via - // GlobalOptions. - - // If SerializeReplacements is requested, then code reformatting must be - // turned off and only one transform should be requested. - if (SerializeOnly && - (std::distance(TransformManager.begin(), TransformManager.end()) > 1 || - DoFormat)) { - llvm::errs() << "Serialization of replacements requested for multiple " - "transforms.\nChanges from only one transform can be " - "serialized.\n"; - return 1; - } - - // If we're asked to apply changes to files on disk, need to locate - // clang-apply-replacements. - if (!SerializeOnly) { - if (!ReplacementHandler.findClangApplyReplacements(argv[0])) { - llvm::errs() << "Could not find clang-apply-replacements\n"; - return 1; - } - - if (DoFormat) - ReplacementHandler.enableFormatting(FormatStyleOpt, FormatStyleConfig); - } - - StringRef TempDestinationDir; - if (SerializeLocation.getNumOccurrences() > 0) - ReplacementHandler.setDestinationDir(SerializeLocation); - else - TempDestinationDir = ReplacementHandler.useTempDestinationDir(); - - SourcePerfData PerfData; - - for (Transforms::const_iterator I = TransformManager.begin(), - E = TransformManager.end(); - I != E; ++I) { - Transform *T = *I; - - if (T->apply(*Compilations, Sources) != 0) { - // FIXME: Improve ClangTool to not abort if just one file fails. - return 1; - } - - if (GlobalOptions.EnableTiming) - collectSourcePerfData(*T, PerfData); - - if (SummaryMode) { - llvm::outs() << "Transform: " << T->getName() - << " - Accepted: " << T->getAcceptedChanges(); - if (T->getChangesNotMade()) { - llvm::outs() << " - Rejected: " << T->getRejectedChanges() - << " - Deferred: " << T->getDeferredChanges(); - } - llvm::outs() << "\n"; - } - - if (!ReplacementHandler.serializeReplacements(T->getAllReplacements())) - return 1; - - if (!SerializeOnly) - if (!ReplacementHandler.applyReplacements()) - return 1; - } - - // Let the user know which temporary directory the replacements got written - // to. - if (SerializeOnly && !TempDestinationDir.empty()) - llvm::errs() << "Replacements serialized to: " << TempDestinationDir << "\n"; - - if (FinalSyntaxCheck) { - ClangTool SyntaxTool(*Compilations, SourcePaths); - if (SyntaxTool.run(newFrontendActionFactory().get()) != 0) - return 1; - } - - // Report execution times. - if (GlobalOptions.EnableTiming && !PerfData.empty()) { - std::string DirectoryName = TimingDirectoryName; - // Use default directory name. - if (DirectoryName.empty()) - DirectoryName = "./migrate_perf"; - writePerfDataJSON(DirectoryName, PerfData); - } - - return 0; -} - -// These anchors are used to force the linker to link the transforms -extern volatile int AddOverrideTransformAnchorSource; -extern volatile int LoopConvertTransformAnchorSource; -extern volatile int PassByValueTransformAnchorSource; -extern volatile int ReplaceAutoPtrTransformAnchorSource; -extern volatile int UseAutoTransformAnchorSource; -extern volatile int UseNullptrTransformAnchorSource; - -static int TransformsAnchorsDestination[] = { - AddOverrideTransformAnchorSource, - LoopConvertTransformAnchorSource, - PassByValueTransformAnchorSource, - ReplaceAutoPtrTransformAnchorSource, - UseAutoTransformAnchorSource, - UseNullptrTransformAnchorSource -}; Index: clang-modernize/tool/Makefile =================================================================== --- clang-modernize/tool/Makefile +++ /dev/null @@ -1,58 +0,0 @@ -##===- tools/extra/loop-convert/Makefile ----sssss----------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../../../.. -include $(CLANG_LEVEL)/../../Makefile.config - -TOOLNAME = clang-modernize - -# No plugins, optimize startup time. -TOOL_NO_EXPORTS = 1 - -SOURCES = ClangModernize.cpp - -# FIXME: All these gross relative paths will go away once transforms are lib-ified. - -# For each Transform subdirectory add to SOURCES and BUILT_SOURCES. -# BUILT_SOURCES ensures a subdirectory is created to house object files from -# transform subdirectories. See below for more on .objdir. -SOURCES += $(addprefix ../LoopConvert/,$(notdir $(wildcard $(PROJ_SRC_DIR)/../LoopConvert/*.cpp))) -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 -SOURCES += $(addprefix ../AddOverride/,$(notdir $(wildcard $(PROJ_SRC_DIR)/../AddOverride/*.cpp))) -BUILT_SOURCES += $(ObjDir)/../AddOverride/.objdir -SOURCES += $(addprefix ../PassByValue/,$(notdir $(wildcard $(PROJ_SRC_DIR)/../PassByValue/*.cpp))) -BUILT_SOURCES += $(ObjDir)/../PassByValue/.objdir -SOURCES += $(addprefix ../ReplaceAutoPtr/,$(notdir $(wildcard $(PROJ_SRC_DIR)/../ReplaceAutoPtr/*.cpp))) -BUILT_SOURCES += $(ObjDir)/../ReplaceAutoPtr/.objdir - -LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc mcparser option -USEDLIBS = modernizeCore.a clangFormat.a \ - clangTooling.a clangToolingCore.a clangFrontend.a \ - clangSerialization.a clangDriver.a clangRewriteFrontend.a \ - clangRewrite.a clangParse.a clangSema.a clangAnalysis.a \ - clangAST.a clangASTMatchers.a clangEdit.a clangLex.a clangBasic.a - -include $(CLANG_LEVEL)/Makefile - -CPP.Flags += -I$(PROJ_SRC_DIR)/.. - -# BUILT_SOURCES gets used as a prereq for many top-level targets. However, at -# the point those targets are defined, $(ObjDir) hasn't been defined and so the -# directory to create becomes // which is not what we want. So instead, -# this .objdir recipe is defined at at point where $(ObjDir) is defined and -# it's specialized to $(ObjDir) to ensure it only works on targets we want it -# to. -$(ObjDir)/%.objdir: - $(Verb) $(MKDIR) $(ObjDir)/$* > /dev/null - $(Verb) $(DOTDIR_TIMESTAMP_COMMAND) > $@ - Index: docs/AddOverrideTransform.rst =================================================================== --- docs/AddOverrideTransform.rst +++ /dev/null @@ -1,54 +0,0 @@ -.. index:: Add-Override Transform - -====================== -Add-Override Transform -====================== - -The Add-Override Transform adds the ``override`` specifier to member -functions that override a virtual function in a base class and that -don't already have the specifier. The transform is enabled with the -:option:`-add-override` option of :program:`clang-modernize`. -For example: - -.. code-block:: c++ - - class A { - public: - virtual void h() const; - }; - - class B : public A { - public: - void h() const; - - // The declaration of h is transformed to - void h() const override; - }; - -Using Expands-to-Override Macros -================================ - -Like LLVM's ``LLVM_OVERRIDE``, several projects have macros that conditionally -expand to the ``override`` keyword when compiling with C++11 features enabled. -To maintain compatibility with non-C++11 builds, the Add-Override Transform -supports detection and use of these macros instead of using the ``override`` -keyword directly. Specify ``-override-macros`` on the command line to the -Modernizer to enable this behavior. - - -Known Limitations -================= -* This transform will not insert the override keyword if a method is - pure. At the moment it's not possible to track down the pure - specifier location. - -.. code-block:: c++ - - class B : public A { - public: - virtual void h() const = 0; - - // The declaration of h is NOT transformed to - virtual void h() const override = 0; - }; - Index: docs/LoopConvertTransform.rst =================================================================== --- docs/LoopConvertTransform.rst +++ /dev/null @@ -1,257 +0,0 @@ -.. index:: Loop Convert Transform - -====================== -Loop Convert Transform -====================== - -The Loop Convert Transform is a transformation to convert ``for(...; ...; -...)`` loops to use the new range-based loops in C++11. The transform is enabled -with the :option:`-loop-convert` option of :program:`clang-modernize`. - -Three kinds of loops can be converted: - -- Loops over statically allocated arrays -- Loops over containers, using iterators -- Loops over array-like containers, using ``operator[]`` and ``at()`` - -Risk -==== - -Risky ------ - -In loops where the container expression is more complex than just a -reference to a declared expression (a variable, function, enum, etc.), -and some part of it appears elsewhere in the loop, we lower our confidence -in the transformation due to the increased risk of changing semantics. -Transformations for these loops are marked as `risky`, and thus will only -be converted if the acceptable risk level is set to ``-risk=risky``. - -.. code-block:: c++ - - int arr[10][20]; - int l = 5; - - for (int j = 0; j < 20; ++j) - int k = arr[l][j] + l; // using l outside arr[l] is considered risky - - for (int i = 0; i < obj.getVector().size(); ++i) - obj.foo(10); // using 'obj' is considered risky - -See -:ref:`Range-based loops evaluate end() only once` -for an example of an incorrect transformation when the maximum acceptable risk -level is set to `risky`. - -Reasonable (Default) --------------------- - -If a loop calls ``.end()`` or ``.size()`` after each iteration, the -transformation for that loop is marked as `reasonable`, and thus will -be converted if the acceptable risk level is set to ``-risk=reasonable`` -(default) or higher. - -.. code-block:: c++ - - // using size() is considered reasonable - for (int i = 0; i < container.size(); ++i) - cout << container[i]; - -Safe ----- - -Any other loops that do not match the above criteria to be marked as -`risky` or `reasonable` are marked `safe`, and thus will be converted -if the acceptable risk level is set to ``-risk=safe`` or higher. - -.. code-block:: c++ - - int arr[] = {1,2,3}; - - for (int i = 0; i < 3; ++i) - cout << arr[i]; - -Example -======= - -Original: - -.. code-block:: c++ - - const int N = 5; - int arr[] = {1,2,3,4,5}; - vector v; - v.push_back(1); - v.push_back(2); - v.push_back(3); - - // safe transform - for (int i = 0; i < N; ++i) - cout << arr[i]; - - // reasonable transform - for (vector::iterator it = v.begin(); it != v.end(); ++it) - cout << *it;* - - // reasonable transform - for (int i = 0; i < v.size(); ++i) - cout << v[i]; - -After transformation with risk level set to ``-risk=reasonable`` (default): - -.. code-block:: c++ - - const int N = 5; - int arr[] = {1,2,3,4,5}; - vector v; - v.push_back(1); - v.push_back(2); - v.push_back(3); - - // safe transform - for (auto & elem : arr) - cout << elem; - - // reasonable transform - for (auto & elem : v) - cout << elem; - - // reasonable transform - for (auto & elem : v) - cout << elem; - -Limitations -=========== - -There are certain situations where the tool may erroneously perform -transformations that remove information and change semantics. Users of the tool -should be aware of the behaviour and limitations of the transform outlined by -the cases below. - -Comments inside loop headers ----------------------------- - -Comments inside the original loop header are ignored and deleted when -transformed. - -.. code-block:: c++ - - for (int i = 0; i < N; /* This will be deleted */ ++i) { } - -Range-based loops evaluate end() only once ------------------------------------------- - -The C++11 range-based for loop calls ``.end()`` only once during the -initialization of the loop. If in the original loop ``.end()`` is called after -each iteration the semantics of the transformed loop may differ. - -.. code-block:: c++ - - // The following is semantically equivalent to the C++11 range-based for loop, - // therefore the semantics of the header will not change. - for (iterator it = container.begin(), e = container.end(); it != e; ++it) { } - - // Instead of calling .end() after each iteration, this loop will be - // transformed to call .end() only once during the initialization of the loop, - // which may affect semantics. - for (iterator it = container.begin(); it != container.end(); ++it) { } - -.. _IncorrectRiskyTransformation: - -As explained above, calling member functions of the container in the body -of the loop is considered `risky`. If the called member function modifies the -container the semantics of the converted loop will differ due to ``.end()`` -being called only once. - -.. code-block:: c++ - - bool flag = false; - for (vector::iterator it = vec.begin(); it != vec.end(); ++it) { - // Add a copy of the first element to the end of the vector. - if (!flag) { - // This line makes this transformation 'risky'. - vec.push_back(*it); - flag = true; - } - cout << *it; - } - -The original code above prints out the contents of the container including the -newly added element while the converted loop, shown below, will only print the -original contents and not the newly added element. - -.. code-block:: c++ - - bool flag = false; - for (auto & elem : vec) { - // Add a copy of the first element to the end of the vector. - if (!flag) { - // This line makes this transformation 'risky' - vec.push_back(elem); - flag = true; - } - cout << elem; - } - -Semantics will also be affected if ``.end()`` has side effects. For example, in -the case where calls to ``.end()`` are logged the semantics will change in the -transformed loop if ``.end()`` was originally called after each iteration. - -.. code-block:: c++ - - iterator end() { - num_of_end_calls++; - return container.end(); - } - -Overloaded operator->() with side effects ------------------------------------------ - -Similarly, if ``operator->()`` was overloaded to have side effects, such as -logging, the semantics will change. If the iterator's ``operator->()`` was used -in the original loop it will be replaced with ``.`` -instead due to the implicit dereference as part of the range-based for loop. -Therefore any side effect of the overloaded ``operator->()`` will no longer be -performed. - -.. code-block:: c++ - - for (iterator it = c.begin(); it != c.end(); ++it) { - it->func(); // Using operator->() - } - // Will be transformed to: - for (auto & elem : c) { - elem.func(); // No longer using operator->() - } - -Pointers and references to containers -------------------------------------- - -While most of the transform's risk analysis is dedicated to determining whether -the iterator or container was modified within the loop, it is possible to -circumvent the analysis by accessing and modifying the container through a -pointer or reference. - -If the container were directly used instead of using the pointer or reference -the following transformation would have only been applied at the ``-risk=risky`` -level since calling a member function of the container is considered `risky`. -The transform cannot identify expressions associated with the container that are -different than the one used in the loop header, therefore the transformation -below ends up being performed at the ``-risk=safe`` level. - -.. code-block:: c++ - - vector vec; - - vector *ptr = &vec; - vector &ref = vec; - - for (vector::iterator it = vec.begin(), e = vec.end(); it != e; ++it) { - if (!flag) { - // Accessing and modifying the container is considered risky, but the risk - // level is not raised here. - ptr->push_back(*it); - ref.push_back(*it); - flag = true; - } - } Index: docs/MigratorUsage.rst =================================================================== --- docs/MigratorUsage.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================== -cpp11-migrate Usage -=================== - -This program has been renamed :doc:`clang-modernize `, and its usage is now -found in :doc:`ModernizerUsage`. Index: docs/ModernizerUsage.rst =================================================================== --- docs/ModernizerUsage.rst +++ /dev/null @@ -1,313 +0,0 @@ -===================== -clang-modernize Usage -===================== - -``clang-modernize [options] [...] [-- [args]]`` - -```` specifies the path to the source to migrate. This path may be -relative to the current directory. If no sources are provided, a compilation -database provided with `-p`_ can be used to provide sources together with the -`include/exclude options`_. - -By default all transformations are applied. There are two ways to enable a -subset of the transformations: - -1. Explicitly, by referring to the transform options directly, see - :ref:`transform-specific-command-line-options`. -2. Implicitly, based on the compilers to support, see - :ref:`-for-compilers=\ `. - -If both ways of specifying transforms are used only explicitly specified -transformations that are supported by the given compilers will be applied. - -General Command Line Options -============================ - -.. option:: -help - - Displays tool usage instructions and command line options. - -.. option:: -version - - Displays the version information of this tool. - -.. _-p: - -.. option:: -p= - - ```` is the directory containing a *compilation databasefile*, a - file named ``compile_commands.json``, which provides compiler arguments for - building each source file. CMake can generate this file by specifying - ``-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`` when running CMake. Ninja_, since v1.2 - can also generate this file with ``ninja -t compdb``. If the compilation - database cannot be used for any reason, an error is reported. - - This option is ignored if ``--`` is present. - - Files in the compilation database will be transformed if no sources are - provided and paths to files are explicitly included using ``-include`` or - ``-include-from``. - In order to transform all files in a compilation database the following - command line can be used: - - ``clang-modernize -p= -include=`` - - Use ``-exclude`` or ``-exclude-from`` to limit the scope of ``-include``. - -.. _Ninja: http://martine.github.io/ninja/ - -.. option:: -- [args] - - Another way to provide compiler arguments is to specify all arguments on the - command line following ``--``. Arguments provided this way are used for - *every* source file. - - If neither ``--`` nor ``-p`` are specified a compilation database is - searched for starting with the path of the first-provided source file and - proceeding through parent directories. If no compilation database is found or - one is found and cannot be used for any reason then ``-std=c++11`` is used as - the only compiler argument. - -.. option:: -risk= - - Some transformations may cause a change in semantics. In such cases the - maximum acceptable risk level specified through the ``-risk`` command - line option decides whether or not a transformation is applied. - - Three different risk level options are available: - - ``-risk=safe`` - Perform only safe transformations. - ``-risk=reasonable`` (default) - Enable transformations that may change semantics. - ``-risk=risky`` - Enable transformations that are likely to change semantics. - - The meaning of risk is handled differently for each transform. See - :ref:`transform documentation ` for details. - -.. option:: -final-syntax-check - - After applying the final transform to a file, parse the file to ensure the - last transform did not introduce syntax errors. Syntax errors introduced by - earlier transforms are already caught when subsequent transforms parse the - file. - -.. option:: -summary - - Displays a summary of the number of changes each transform made or could have - made to each source file immediately after each transform is applied. - **Accepted** changes are those actually made. **Rejected** changes are those - that could have been made if the acceptable risk level were higher. - **Deferred** changes are those that might be possible but they might conflict - with other accepted changes. Re-applying the transform will resolve deferred - changes. - -.. _for-compilers-option: - -.. option:: -for-compilers= - - Select transforms targeting the intersection of language features supported by - the given compilers. - - Four compilers are supported. The transforms are enabled according to this - table: - - =============== ===== === ==== ==== - Transforms clang gcc icc mscv - =============== ===== === ==== ==== - AddOverride (1) 3.0 4.7 14 8 - LoopConvert 3.0 4.6 13 11 - PassByValue 3.0 4.6 13 11 - ReplaceAutoPtr 3.0 4.6 13 11 - UseAuto 2.9 4.4 12 10 - UseNullptr 3.0 4.6 12.1 10 - =============== ===== === ==== ==== - - (1): if *-override-macros* is provided it's assumed that the macros are C++11 - aware and the transform is enabled without regard to the supported compilers. - - The structure of the argument to the `-for-compilers` option is - **-[.]** where **** is one of the - compilers from the above table. - - Some examples: - - 1. To support `Clang >= 3.0`, `gcc >= 4.6` and `MSVC >= 11`: - - ``clang-modernize -for-compilers=clang-3.0,gcc-4.6,msvc-11 `` - - Enables LoopConvert, ReplaceAutoPtr, UseAuto, UseNullptr. - - 2. To support `icc >= 12` while using a C++11-aware macro for the `override` - virtual specifier: - - ``clang-modernize -for-compilers=icc-12 -override-macros `` - - Enables AddOverride and UseAuto. - - .. warning:: - - If your version of Clang depends on the GCC headers (e.g: when `libc++` is - not used), then you probably want to add the GCC version to the targeted - platforms as well. - -.. option:: -perf[=] - - Turns on performance measurement and output functionality. The time it takes to - apply each transform is recorded by the migrator and written in JSON format - to a uniquely named file in the given ````. All sources processed - by a single Modernizer process are written to the same output file. If - ```` is not provided the default is ``./migrate_perf/``. - - The time recorded for a transform includes parsing and creating source code - replacements. - -.. option:: -serialize-replacements - - Causes the modernizer to generate replacements and serialize them to disk but - not apply them. This can be useful for debugging or for manually running - ``clang-apply-replacements``. Replacements are serialized in YAML_ format. - By default serialzied replacements are written to a temporary directory whose - name is written to stderr when serialization is complete. - -.. _YAML: http://www.yaml.org/ - -.. option:: -serialize-dir= - - Choose a directory to serialize replacements to. The directory must exist. - -.. _include/exclude options: - -Path Inclusion/Exclusion Options -================================ - -.. option:: -include=,,..., - - Use this option to indicate which directories contain files that can be - changed by the modernizer. Inidividual files may be specified if desired. - Multiple paths can be specified as a comma-separated list. Sources mentioned - explicitly on the command line are always included so this option controls - which other files (e.g. headers) may be changed while transforming - translation units. - -.. option:: -exclude=,,..., - - Used with ``-include`` to provide finer control over which files and - directories can be transformed. Individual files and files within directories - specified by this option **will not** be transformed. Multiple paths can be - specified as a comma-separated list. - -.. option:: -include-from= - - Like ``-include`` but read paths from the given file. Paths should be one per - line. - -.. option:: -exclude-from= - - Like ``-exclude`` but read paths from the given file. Paths are listed one - per line. - -Formatting Command Line Options -=============================== - -.. option:: -format - - Enable reformatting of code changed by transforms. Formatting is done after - every transform. - -.. option:: -style= - - Specifies how formatting should be done. The behaviour of this option is - identical to the same option provided by clang-format_. Refer to - `clang-format's style options`_ for more details. - -.. option:: -style-config= - - When using ``-style=file``, the default behaviour is to look for - ``.clang-format`` starting in the current directory and then in ancestors. To - specify a directory to find the style configuration file, use this option. - -Example: - -.. code-block:: c++ - :emphasize-lines: 10-12,18 - - // file.cpp - for (std::vector::const_iterator I = my_container.begin(), - E = my_container.end(); - I != E; ++I) { - std::cout << *I << std::endl; - } - - // No reformatting: - // clang-modernize -use-auto file.cpp - for (auto I = my_container.begin(), - E = my_container.end(); - I != E; ++I) { - std::cout << *I << std::endl; - } - - // With reformatting enabled: - // clang-modernize -format -use-auto file.cpp - for (auto I = my_container.begin(), E = my_container.end(); I != E; ++I) { - std::cout << *I << std::endl; - } - -.. _clang-format: http://clang.llvm.org/docs/ClangFormat.html -.. _clang-format's style options: http://clang.llvm.org/docs/ClangFormatStyleOptions.html - - -.. _transform-specific-command-line-options: - -Transform-Specific Command Line Options -======================================= - -.. option:: -loop-convert - - Makes use of C++11 range-based for loops where possible. See - :doc:`LoopConvertTransform`. - -.. option:: -use-nullptr - - Makes use of the new C++11 keyword ``nullptr`` where possible. - See :doc:`UseNullptrTransform`. - -.. option:: -user-null-macros= - - ```` is a comma-separated list of user-defined macros that behave like - the ``NULL`` macro. The :option:`-use-nullptr` transform will replace these - macros along with ``NULL``. See :doc:`UseNullptrTransform`. - -.. option:: -use-auto - - Replace the type specifier of variable declarations with the ``auto`` type - specifier. See :doc:`UseAutoTransform`. - -.. option:: -add-override - - Adds the override specifier to member functions where it is appropriate. That - is, the override specifier is added to member functions that override a - virtual function in a base class and that don't already have the specifier. - See :doc:`AddOverrideTransform`. - -.. option:: -override-macros - - Tells the Add Override Transform to locate a macro that expands to - ``override`` and use that macro instead of the ``override`` keyword directly. - If no such macro is found, ``override`` is still used. This option enables - projects that use such macros to maintain build compatibility with non-C++11 - code. - -.. option:: -pass-by-value - - Replace const-reference parameters by values in situations where it can be - beneficial. - See :doc:`PassByValueTransform`. - -.. option:: -replace-auto_ptr - - Replace ``std::auto_ptr`` (deprecated in C++11) by ``std::unique_ptr`` and - wrap calls to the copy constructor and assignment operator with - ``std::move()``. - See :doc:`ReplaceAutoPtrTransform`. Index: docs/PassByValueTransform.rst =================================================================== --- docs/PassByValueTransform.rst +++ /dev/null @@ -1,165 +0,0 @@ -.. index:: Pass-By-Value Transform - -======================= -Pass-By-Value Transform -======================= - -The Pass-By-Value Transform makes use of the pass-by-value idiom when possible. - -With move semantics added to the language and the standard library updated with -move constructors added for many types it is now interesting to take an argument -directly by value, instead of by const-reference, and then copy. This -transformation allows the compiler to take care of choosing the best way to -construct the copy. - -The transformation is usually beneficial when the calling code passes an -*rvalue* and assumes the move construction is a cheap operation. This short -example illustrates how the construction of the value happens: - - .. code-block:: c++ - - void foo(std::string s); - std::string get_str(); - - void f(const std::string &str) { - foo(str); // lvalue -> copy construction - foo(get_str()); // prvalue -> move construction - } - -.. note:: - - Currently only constructors are transformed to make use of pass-by-value. - Contributions that handle other situations are welcome! - - -Pass-by-value in constructors ------------------------------ - -Replaces the uses of const-references constructor parameters that are copied -into class fields. The parameter is then moved with `std::move()`. - -Since `std::move()` is a library function declared in `` it may be -necessary to add this include. The transform will add the include directive when -necessary. - -Example:: - - $ clang-modernize -pass-by-value ctor.cpp - -**ctor.cpp** - - .. code-block:: c++ - - #include - - class Foo { - public: - - Foo(const std::string &Copied, const std::string &ReadOnly) - - : Copied(Copied), ReadOnly(ReadOnly) - + Foo(std::string Copied, const std::string &ReadOnly) - + : Copied(std::move(Copied)), ReadOnly(ReadOnly) - {} - - private: - std::string Copied; - const std::string &ReadOnly; - }; - - std::string get_cwd(); - - void f(const std::string &Path) { - // The parameter corresponding to 'get_cwd()' is move-constructed. By - // using pass-by-value in the Foo constructor we managed to avoid a - // copy-construction. - Foo foo(get_cwd(), Path); - } - - -If the parameter is used more than once no transformation is performed since -moved objects have an undefined state. It means the following code will be left -untouched: - -.. code-block:: c++ - - #include - - void pass(const std::string &S); - - struct Foo { - Foo(const std::string &S) : Str(S) { - pass(S); - } - - std::string Str; - }; - - -Risk -^^^^ - -This modification is considered **reasonably safe** (see :option:`-risk` -option). - -A situation where the generated code can be wrong is when the object referenced -is modified before the assignment in the init-list through a "hidden" reference. - -Example: - -.. code-block:: c++ - - std::string s("foo"); - - struct Base { - Base() { - s = "bar"; - } - }; - - struct Derived : Base { - - Derived(const std::string &S) : Field(S) - + Derived(std::string S) : Field(std::move(S)) - { } - - std::string Field; - }; - - void f() { - - Derived d(s); // d.Field holds "bar" - + Derived d(s); // d.Field holds "foo" - } - - -Note about delayed template parsing -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When delayed template parsing is enabled, constructors part of templated -contexts; templated constructors, constructors in class templates, constructors -of inner classes of template classes, etc., are not transformed. Delayed -template parsing is enabled by default on Windows as a Microsoft extension: -`Clang Compiler User’s Manual - Microsoft extensions`_. - -Delayed template parsing can be enabled using the `-fdelayed-template-parsing` -flag and disabled using `-fno-delayed-template-parsing`. - -Example: - -.. code-block:: c++ - - template class C { - std::string S; - - public: - = // using -fdelayed-template-parsing (default on Windows) - = C(const std::string &S) : S(S) {} - - + // using -fno-delayed-template-parsing (default on non-Windows systems) - + C(std::string S) : S(std::move(S)) {} - }; - -.. _Clang Compiler User’s Manual - Microsoft extensions: http://clang.llvm.org/docs/UsersManual.html#microsoft-extensions - -.. seealso:: - - For more information about the pass-by-value idiom, read: `Want Speed? Pass by Value`_. - - .. _Want Speed? Pass by Value: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ Index: docs/ReplaceAutoPtrTransform.rst =================================================================== --- docs/ReplaceAutoPtrTransform.rst +++ /dev/null @@ -1,72 +0,0 @@ -.. index:: Replace-AutoPtr Transform - -========================= -Replace-AutoPtr Transform -========================= - -The Replace-AutoPtr Transform replaces the uses of the deprecated class -``std::auto_ptr`` by ``std::unique_ptr`` (introduced in C++11). The transfer of -ownership, done by the copy-constructor and the assignment operator, is changed -to match ``std::unique_ptr`` usage by using explicit calls to ``std::move()``. -The transform is enabled with the :option:`-replace-auto_ptr` option of -:program:`clang-modernize`. - -Migration example: - -.. code-block:: c++ - - -void take_ownership_fn(std::auto_ptr int_ptr); - +void take_ownership_fn(std::unique_ptr int_ptr); - - void f(int x) { - - std::auto_ptr a(new int(x)); - - std::auto_ptr b; - + std::unique_ptr a(new int(x)); - + std::unique_ptr b; - - - b = a; - - take_ownership_fn(b); - + b = std::move(a); - + take_ownership_fn(std::move(b)); - } - - -Known Limitations -================= -* If headers modification is not activated or if a header is not allowed to be - changed this transform will produce broken code (compilation error), where the - the headers' code will stay unchanged while the code using them will be - changed. - -* Client code that declares a reference to an ``std::auto_ptr`` coming from code - that can't be migrated (such as a header coming from a 3\ :sup:`rd` party - library) will produce a compilation error after migration. This is because the - type of the reference will be changed to ``std::unique_ptr`` but the type - returned by the library won't change, binding a reference to - ``std::unique_ptr`` from an ``std::auto_ptr``. This pattern doesn't make much - sense and usually ``std::auto_ptr`` are stored by value (otherwise what is the - point in using them instead of a reference or a pointer?). - - .. code-block:: c++ - - // <3rd-party header...> - std::auto_ptr get_value(); - const std::auto_ptr & get_ref(); - - // - -std::auto_ptr a(get_value()); - +std::unique_ptr a(get_value()); // ok, unique_ptr constructed from auto_ptr - - -const std::auto_ptr & p = get_ptr(); - +const std::unique_ptr & p = get_ptr(); // won't compile - -* Non-instantiated templates aren't modified. - - .. code-block:: c++ - - template - void f() { - std::auto_ptr p; - } - - // only 'f()' (or similar) will trigger the replacement Index: docs/UseAutoTransform.rst =================================================================== --- docs/UseAutoTransform.rst +++ /dev/null @@ -1,137 +0,0 @@ -.. index:: Use-Auto Transform - -================== -Use-Auto Transform -================== - -The Use-Auto Transform is responsible for using the ``auto`` type specifier for -variable declarations to *improve code readability and maintainability*. The -transform is enabled with the :option:`-use-auto` option of -:program:`clang-modernize`. For example: - -.. code-block:: c++ - - std::vector::iterator I = my_container.begin(); - - // transforms to: - - auto I = my_container.begin(); - -The ``auto`` type specifier will only be introduced in situations where the -variable type matches the type of the initializer expression. In other words -``auto`` should deduce the same type that was originally spelled in the source. -However, not every situation should be transformed: - -.. code-block:: c++ - - int val = 42; - InfoStruct &I = SomeObject.getInfo(); - - // Should not become: - - auto val = 42; - auto &I = SomeObject.getInfo(); - -In this example using ``auto`` for builtins doesn't improve readability. In -other situations it makes the code less self-documenting impairing readability -and maintainability. As a result, ``auto`` is used only introduced in specific -situations described below. - -Iterators -========= - -Iterator type specifiers tend to be long and used frequently, especially in -loop constructs. Since the functions generating iterators have a common format, -the type specifier can be replaced without obscuring the meaning of code while -improving readability and maintainability. - -.. code-block:: c++ - - for (std::vector::iterator I = my_container.begin(), - E = my_container.end(); - I != E; ++I) { - } - - // becomes - - for (auto I = my_container.begin(), E = my_container.end(); I != E; ++I) { - } - -The transform will only replace iterator type-specifiers when all of the -following conditions are satisfied: -* The iterator is for one of the standard container in ``std`` namespace: - - * ``array`` - - * ``deque`` - - * ``forward_list`` - - * ``list`` - - * ``vector`` - - * ``map`` - - * ``multimap`` - - * ``set`` - - * ``multiset`` - - * ``unordered_map`` - - * ``unordered_multimap`` - - * ``unordered_set`` - - * ``unordered_multiset`` - - * ``queue`` - - * ``priority_queue`` - - * ``stack`` - -* The iterator is one of the possible iterator types for standard containers: - - * ``iterator`` - - * ``reverse_iterator`` - - * ``const_iterator`` - - * ``const_reverse_iterator`` - -* In addition to using iterator types directly, typedefs or other ways of - referring to those types are also allowed. However, implementation-specific - types for which a type like ``std::vector::iterator`` is itself a - typedef will not be transformed. Consider the following examples: - -.. code-block:: c++ - - // The following direct uses of iterator types will be transformed. - std::vector::iterator I = MyVec.begin(); - { - using namespace std; - list::iterator I = MyList.begin(); - } - - // The type specifier for J would transform to auto since it's a typedef - // to a standard iterator type. - typedef std::map::const_iterator map_iterator; - map_iterator J = MyMap.begin(); - - // The following implementation-specific iterator type for which - // std::vector::iterator could be a typedef would not be transformed. - __gnu_cxx::__normal_iterator K = MyVec.begin(); - -* The initializer for the variable being declared is not a braced initializer - list. Otherwise, use of ``auto`` would cause the type of the variable to be - deduced as``std::initializer_list``. - -Known Limitations -================= -* If the initializer is an explicit conversion constructor, the transform will - not replace the type specifier even though it would be safe to do so. -* User-defined iterators are not handled at this time. Index: docs/UseNullptrTransform.rst =================================================================== --- docs/UseNullptrTransform.rst +++ /dev/null @@ -1,82 +0,0 @@ -.. index:: Use-Nullptr Transform - -===================== -Use-Nullptr Transform -===================== - -The Use-Nullptr Transform is a transformation to convert the usage of null -pointer constants (eg. ``NULL``, ``0``) to use the new C++11 ``nullptr`` -keyword. The transform is enabled with the :option:`-use-nullptr` option of -:program:`clang-modernize`. - -Example -======= - -.. code-block:: c++ - - void assignment() { - char *a = NULL; - char *b = 0; - char c = 0; - } - - int *ret_ptr() { - return 0; - } - - -transforms to: - -.. code-block:: c++ - - void assignment() { - char *a = nullptr; - char *b = nullptr; - char c = 0; - } - - int *ret_ptr() { - return nullptr; - } - - -User defined macros -=================== - -By default this transform will only replace the ``NULL`` macro and will skip any -user-defined macros that behaves like ``NULL``. The user can use the -:option:`-user-null-macros` option to specify a comma-separated list of macro -names that will be transformed along with ``NULL``. - -Example -------- - -.. code-block:: c++ - - #define MY_NULL (void*)0 - void assignment() { - void *p = MY_NULL; - } - - -using the command-line - -.. code-block:: bash - - clang-modernize -use-nullptr -user-null-macros=MY_NULL foo.cpp - - -transforms to: - -.. code-block:: c++ - - #define MY_NULL NULL - void assignment() { - int *p = nullptr; - } - - -Risk -==== - -:option:`-risk` has no effect in this transform. Index: docs/clang-modernize.rst =================================================================== --- docs/clang-modernize.rst +++ docs/clang-modernize.rst @@ -1,112 +1,2 @@ -.. index:: clang-modernize - -.. note:: - - **Deprecation** - - As of September 2015 all :program:`clang-modernize` transforms have been - ported to :doc:`clang-tidy/index`. :program:`clang-modernize` is deprecated - and is going to be removed soon. - - -================================== -Clang C++ Modernizer User's Manual -================================== - -.. toctree:: - :hidden: - - UseAutoTransform - UseNullptrTransform - LoopConvertTransform - AddOverrideTransform - PassByValueTransform - ReplaceAutoPtrTransform - ModernizerUsage - cpp11-migrate - MigratorUsage - -:program:`clang-modernize` is a standalone tool used to automatically convert -C++ code written against old standards to use features of the newest C++ -standard where appropriate. - -Getting Started -=============== - -To build from source: - -1. Read `Getting Started with the LLVM System`_ and `Clang Tools - Documentation`_ for information on getting sources for LLVM, Clang, and - Clang Extra Tools. - -2. `Getting Started with the LLVM System`_ and `Building LLVM with CMake`_ give - directions for how to build. With sources all checked out into the - right place the LLVM build will build Clang Extra Tools and their - dependencies automatically. - - * If using CMake, you can also use the ``clang-modernize`` target to build - just the Modernizer and its dependencies. - -Before continuing, take a look at :doc:`ModernizerUsage` to see how to invoke -the Modernizer. - -Before running the Modernizer on code you'll need the arguments you'd normally -pass to the compiler. If you're migrating a single file with few compiler -arguments, it might be easier to pass the compiler args on the command line -after ``--``. If you don't have any compiler arguments then ``--`` is not needed. -If you're working with multiple files or even a single file with many compiler -args, it's probably best to use a *compilation database*. - -A `compilation database`_ contains the command-line arguments for multiple -files. If the code you want to transform can be built with CMake, you can -generate this database easily by running CMake with the -``-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`` option. The Ninja_ build system, since -v1.2, can create this file too using the *compdb* tool: ``ninja -t compdb``. If -you're not already using either of these tools or cannot easily make use of -them you might consider looking into Bear_. - -In addition to the compiler arguments you usually build your code with, you must -provide the option for enabling C++11 features. For clang and versions of gcc -≥ v4.8 this is ``-std=c++11``. - -With compiler arguments in hand, the modernizer can be applied to sources. Each -transform is applied to all sources before the next transform. All the changes -generated by each transform pass are serialized to disk and applied using -``clang-apply-replacements``. This executable must be located on the ``PATH`` -or be present in the same directory as the ``clang-modernizer`` executable. If -any changes fail to apply, the modernizer will **not** proceed to the next -transform and will halt. - -There's a small chance that changes made by a transform will produce code that -doesn't compile, also causing the modernizer to halt. This can happen with -bugs in the transforms or use of the pre-processor to make the same code behave -differently between translation units. Before logging a bug, be sure which -situation you are dealing with. - -.. _Ninja: http://martine.github.io/ninja/ -.. _Bear: https://github.com/rizsotto/Bear -.. _compilation database: http://clang.llvm.org/docs/JSONCompilationDatabase.html -.. _Getting Started with the LLVM System: http://llvm.org/docs/GettingStarted.html -.. _Building LLVM with CMake: http://llvm.org/docs/CMake.html -.. _Clang Tools Documentation: http://clang.llvm.org/docs/ClangTools.html - - -.. _transforms: - -Transformations -=============== - -The Modernizer is a collection of independent transforms which can be -independently enabled. The transforms currently implemented are: - -* :doc:`LoopConvertTransform` - -* :doc:`UseNullptrTransform` - -* :doc:`UseAutoTransform` - -* :doc:`AddOverrideTransform` - -* :doc:`PassByValueTransform` - -* :doc:`ReplaceAutoPtrTransform` +All :program:`clang-modernize` transforms have moved to :doc:`clang-tidy/index` +(see the ``modernize`` module). Index: docs/cpp11-migrate.rst =================================================================== --- docs/cpp11-migrate.rst +++ docs/cpp11-migrate.rst @@ -1,5 +1,2 @@ -============================ -C++11 Migrator User's Manual -============================ - -This tool has been renamed :doc:`clang-modernize `. +All :program:`clang-modernize` transforms have moved to :doc:`clang-tidy/index` +(see the ``modernize`` module). Index: docs/index.rst =================================================================== --- docs/index.rst +++ docs/index.rst @@ -15,7 +15,6 @@ .. toctree:: :maxdepth: 1 - clang-modernize clang-tidy/index modularize pp-trace Index: test/CMakeLists.txt =================================================================== --- test/CMakeLists.txt +++ test/CMakeLists.txt @@ -36,7 +36,6 @@ # Individual tools we test. clang-apply-replacements - clang-modernize clang-rename clang-query clang-tidy Index: test/clang-modernize/AddOverride/basic.cpp =================================================================== --- test/clang-modernize/AddOverride/basic.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -add-override %t.cpp -- -I %S -std=c++11 -// RUN: FileCheck -input-file=%t.cpp %s -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -add-override -override-macros %t.cpp -- -I %S -std=c++11 -// RUN: FileCheck --check-prefix=MACRO --input-file=%t.cpp %s - -struct A { - virtual ~A(); - // CHECK: virtual ~A(); - void f(); - virtual void h() const; - // CHECK: virtual void h() const; - virtual void i() = 0; - // CHECK: virtual void i() = 0; -}; - -// Test that override isn't added to non-virtual functions. -struct B : public A { - void f(); - // CHECK: struct B - // CHECK-NEXT: void f(); -}; - -// Test that override is added to functions that override virtual functions. -struct C : public A { - void h() const; - // CHECK: struct C - // CHECK-NEXT: void h() const override; - // MACRO: struct C - // MACRO-NEXT: void h() const override; -}; - -// Test that override isn't add to functions that overload but not override. -struct D : public A { - void h(); - // CHECK: struct D - // CHECK-NEXT: void h(); -}; - -// Test that override isn't added again to functions that already have it. -struct E : public A { - void h() const override; - // CHECK: struct E - // CHECK-NEXT: void h() const override; - // MACRO: struct E - // MACRO-NEXT: void h() const override; -}; - -// Test that override isn't added to the destructor. -struct F : public A { - virtual ~F(); - // CHECK: struct F - // CHECK-NEXT: virtual ~F(); -}; - -// Test that override is placed before any end of line comments. -struct G : public A { - void h() const; // comment - void i() // comment - {} - // CHECK: struct G - // CHECK-NEXT: void h() const override; // comment - // CHECK-NEXT: void i() override // comment - // CHECK-NEXT: {} -}; - -// Test that override is placed correctly if there is an inline body. -struct H : public A { - void h() const { } - // CHECK: struct H - // CHECK-NEXT: void h() const override { } -}; - -// Test that override is placed correctly if there is a body on the next line. -struct I : public A { - void h() const - { } - // CHECK: struct I - // CHECK-NEXT: void h() const override - // CHECK-NEXT: { } -}; - -// Test that override is placed correctly if there is a body outside the class. -struct J : public A { - void h() const; - // CHECK: struct J - // CHECK-NEXT: void h() const override; -}; - -void J::h() const { - // CHECK: void J::h() const { -} - -// Test that override is placed correctly if there is a trailing return type. -struct K : public A { - auto h() const -> void; - // CHECK: struct K - // CHECK-NEXT: auto h() const -> void override; -}; - -#define LLVM_OVERRIDE override - -// Test that override isn't added if it is already specified via a macro. -struct L : public A { - void h() const LLVM_OVERRIDE; - // CHECK: struct L - // CHECK-NEXT: void h() const LLVM_OVERRIDE; - // MACRO: struct L - // MACRO-NEXT: void h() const LLVM_OVERRIDE; -}; - -template -struct M : public A { - virtual void i(); - // CHECK: struct M - // CHECK-NEXT: virtual void i() override; - // MACRO: struct M - // MACRO-NEXT: virtual void i() LLVM_OVERRIDE; -}; -M b; - -// Test that override isn't added at the wrong place for "pure overrides" -struct APure { - virtual APure *clone() = 0; -}; -struct BPure : APure { - virtual BPure *clone() { return new BPure(); } -}; -struct CPure : BPure { - virtual BPure *clone() = 0; - // CHECK: struct CPure : BPure { - // CHECK-NOT: virtual BPure *clone() = 0 override; - // CHECK: }; -}; -struct DPure : CPure { - virtual DPure *clone() { return new DPure(); } -}; - -// Test that override is not added on dangerous template constructs -struct Base1 { - virtual void f(); -}; -struct Base2 {}; -template struct Derived : T { - void f(); // adding 'override' here will break instantiation of Derived - // CHECK: struct Derived - // CHECK-NEXT: void f(); -}; -Derived d1; -Derived d2; - -#undef LLVM_OVERRIDE - -struct N : public A { - void h() const; - // CHECK: struct N - // CHECK-NEXT: void h() const override; - // MACRO: struct N - // MACRO-NEXT: void h() const override; -}; Index: test/clang-modernize/AddOverride/pure_specifier_fail.cpp =================================================================== --- test/clang-modernize/AddOverride/pure_specifier_fail.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -add-override %t.cpp -- -I %S -// RUN: FileCheck -input-file=%t.cpp %s -// XFAIL: * - -// Test that override isn't placed correctly after "pure overrides" -struct A { - virtual A *clone() = 0; -}; -struct B : A { - virtual B *clone() { return new B(); } -}; -struct C : B { - virtual B *clone() = 0; - // CHECK: struct C : B { - // CHECK: virtual B *clone() override = 0; -}; -struct D : C { - virtual D *clone() { return new D(); } -}; Index: test/clang-modernize/Combined/combined.cpp =================================================================== --- test/clang-modernize/Combined/combined.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t_risky.cpp -// RUN: clang-modernize -loop-convert -use-nullptr %t.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%t.cpp %s -// RUN: clang-modernize -loop-convert -use-nullptr -risk=risky %t_risky.cpp -- -std=c++11 -// RUN: FileCheck -check-prefix=RISKY -input-file=%t_risky.cpp %s - -#define NULL 0 - -struct T { - struct iterator { - int *& operator*(); - const int *& operator*() const; - iterator & operator++(); - bool operator!=(const iterator &other); - void insert(int *); - int *x; - }; - - iterator begin(); - iterator end(); -}; - -void test_loopconvert_and_nullptr_iterator() { - T t; - - for (T::iterator it = t.begin(); it != t.end(); ++it) { - *it = NULL; - } - - // CHECK: for (auto & elem : t) - // CHECK-NEXT: elem = nullptr; -} - -void test_loopconvert_and_nullptr_risky() { - const int N = 10; - int *(*pArr)[N]; - - for (int i = 0; i < N; ++i) { - (*pArr)[i] = NULL; - } - - // RISKY: for (auto & elem : *pArr) - // RISKY-NEXT: elem = nullptr; -} Index: test/clang-modernize/Combined/compilers.cpp =================================================================== --- test/clang-modernize/Combined/compilers.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// RUN: grep -Ev "// *[A-Z0-9-]+:" %s > %t.cpp -// RUN: clang-modernize -for-compilers=clang-2.9 %t.cpp -- -std=c++11 -// RUN: FileCheck -check-prefix=CLANG-29 -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z0-9-]+:" %s > %t.cpp -// RUN: clang-modernize -for-compilers=clang-2.9 -override-macros %t.cpp -- -std=c++11 -// RUN: FileCheck -check-prefix=CLANG-29-OV-MACROS -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z0-9-]+:" %s > %t.cpp -// RUN: clang-modernize -for-compilers=clang-3.0 %t.cpp -- -std=c++11 -// RUN: FileCheck -check-prefix=CLANG-30 -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z0-9-]+:" %s > %t.cpp -// RUN: clang-modernize -for-compilers=gcc-4.6 %t.cpp -- -std=c++11 -// RUN: FileCheck -check-prefix=GCC-46 -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z0-9-]+:" %s > %t.cpp -// RUN: clang-modernize -for-compilers=gcc-4.7 %t.cpp -- -std=c++11 -// RUN: FileCheck -check-prefix=GCC-47 -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z0-9-]+:" %s > %t.cpp -// RUN: clang-modernize -for-compilers=icc-13 %t.cpp -- -std=c++11 -// RUN: FileCheck -check-prefix=ICC-13 -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z0-9-]+:" %s > %t.cpp -// RUN: clang-modernize -for-compilers=icc-14 %t.cpp -- -std=c++11 -// RUN: FileCheck -check-prefix=ICC-14 -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z0-9-]+:" %s > %t.cpp -// RUN: clang-modernize -for-compilers=msvc-8 %t.cpp -- -std=c++11 -// RUN: FileCheck -check-prefix=MSVC-8 -input-file=%t.cpp %s -// -// Test multiple compilers -// RUN: grep -Ev "// *[A-Z0-9-]+:" %s > %t.cpp -// RUN: clang-modernize -for-compilers=clang-3.0,gcc-4.6,gcc-4.7 %t.cpp -- -std=c++11 -// RUN: FileCheck -check-prefix=MULTIPLE -input-file=%t.cpp %s -// -// Test unknown platform -// RUN: not clang-modernize -for-compilers=foo-10 %t.cpp -- -std=c++11 -// -// Test when no transforms can be selected because the compiler lacks support of -// the needed C++11 features -// RUN: not clang-modernize -for-compilers=clang-2.0 %t.cpp -- -std=c++11 - -// Test add overrides -struct A { - virtual A *clone() = 0; -}; - -#define LLVM_OVERRIDE override - -struct B : A { - virtual B *clone(); - // CLANG-29-OV-MACROS: virtual B *clone() LLVM_OVERRIDE; - // CLANG-29: virtual B *clone(); - // CLANG-30: virtual B *clone() override; - // GCC-46: virtual B *clone(); - // GCC-47: virtual B *clone() override; - // ICC-13: virtual B *clone(); - // ICC-14: virtual B *clone() override; - // MSVC-8: virtual B *clone() override; - // MULTIPLE: virtual B *clone(); -}; Index: test/clang-modernize/Compilations/Inputs/compilations.cpp =================================================================== --- test/clang-modernize/Compilations/Inputs/compilations.cpp +++ /dev/null @@ -1,3 +0,0 @@ -void foo() { - int *p = 0; -} Index: test/clang-modernize/Compilations/Inputs/compilations_expected.cpp =================================================================== --- test/clang-modernize/Compilations/Inputs/compilations_expected.cpp +++ /dev/null @@ -1,3 +0,0 @@ -void foo() { - int *p = nullptr; -} Index: test/clang-modernize/Compilations/Inputs/compile_commands.json =================================================================== --- test/clang-modernize/Compilations/Inputs/compile_commands.json +++ /dev/null @@ -1,17 +0,0 @@ -[ -{ - "directory": "$(path)/a1/", - "command": "clang++ -o compilations.o -c $(path)/a1/compilations.cpp -std=c++11", - "file": "$(path)/a1/compilations.cpp" -}, -{ - "directory": "$(path)/a2/", - "command": "clang++ -o compilations.o -c $(path)/a2/compilations.cpp -std=c++11", - "file": "$(path)/a2/compilations.cpp" -}, -{ - "directory": "$(path)/a3/", - "command": "clang++ -o compilations.o -c $(path)/a3/compilations.cpp -std=c++11", - "file": "$(path)/a3/compilations.cpp" -} -] Index: test/clang-modernize/Compilations/Inputs/cpp11.cpp =================================================================== --- test/clang-modernize/Compilations/Inputs/cpp11.cpp +++ /dev/null @@ -1,4 +0,0 @@ -void foo() { - int *p = 0; - int *k = nullptr; -} Index: test/clang-modernize/Compilations/Inputs/cpp11_expected.cpp =================================================================== --- test/clang-modernize/Compilations/Inputs/cpp11_expected.cpp +++ /dev/null @@ -1,4 +0,0 @@ -void foo() { - int *p = nullptr; - int *k = nullptr; -} Index: test/clang-modernize/Compilations/compilation_inc.cpp =================================================================== --- test/clang-modernize/Compilations/compilation_inc.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// The following block tests: -// - A compilation database is detected from build path specified by -p and -// -include was provided. - -// Create directory structure -// a1, a2 and a3 are specified paths for files in the compilation database. -// RUN: rm -rf %T/CompilationInc -// RUN: mkdir -p %T/CompilationInc -// RUN: mkdir -p %T/CompilationInc/a1 -// RUN: mkdir -p %T/CompilationInc/a2 -// RUN: mkdir -p %T/CompilationInc/a3 - -// This test uses a compilation database -// RUN: sed -e 's#$(path)#%/T/CompilationInc#g' %S/Inputs/compile_commands.json > %T/CompilationInc/compile_commands.json - -// Check that files are transformed when -p and -include are specified. -// RUN: cp %S/Inputs/compilations.cpp %T/CompilationInc/a1 -// RUN: cp %S/Inputs/compilations.cpp %T/CompilationInc/a2 -// RUN: cp %S/Inputs/compilations.cpp %T/CompilationInc/a3 - -// RUN: clang-modernize -use-nullptr -p=%T/CompilationInc -include=%T/CompilationInc/a1,%T/CompilationInc/a3 -// RUN: diff -b %S/Inputs/compilations_expected.cpp %T/CompilationInc/a1/compilations.cpp -// RUN: not diff -b %S/Inputs/compilations_expected.cpp %T/CompilationInc/a2/compilations.cpp -// RUN: diff -b %S/Inputs/compilations_expected.cpp %T/CompilationInc/a3/compilations.cpp Index: test/clang-modernize/Compilations/compilation_inc_sources.cpp =================================================================== --- test/clang-modernize/Compilations/compilation_inc_sources.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// Test that only specified sources are transformed when -p and -include are -// specified along with sources. - -// Create directory structure -// a1, a2 and a3 are specified paths for files in the compilation database. -// RUN: rm -rf %T/CompilationIncSources -// RUN: mkdir -p %T/CompilationIncSources -// RUN: mkdir -p %T/CompilationIncSources/a1 -// RUN: mkdir -p %T/CompilationIncSources/a2 -// RUN: mkdir -p %T/CompilationIncSources/a3 - -// This test uses a compilation database -// RUN: sed -e 's#$(path)#%/T/CompilationIncSources#g' %S/Inputs/compile_commands.json > %T/CompilationIncSources/compile_commands.json - -// RUN: cp %S/Inputs/compilations.cpp %T/CompilationIncSources/a1 -// RUN: cp %S/Inputs/compilations.cpp %T/CompilationIncSources/a2 -// RUN: cp %S/Inputs/compilations.cpp %T/CompilationIncSources/a3 - -// RUN: clang-modernize -use-nullptr -p=%T/CompilationIncSources -include=%T/CompilationIncSources %T/CompilationIncSources/a2/compilations.cpp -// RUN: not diff -b %S/Inputs/compilations_expected.cpp %T/CompilationIncSources/a1/compilations.cpp -// RUN: diff -b %S/Inputs/compilations_expected.cpp %T/CompilationIncSources/a2/compilations.cpp -// RUN: not diff -b %S/Inputs/compilations_expected.cpp %T/CompilationIncSources/a3/compilations.cpp Index: test/clang-modernize/Compilations/compilation_not_inc.cpp =================================================================== --- test/clang-modernize/Compilations/compilation_not_inc.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// The following block tests: -// - A compilation database is detected from build path specified by -p but -// neither sources nor -include was provided. - -// Create directory structure -// a1, a2 and a3 are specified paths for files in the compilation database. -// RUN: rm -rf %T/CompilationNotInc -// RUN: mkdir -p %T/CompilationNotInc -// RUN: mkdir -p %T/CompilationNotInc/a1 -// RUN: mkdir -p %T/CompilationNotInc/a2 -// RUN: mkdir -p %T/CompilationNotInc/a3 - -// This test uses a compilation database -// RUN: sed -e 's#$(path)#%/T/CompilationNotInc#g' %S/Inputs/compile_commands.json > %T/CompilationNotInc/compile_commands.json - -// Check that no files are transformed when -p is specified but not -include. -// RUN: cp %S/Inputs/compilations.cpp %T/CompilationNotInc/a1 -// RUN: cp %S/Inputs/compilations.cpp %T/CompilationNotInc/a2 -// RUN: cp %S/Inputs/compilations.cpp %T/CompilationNotInc/a3 - -// RUN: not clang-modernize -use-nullptr -p=%T/CompilationNotInc -// RUN: not diff -b %T/compilations_expected.cpp %T/CompilationNotInc/a1/compilations.cpp -// RUN: not diff -b %T/compilations_expected.cpp %T/CompilationNotInc/a2/compilations.cpp -// RUN: not diff -b %T/compilations_expected.cpp %T/CompilationNotInc/a3/compilations.cpp Index: test/clang-modernize/Compilations/detect_from_path.cpp =================================================================== --- test/clang-modernize/Compilations/detect_from_path.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// The following block tests: -// - A compilation database is detected from build path specified by -p and -// files are provided. - -// Create directory structure -// a1, a2 and a3 are specified paths for files in the compilation database. -// RUN: rm -rf %T/DetectFromPath -// RUN: mkdir -p %T/DetectFromPath -// RUN: mkdir -p %T/DetectFromPath/a1 -// RUN: mkdir -p %T/DetectFromPath/a2 -// RUN: mkdir -p %T/DetectFromPath/a3 - -// This test uses a compilation database -// RUN: sed -e 's#$(path)#%/T/DetectFromPath#g' %S/Inputs/compile_commands.json > %T/DetectFromPath/compile_commands.json - -// Check that files are transformed when -p is provided and files are specified. -// RUN: cp %S/Inputs/compilations.cpp %T/DetectFromPath/a1 -// RUN: cp %S/Inputs/compilations.cpp %T/DetectFromPath/a2 -// RUN: cp %S/Inputs/compilations.cpp %T/DetectFromPath/a3 - -// RUN: clang-modernize -use-nullptr -p=%T/DetectFromPath %T/DetectFromPath/a1/compilations.cpp %T/DetectFromPath/a3/compilations.cpp -// RUN: diff -b %S/Inputs/compilations_expected.cpp %T/DetectFromPath/a1/compilations.cpp -// RUN: not diff -b %S/Inputs/compilations_expected.cpp %T/DetectFromPath/a2/compilations.cpp -// RUN: diff -b %S/Inputs/compilations_expected.cpp %T/DetectFromPath/a3/compilations.cpp Index: test/clang-modernize/Compilations/detect_from_source.cpp =================================================================== --- test/clang-modernize/Compilations/detect_from_source.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// The following block tests: -// - A compilation database is detected from source0. - -// Create directory structure -// a1, a2 and a3 are specified paths for files in the compilation database. -// RUN: rm -rf %T/DetectFromSource -// RUN: mkdir -p %T/DetectFromSource -// RUN: mkdir -p %T/DetectFromSource/a1 -// RUN: mkdir -p %T/DetectFromSource/a2 -// RUN: mkdir -p %T/DetectFromSource/a3 - -// This test uses a compilation database -// RUN: sed -e 's#$(path)#%/T/DetectFromSource#g' %S/Inputs/compile_commands.json > %T/DetectFromSource/compile_commands.json - -// Check that a compilation database can be auto-detected from source0 -// RUN: cp %S/Inputs/compilations.cpp %T/DetectFromSource/a1 -// RUN: cp %S/Inputs/compilations.cpp %T/DetectFromSource/a2 -// RUN: cp %S/Inputs/compilations.cpp %T/DetectFromSource/a3 - -// RUN: clang-modernize -use-nullptr %T/DetectFromSource/a1/compilations.cpp %T/DetectFromSource/a3/compilations.cpp -// RUN: diff -b %S/Inputs/compilations_expected.cpp %T/DetectFromSource/a1/compilations.cpp -// RUN: not diff -b %S/Inputs/compilations_expected.cpp %T/DetectFromSource/a2/compilations.cpp -// RUN: diff -b %S/Inputs/compilations_expected.cpp %T/DetectFromSource/a3/compilations.cpp Index: test/clang-modernize/Compilations/fixed_comp.cpp =================================================================== --- test/clang-modernize/Compilations/fixed_comp.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// The following block tests that files are transformed when -- is specified. - -// Create directory structure -// a1, a2 and a3 are specified paths for files in the compilation database. -// RUN: rm -rf %T/FixedComp -// RUN: mkdir -p %T/FixedComp -// RUN: mkdir -p %T/FixedComp/a1 -// RUN: mkdir -p %T/FixedComp/a2 -// RUN: mkdir -p %T/FixedComp/a3 - -// RUN: cp %S/Inputs/compilations.cpp %T/FixedComp/a1 -// RUN: cp %S/Inputs/compilations.cpp %T/FixedComp/a2 -// RUN: cp %S/Inputs/compilations.cpp %T/FixedComp/a3 - -// RUN: clang-modernize -use-nullptr %T/FixedComp/a1/compilations.cpp %T/FixedComp/a3/compilations.cpp -- -// RUN: diff -b %S/Inputs/compilations_expected.cpp %T/FixedComp/a1/compilations.cpp -// RUN: not diff -b %S/Inputs/compilations_expected.cpp %T/FixedComp/a2/compilations.cpp -// RUN: diff -b %S/Inputs/compilations_expected.cpp %T/FixedComp/a3/compilations.cpp Index: test/clang-modernize/Compilations/fixed_comp_inc.cpp =================================================================== --- test/clang-modernize/Compilations/fixed_comp_inc.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// The following block tests: -// - A fixed compilation database is provided and -exclude was also used. - -// Create directory structure -// a1, a2 and a3 are specified paths for files in the compilation database. -// RUN: rm -rf %T/FixedCompInc -// RUN: mkdir -p %T/FixedCompInc -// RUN: mkdir -p %T/FixedCompInc/a1 -// RUN: mkdir -p %T/FixedCompInc/a2 -// RUN: mkdir -p %T/FixedCompInc/a3 - -// Check that only files not explicitly excluded are transformed. -// RUN: cp %S/Inputs/compilations.cpp %T/FixedCompInc/a1 -// RUN: cp %S/Inputs/compilations.cpp %T/FixedCompInc/a2 -// RUN: cp %S/Inputs/compilations.cpp %T/FixedCompInc/a3 - -// RUN: clang-modernize -use-nullptr %T/FixedCompInc/a1/compilations.cpp %T/FixedCompInc/a2/compilations.cpp %T/FixedCompInc/a3/compilations.cpp -exclude=%T/FixedCompInc/a2 -- -// RUN: diff -b %S/Inputs/compilations_expected.cpp %T/FixedCompInc/a1/compilations.cpp -// RUN: not diff -b %S/Inputs/compilations_expected.cpp %T/FixedCompInc/a2/compilations.cpp -// RUN: diff -b %S/Inputs/compilations_expected.cpp %T/FixedCompInc/a3/compilations.cpp Index: test/clang-modernize/Compilations/no_compilation.cpp =================================================================== --- test/clang-modernize/Compilations/no_compilation.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// The following block tests: -// - Neither -p nor -- was specified and a compilation database is detected -// from source0 but the file isn't found the compilation database then -// it's transformed using a fixed compilation database with c++11 support. -// (-- -std=c++11). - -// Create directory structure -// a1, a2 and a3 are specified paths for files in the compilation database but -// not a4. -// RUN: rm -rf %T/NoCompilation -// RUN: mkdir -p %T/NoCompilation -// RUN: mkdir -p %T/NoCompilation/a1 -// RUN: mkdir -p %T/NoCompilation/a2 -// RUN: mkdir -p %T/NoCompilation/a3 -// RUN: mkdir -p %T/NoCompilation/a4 - -// This test uses of a compilation database -// RUN: sed -e 's#$(path)#%/T/NoCompilation#g' %S/Inputs/compile_commands.json > %T/NoCompilation/compile_commands.json - -// RUN: cp %S/Inputs/cpp11.cpp %T/NoCompilation/a4 -// RUN: clang-modernize -use-nullptr %T/NoCompilation/a4/cpp11.cpp -// RUN: diff -b %S/Inputs/cpp11_expected.cpp %T/NoCompilation/a4/cpp11.cpp Index: test/clang-modernize/Core/Inputs/.clang-format =================================================================== --- test/clang-modernize/Core/Inputs/.clang-format +++ /dev/null @@ -1,42 +0,0 @@ ---- -# BasedOnStyle: Google -AccessModifierOffset: -1 -ConstructorInitializerIndentWidth: 4 -AlignEscapedNewlinesLeft: true -AlignTrailingComments: true -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortIfStatementsOnASingleLine: true -AllowShortLoopsOnASingleLine: true -AlwaysBreakTemplateDeclarations: true -AlwaysBreakBeforeMultilineStrings: true -BreakBeforeBinaryOperators: false -BreakConstructorInitializersBeforeComma: false -BinPackParameters: true -ColumnLimit: 80 -ConstructorInitializerAllOnOneLineOrOnePerLine: true -DerivePointerBinding: true -ExperimentalAutoDetectBinPacking: false -IndentCaseLabels: true -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCSpaceBeforeProtocolList: false -PenaltyBreakComment: 60 -PenaltyBreakString: 1000 -PenaltyBreakFirstLessLess: 120 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 200 -PointerBindsToType: true -SpacesBeforeTrailingComments: 2 -Cpp11BracedListStyle: true -Standard: Auto -IndentWidth: 2 -TabWidth: 8 -UseTab: Never -BreakBeforeBraces: Attach -SpacesInParentheses: false -SpaceInEmptyParentheses: false -SpacesInCStyleCastParentheses: false -SpaceAfterControlStatementKeyword: true -SpaceBeforeAssignmentOperators: true -... - Index: test/clang-modernize/Core/Reformatting.cpp =================================================================== --- test/clang-modernize/Core/Reformatting.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -format -use-auto %t.cpp -// RUN: FileCheck --strict-whitespace -input-file=%t.cpp %s - -// Ensure that -style is forwarded to clang-apply-replacements by using a style -// other than LLVM and ensuring the result is styled as requested. -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -format -style=Google -use-nullptr %t.cpp -// RUN: FileCheck --check-prefix=Google --strict-whitespace -input-file=%t.cpp %s - -// Ensure -style-config is forwarded to clang-apply-replacements. The .clang-format -// in %S/Inputs is a dump of the Google style so the same test can be used. -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -format -style=file -style-config=%S/Inputs -use-nullptr %t.cpp -// RUN: FileCheck --check-prefix=Google --strict-whitespace -input-file=%t.cpp %s - -class MyType012345678901234567890123456789 { -public: - MyType012345678901234567890123456789() - : iiiiiiiiiiii(0), jjjjjjjjjjjj(0), kkkkkkkkkkkk(0), mmmmmmmmmmmm(0), - nnnnnnnnnnnn(0) {} - // Google: iiiiiiiiiiii(nullptr), - // Google-NEXT: jjjjjjjjjjjj(nullptr), - // Google-NEXT: kkkkkkkkkkkk(nullptr), - // Google-NEXT: mmmmmmmmmmmm(nullptr), - // Google-NEXT: nnnnnnnnnnnn(nullptr) {} - -private: - int *iiiiiiiiiiii; - int *jjjjjjjjjjjj; - int *kkkkkkkkkkkk; - int *mmmmmmmmmmmm; - int *nnnnnnnnnnnn; -}; - -int f() { - MyType012345678901234567890123456789 *a = - new MyType012345678901234567890123456789(); - // CHECK: {{^\ \ auto\ a\ \=\ new\ MyType012345678901234567890123456789\(\);}} - - delete a; - - return 0; -} Index: test/clang-modernize/HeaderReplacements/Inputs/no_yaml.h =================================================================== --- test/clang-modernize/HeaderReplacements/Inputs/no_yaml.h +++ /dev/null @@ -1,8 +0,0 @@ -void update(int (&arr)[10]) { - int val = 1; - for (unsigned i = 0; i < sizeof(arr)/sizeof(int); ++i) { - arr[i] = val++; - // CHECK: for (auto & elem : arr) { - // CHECK-NEXT: elem = val++; - } -} Index: test/clang-modernize/HeaderReplacements/common.h =================================================================== --- test/clang-modernize/HeaderReplacements/common.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef CPP11_MIGRATE_TEST_HEADER_REPLACEMENTS_COMMON_H -#define CPP11_MIGRATE_TEST_HEADER_REPLACEMENTS_COMMON_H - -struct container { - struct iterator { - int &operator*(); - const int &operator*() const; - iterator &operator++(); - bool operator!=(const iterator &other); - }; - - iterator begin(); - iterator end(); - void push_back(const int &); -}; - -void func1(int &I); -void func2(); - -void dostuff() { - container C; - for (container::iterator I = C.begin(), E = C.end(); I != E; ++I) { - func1(*I); - } -} - -#endif // CPP11_MIGRATE_TEST_HEADER_REPLACEMENTS_COMMON_H Index: test/clang-modernize/HeaderReplacements/common.cpp =================================================================== --- test/clang-modernize/HeaderReplacements/common.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// This is just a dummy run command to keep lit happy. Tests for this file are -// in main.cpp -// RUN: true - -#include "common.h" - -void func1(int &I) { -} - -void func2() { - container C1; - container C2; - for (container::iterator I = C1.begin(), E = C1.end(); I != E; ++I) { - C2.push_back(*I); - } -} Index: test/clang-modernize/HeaderReplacements/common_expected.yaml =================================================================== --- test/clang-modernize/HeaderReplacements/common_expected.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -MainSourceFile: '$(path)/common.cpp' -Replacements: - - FilePath: '$(path)/common.h' - Offset: 506 - Length: 2 - ReplacementText: elem - - FilePath: '$(path)/common.h' - Offset: 432 - Length: 61 - ReplacementText: '(auto & elem : C)' - - FilePath: '$(path)/common.cpp' - Offset: 289 - Length: 2 - ReplacementText: elem - - FilePath: '$(path)/common.cpp' - Offset: 206 - Length: 63 - ReplacementText: '(auto & elem : C1)' -... Index: test/clang-modernize/HeaderReplacements/main.cpp =================================================================== --- test/clang-modernize/HeaderReplacements/main.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// The following block tests the following: -// - Only 1 file is generated per translation unit -// - Replacements are written in YAML that matches the expected YAML file -// The test is run in %T/SerializeTest so it's easy to create a clean test -// directory. -// -// RUN: rm -rf %T/SerializeTest -// RUN: mkdir -p %T/SerializeTest -// RUN: cp %S/main.cpp %S/common.cpp %S/common.h %T/SerializeTest -// RUN: clang-modernize -loop-convert -serialize-replacements -serialize-dir=%T/SerializeTest -include=%T/SerializeTest %T/SerializeTest/main.cpp %T/SerializeTest/common.cpp -- -// Check that only 1 file is generated per translation unit -// RUN: ls -1 %T/SerializeTest | FileCheck %s --check-prefix=MAIN_CPP -// RUN: ls -1 %T/SerializeTest | FileCheck %s --check-prefix=COMMON_CPP -// We need to put the build path to the expected YAML file to diff against the generated one. -// RUN: sed -e 's#$(path)#%/T/SerializeTest#g' -e "s#[^[:space:]]'[^[:space:]]#''#g" -e "s#'\([-a-zA-Z0-9_/^., \t]*\)'#\1#g" %S/main_expected.yaml > %T/SerializeTest/main_expected.yaml -// RUN: sed -i -e 's#\\#/#g' %T/SerializeTest/main.cpp_*.yaml -// RUN: diff -b %T/SerializeTest/main_expected.yaml %T/SerializeTest/main.cpp_*.yaml -// RUN: sed -e 's#$(path)#%/T/SerializeTest#g' -e "s#[^[:space:]]'[^[:space:]]#''#g" -e "s#'\([-a-zA-Z0-9_/^., \t]*\)'#\1#g" %S/common_expected.yaml > %T/SerializeTest/common_expected.yaml -// RUN: sed -i -e 's#\\#/#g' %T/SerializeTest/common.cpp_*.yaml -// RUN: diff -b %T/SerializeTest/common_expected.yaml %T/SerializeTest/common.cpp_*.yaml -// -// The following are for FileCheck when used on output of 'ls'. See above. -// MAIN_CPP: {{^main.cpp_.*.yaml$}} -// MAIN_CPP-NOT: {{main.cpp_.*.yaml}} -// -// COMMON_CPP: {{^common.cpp_.*.yaml$}} -// COMMON_CPP-NOT: {{common.cpp_.*.yaml}} - -// REQUIRES: shell - -#include "common.h" - -void test_header_replacement() { - dostuff(); - func2(); -} Index: test/clang-modernize/HeaderReplacements/main_expected.yaml =================================================================== --- test/clang-modernize/HeaderReplacements/main_expected.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -MainSourceFile: '$(path)/main.cpp' -Replacements: - - FilePath: '$(path)/common.h' - Offset: 506 - Length: 2 - ReplacementText: elem - - FilePath: '$(path)/common.h' - Offset: 432 - Length: 61 - ReplacementText: '(auto & elem : C)' -... Index: test/clang-modernize/HeaderReplacements/no_yaml.cpp =================================================================== --- test/clang-modernize/HeaderReplacements/no_yaml.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Ensure that if -serialize-replacements is not provided, no serialized -// replacement files should be generated and the changes are made directly. -// -// RUN: rm -rf %T/Inputs -// RUN: mkdir -p %T/Inputs -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/no_yaml.h > %T/Inputs/no_yaml.h -// RUN: clang-modernize -loop-convert %t.cpp -include=%T/Inputs -- -I %T/Inputs/no_yaml.h -// RUN: FileCheck --input-file=%t.cpp %s -// RUN: FileCheck --input-file=%T/Inputs/no_yaml.h %S/Inputs/no_yaml.h -// RUN: ls %T | FileCheck %s --check-prefix=NO_YAML -// -// NO_YAML-NOT: {{no_yaml.cpp_.*.yaml}} -#include "Inputs/no_yaml.h" - -void func() { - int arr[10]; - for (unsigned i = 0; i < sizeof(arr)/sizeof(int); ++i) { - arr[i] = 0; - // CHECK: for (auto & elem : arr) { - // CHECK-NEXT: elem = 0; - } - - update(arr); -} Index: test/clang-modernize/LoopConvert/Inputs/macro_problem.h =================================================================== --- test/clang-modernize/LoopConvert/Inputs/macro_problem.h +++ /dev/null @@ -1,7 +0,0 @@ -#define myns nsblah - -namespace nsblah { -struct MyType { -}; - -} // namespace nsblah Index: test/clang-modernize/LoopConvert/Inputs/negative-header.h =================================================================== --- test/clang-modernize/LoopConvert/Inputs/negative-header.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef NEGATIVE_HEADER_H -#define NEGATIVE_HEADER_H - -// Single FileCheck line to make sure that no loops are converted. -// CHECK-NOT: for ({{.*[^:]:[^:].*}}) -static void loopInHeader() { - const int N = 10; - int arr[N]; - int sum = 0; - for (int i = 0; i < N; ++i) - sum += arr[i]; -} - -#endif // NEGATIVE_HEADER_H Index: test/clang-modernize/LoopConvert/Inputs/structures.h =================================================================== --- test/clang-modernize/LoopConvert/Inputs/structures.h +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef STRUCTURES_H -#define STRUCTURES_H - -extern "C" { -extern int printf(const char *restrict, ...); -} - -struct Val {int x; void g(); }; - -struct MutableVal { - void constFun(int) const; - void nonConstFun(int, int); - void constFun(MutableVal &) const; - void constParamFun(const MutableVal &) const; - void nonConstParamFun(const MutableVal &); - int x; -}; - -struct S { - typedef MutableVal *iterator; - typedef const MutableVal *const_iterator; - const_iterator begin() const; - const_iterator end() const; - iterator begin(); - iterator end(); -}; - -struct T { - struct iterator { - int& operator*(); - const int& operator*()const; - iterator& operator ++(); - bool operator!=(const iterator &other); - void insert(int); - int x; - }; - iterator begin(); - iterator end(); -}; - -struct U { - struct iterator { - Val& operator*(); - const Val& operator*()const; - iterator& operator ++(); - bool operator!=(const iterator &other); - Val *operator->(); - }; - iterator begin(); - iterator end(); - int x; -}; - -struct X { - S s; - T t; - U u; - S getS(); -}; - -template -class dependent{ - public: - struct iterator_base { - const ElemType& operator*()const; - iterator_base& operator ++(); - bool operator!=(const iterator_base &other) const; - const ElemType *operator->() const; - }; - - struct iterator : iterator_base { - ElemType& operator*(); - iterator& operator ++(); - ElemType *operator->(); - }; - - typedef iterator_base const_iterator; - const_iterator begin() const; - const_iterator end() const; - iterator begin(); - iterator end(); - unsigned size() const; - ElemType & operator[](unsigned); - const ElemType & operator[](unsigned) const; - ElemType & at(unsigned); - const ElemType & at(unsigned) const; - - // Intentionally evil. - dependent operator*(); - - void foo(); - void constFoo() const; -}; - -template -class doublyDependent{ - public: - struct Value { - First first; - Second second; - }; - - struct iterator_base { - const Value& operator*()const; - iterator_base& operator ++(); - bool operator!=(const iterator_base &other) const; - const Value *operator->() const; - }; - - struct iterator : iterator_base { - Value& operator*(); - Value& operator ++(); - Value *operator->(); - }; - - typedef iterator_base const_iterator; - const_iterator begin() const; - const_iterator end() const; - iterator begin(); - iterator end(); -}; - -template -class transparent { - public: - Contained *at(); - Contained *operator->(); - Contained operator*(); -}; - -template -struct Nested { - typedef IteratorType* iterator; - typedef const IteratorType* const_iterator; - IteratorType *operator->(); - IteratorType operator*(); - iterator begin(); - iterator end(); - const_iterator begin() const; - const_iterator end() const; -}; - -// Like llvm::SmallPtrSet, the iterator has a dereference operator that returns -// by value instead of by reference. -template -struct PtrSet { - struct iterator { - bool operator!=(const iterator &other) const; - const T operator*(); - iterator &operator++(); - }; - iterator begin() const; - iterator end() const; -}; - -template -struct TypedefDerefContainer { - struct iterator { - typedef T &deref_type; - bool operator!=(const iterator &other) const; - deref_type operator*(); - iterator &operator++(); - }; - iterator begin() const; - iterator end() const; -}; - -template -struct RValueDerefContainer { - struct iterator { - typedef T &&deref_type; - bool operator!=(const iterator &other) const; - deref_type operator*(); - iterator &operator++(); - }; - iterator begin() const; - iterator end() const; -}; -#endif // STRUCTURES_H Index: test/clang-modernize/LoopConvert/array.cpp =================================================================== --- test/clang-modernize/LoopConvert/array.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: cp %t.cpp %t.base -// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// RUN: cp %t.base %t.cpp -// NORUN clang-modernize -count-only . %t.cpp -- -I %S/Inputs > %T/out -// NORUN FileCheck -check-prefix=COUNTONLY -input-file=%T/out %s -// RUN: diff %t.cpp %t.base - -#include "structures.h" - -const int N = 6; -const int NMinusOne = N - 1; -int arr[N] = {1, 2, 3, 4, 5, 6}; -int (*pArr)[N] = &arr; - -void f() { - int sum = 0; - // Update the number of correctly converted loops as this test changes: - // COUNTONLY: 15 converted - // COUNTONLY-NEXT: 0 potentially conflicting - // COUNTONLY-NEXT: 0 change(s) rejected - - for (int i = 0; i < N; ++i) { - sum += arr[i]; - int k; - } - // CHECK: for (auto & elem : arr) { - // CHECK-NEXT: sum += elem; - // CHECK-NEXT: int k; - // CHECK-NEXT: } - - for (int i = 0; i < N; ++i) { - printf("Fibonacci number is %d\n", arr[i]); - sum += arr[i] + 2; - } - // CHECK: for (auto & elem : arr) - // CHECK-NEXT: printf("Fibonacci number is %d\n", elem); - // CHECK-NEXT: sum += elem + 2; - - for (int i = 0; i < N; ++i) { - int x = arr[i]; - int y = arr[i] + 2; - } - // CHECK: for (auto & elem : arr) - // CHECK-NEXT: int x = elem; - // CHECK-NEXT: int y = elem + 2; - - for (int i = 0; i < N; ++i) { - int x = N; - x = arr[i]; - } - // CHECK: for (auto & elem : arr) - // CHECK-NEXT: int x = N; - // CHECK-NEXT: x = elem; - - for (int i = 0; i < N; ++i) { - arr[i] += 1; - } - // CHECK: for (auto & elem : arr) { - // CHECK-NEXT: elem += 1; - // CHECK-NEXT: } - - for (int i = 0; i < N; ++i) { - int x = arr[i] + 2; - arr[i] ++; - } - // CHECK: for (auto & elem : arr) - // CHECK-NEXT: int x = elem + 2; - // CHECK-NEXT: elem ++; - - for (int i = 0; i < N; ++i) { - arr[i] = 4 + arr[i]; - } - // CHECK: for (auto & elem : arr) - // CHECK-NEXT: elem = 4 + elem; - - for (int i = 0; i < NMinusOne + 1; ++i) { - sum += arr[i]; - } - // CHECK: for (auto & elem : arr) { - // CHECK-NEXT: sum += elem; - // CHECK-NEXT: } - - for (int i = 0; i < N; ++i) { - printf("Fibonacci number %d has address %p\n", arr[i], &arr[i]); - sum += arr[i] + 2; - } - // CHECK: for (auto & elem : arr) - // CHECK-NEXT: printf("Fibonacci number %d has address %p\n", elem, &elem); - // CHECK-NEXT: sum += elem + 2; - - Val teas[N]; - for (int i = 0; i < N; ++i) { - teas[i].g(); - } - // CHECK: for (auto & tea : teas) { - // CHECK-NEXT: tea.g(); - // CHECK-NEXT: } -} - -struct HasArr { - int Arr[N]; - Val ValArr[N]; - void implicitThis() { - for (int i = 0; i < N; ++i) { - printf("%d", Arr[i]); - } - // CHECK: for (auto & elem : Arr) { - // CHECK-NEXT: printf("%d", elem); - // CHECK-NEXT: } - - for (int i = 0; i < N; ++i) { - printf("%d", ValArr[i].x); - } - // CHECK: for (auto & elem : ValArr) { - // CHECK-NEXT: printf("%d", elem.x); - // CHECK-NEXT: } - } - - void explicitThis() { - for (int i = 0; i < N; ++i) { - printf("%d", this->Arr[i]); - } - // CHECK: for (auto & elem : this->Arr) { - // CHECK-NEXT: printf("%d", elem); - // CHECK-NEXT: } - - for (int i = 0; i < N; ++i) { - printf("%d", this->ValArr[i].x); - } - // CHECK: for (auto & elem : this->ValArr) { - // CHECK-NEXT: printf("%d", elem.x); - // CHECK-NEXT: } - } -}; - -// Loops whose bounds are value-dependent shold not be converted. -template -void dependentExprBound() { - for (int i = 0; i < N; ++i) - arr[i] = 0; - // CHECK: for (int i = 0; i < N; ++i) - // CHECK-NEXT: arr[i] = 0; -} -template void dependentExprBound<20>(); - -void memberFunctionPointer() { - Val v; - void (Val::*mfpArr[N])(void) = { &Val::g }; - for (int i = 0; i < N; ++i) - (v.*mfpArr[i])(); - // CHECK: for (auto & elem : mfpArr) - // CHECK-NEXT: (v.*elem)(); -} Index: test/clang-modernize/LoopConvert/confidence.cpp =================================================================== --- test/clang-modernize/LoopConvert/confidence.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// RUN: clang-modernize -loop-convert %t.cpp -risk=risky -- -I %S/Inputs -// RUN: FileCheck -check-prefix=RISKY -input-file=%t.cpp %s - -#include "structures.h" - -void f() { - const int N = 5; - const int M = 7; - int (*pArr)[N]; - int Arr[N][M]; - int sum = 0; - - for (int i = 0; i < M; ++i) { - sum += Arr[0][i]; - } - // CHECK: for (int i = 0; i < M; ++i) { - // CHECK-NEXT: sum += Arr[0][i]; - // CHECK-NEXT: } - // RISKY: for (auto & elem : Arr[0]) { - // RISKY-NEXT: sum += elem; - // RISKY-NEXT: } - - for (int i = 0; i < N; ++i) { - sum += (*pArr)[i]; - } - // RISKY: for (auto & elem : *pArr) { - // RISKY-NEXT: sum += elem; - // RISKY-NEXT: } - // CHECK: for (int i = 0; i < N; ++i) { - // CHECK-NEXT: sum += (*pArr)[i]; - // CHECK-NEXT: } -} Index: test/clang-modernize/LoopConvert/dependency.cpp =================================================================== --- test/clang-modernize/LoopConvert/dependency.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -loop-convert %t.cpp -- && FileCheck -input-file=%t.cpp %s - -void f() { - const int N = 6; - const int M = 8; - int arr[N][M]; - - for (int i = 0; i < N; ++i) { - int a = 0; - int b = arr[i][a]; - } - // CHECK: for (auto & elem : arr) { - // CHECK-NEXT: int a = 0; - // CHECK-NEXT: int b = elem[a]; - // CHECK-NEXT: } - - for (int j = 0; j < M; ++j) { - int a = 0; - int b = arr[a][j]; - } - // CHECK: for (int j = 0; j < M; ++j) { - // CHECK-NEXT: int a = 0; - // CHECK-NEXT: int b = arr[a][j]; - // CHECK-NEXT: } -} Index: test/clang-modernize/LoopConvert/free_begin_end_fail.cpp =================================================================== --- test/clang-modernize/LoopConvert/free_begin_end_fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -std=c++11 -// RUN: FileCheck -input-file=%t.cpp %s -// XFAIL: * - -struct MyArray { - unsigned size(); -}; - -template -struct MyContainer { -}; - -int *begin(const MyArray &Arr); -int *end(const MyArray &Arr); - -template -T *begin(const MyContainer &C); -template -T *end(const MyContainer &C); - -// The Loop Convert Transform doesn't detect free functions begin()/end() and -// so fails to transform these cases which it should. -void f() { - MyArray Arr; - for (unsigned i = 0, e = Arr.size(); i < e; ++i) {} - // CHECK: for (auto & elem : Arr) {} - - MyContainer C; - for (int *I = begin(C), *E = end(C); I != E; ++I) {} - // CHECK: for (auto & elem : C) {} -} Index: test/clang-modernize/LoopConvert/iterator.cpp =================================================================== --- test/clang-modernize/LoopConvert/iterator.cpp +++ /dev/null @@ -1,244 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -std=c++11 -// RUN: FileCheck -input-file=%t.cpp %s -// RUN: clang-modernize -loop-convert %t.cpp -risk=risky -- -I %S/Inputs -// RUN: FileCheck -check-prefix=RISKY -input-file=%t.cpp %s - -#include "structures.h" - -void f() { - /// begin()/end() - based for loops here: - T t; - for (T::iterator it = t.begin(), e = t.end(); it != e; ++it) { - printf("I found %d\n", *it); - } - // CHECK: for (auto & elem : t) - // CHECK-NEXT: printf("I found %d\n", elem); - - T *pt; - for (T::iterator it = pt->begin(), e = pt->end(); it != e; ++it) { - printf("I found %d\n", *it); - } - // CHECK: for (auto & elem : *pt) - // CHECK-NEXT: printf("I found %d\n", elem); - - S s; - for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) { - printf("s has value %d\n", (*it).x); - } - // CHECK: for (auto & elem : s) - // CHECK-NEXT: printf("s has value %d\n", (elem).x); - - S *ps; - for (S::iterator it = ps->begin(), e = ps->end(); it != e; ++it) { - printf("s has value %d\n", (*it).x); - } - // CHECK: for (auto & p : *ps) - // CHECK-NEXT: printf("s has value %d\n", (p).x); - - for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) { - printf("s has value %d\n", it->x); - } - // CHECK: for (auto & elem : s) - // CHECK-NEXT: printf("s has value %d\n", elem.x); - - for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) { - it->x = 3; - } - // CHECK: for (auto & elem : s) - // CHECK-NEXT: elem.x = 3; - - for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) { - (*it).x = 3; - } - // CHECK: for (auto & elem : s) - // CHECK-NEXT: (elem).x = 3; - - for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) { - it->nonConstFun(4, 5); - } - // CHECK: for (auto & elem : s) - // CHECK-NEXT: elem.nonConstFun(4, 5); - - U u; - for (U::iterator it = u.begin(), e = u.end(); it != e; ++it) { - printf("s has value %d\n", it->x); - } - // CHECK: for (auto & elem : u) - // CHECK-NEXT: printf("s has value %d\n", elem.x); - - for (U::iterator it = u.begin(), e = u.end(); it != e; ++it) { - printf("s has value %d\n", (*it).x); - } - // CHECK: for (auto & elem : u) - // CHECK-NEXT: printf("s has value %d\n", (elem).x); - - U::iterator A; - for (U::iterator i = u.begin(), e = u.end(); i != e; ++i) - int k = A->x + i->x; - // CHECK: for (auto & elem : u) - // CHECK-NEXT: int k = A->x + elem.x; - - dependent v; - for (dependent::iterator it = v.begin(), e = v.end(); - it != e; ++it) { - printf("Fibonacci number is %d\n", *it); - } - // CHECK: for (auto & elem : v) { - // CHECK-NEXT: printf("Fibonacci number is %d\n", elem); - - for (dependent::iterator it(v.begin()), e = v.end(); - it != e; ++it) { - printf("Fibonacci number is %d\n", *it); - } - // CHECK: for (auto & elem : v) { - // CHECK-NEXT: printf("Fibonacci number is %d\n", elem); - - doublyDependent intmap; - for (doublyDependent::iterator it = intmap.begin(), e = intmap.end(); - it != e; ++it) { - printf("intmap[%d] = %d", it->first, it->second); - } - // CHECK: for (auto & elem : intmap) - // CHECK-NEXT: printf("intmap[%d] = %d", elem.first, elem.second); - - // PtrSet's iterator dereferences by value so auto & can't be used. - { - PtrSet int_ptrs; - for (PtrSet::iterator I = int_ptrs.begin(), - E = int_ptrs.end(); I != E; ++I) { - // CHECK: for (auto && int_ptr : int_ptrs) { - } - } - - // This container uses an iterator where the derefence type is a typedef of - // a reference type. Make sure non-const auto & is still used. A failure here - // means canonical types aren't being tested. - { - TypedefDerefContainer int_ptrs; - for (TypedefDerefContainer::iterator I = int_ptrs.begin(), - E = int_ptrs.end(); I != E; ++I) { - // CHECK: for (auto & int_ptr : int_ptrs) { - } - } - - { - // Iterators returning an rvalue reference should disqualify the loop from - // transformation. - RValueDerefContainer container; - for (RValueDerefContainer::iterator I = container.begin(), - E = container.end(); I != E; ++I) { - // CHECK: for (RValueDerefContainer::iterator I = container.begin(), - // CHECK-NEXT: E = container.end(); I != E; ++I) { - } - } -} - -// Tests to verify the proper use of auto where the init variable type and the -// initializer type differ or are mostly the same except for const qualifiers. -void different_type() { - // s.begin() returns a type 'iterator' which is just a non-const pointer and - // differs from const_iterator only on the const qualification. - S s; - for (S::const_iterator it = s.begin(), e = s.end(); it != e; ++it) { - printf("s has value %d\n", (*it).x); - } - // CHECK: for (const auto & elem : s) - // CHECK-NEXT: printf("s has value %d\n", (elem).x); - - S *ps; - for (S::const_iterator it = ps->begin(), e = ps->end(); it != e; ++it) { - printf("s has value %d\n", (*it).x); - } - // CHECK: for (const auto & p : *ps) - // CHECK-NEXT: printf("s has value %d\n", (p).x); - - // v.begin() returns a user-defined type 'iterator' which, since it's - // different from const_iterator, disqualifies these loops from - // transformation. - dependent v; - for (dependent::const_iterator it = v.begin(), e = v.end(); - it != e; ++it) { - printf("Fibonacci number is %d\n", *it); - } - // CHECK: for (dependent::const_iterator it = v.begin(), e = v.end(); - // CHECK-NEXT: it != e; ++it) { - // CHECK-NEXT: printf("Fibonacci number is %d\n", *it); - - for (dependent::const_iterator it(v.begin()), e = v.end(); - it != e; ++it) { - printf("Fibonacci number is %d\n", *it); - } - // CHECK: for (dependent::const_iterator it(v.begin()), e = v.end(); - // CHECK-NEXT: it != e; ++it) { - // CHECK-NEXT: printf("Fibonacci number is %d\n", *it); -} - -// Tests to ensure that an implicit 'this' is picked up as the container. -// If member calls are made to 'this' within the loop, the transform becomes -// risky as these calls may affect state that affects the loop. -class C { -public: - typedef MutableVal *iterator; - typedef const MutableVal *const_iterator; - - iterator begin(); - iterator end(); - const_iterator begin() const; - const_iterator end() const; - - void doSomething(); - void doSomething() const; - - void doLoop() { - for (iterator I = begin(), E = end(); I != E; ++I) { - // CHECK: for (auto & elem : *this) { - } - for (iterator I = C::begin(), E = C::end(); I != E; ++I) { - // CHECK: for (auto & elem : *this) { - } - for (iterator I = begin(), E = end(); I != E; ++I) { - // CHECK: for (iterator I = begin(), E = end(); I != E; ++I) { - // RISKY: for (auto & elem : *this) { - doSomething(); - } - for (iterator I = begin(); I != end(); ++I) { - // CHECK: for (auto & elem : *this) { - } - for (iterator I = begin(); I != end(); ++I) { - // CHECK: for (iterator I = begin(); I != end(); ++I) { - // RISKY: for (auto & elem : *this) { - doSomething(); - } - } - - void doLoop() const { - for (const_iterator I = begin(), E = end(); I != E; ++I) { - // CHECK: for (auto & elem : *this) { - } - for (const_iterator I = C::begin(), E = C::end(); I != E; ++I) { - // CHECK: for (auto & elem : *this) { - } - for (const_iterator I = begin(), E = end(); I != E; ++I) { - // CHECK: for (const_iterator I = begin(), E = end(); I != E; ++I) { - // RISKY: for (auto & elem : *this) { - doSomething(); - } - } -}; - -class C2 { -public: - typedef MutableVal *iterator; - - iterator begin() const; - iterator end() const; - - void doLoop() { - // The implicit 'this' will have an Implicit cast to const C2* wrapped - // around it. Make sure the replacement still happens. - for (iterator I = begin(), E = end(); I != E; ++I) { - // CHECK: for (auto & elem : *this) { - } - } -}; Index: test/clang-modernize/LoopConvert/macro_problem.cpp =================================================================== --- test/clang-modernize/LoopConvert/macro_problem.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: cp %t.cpp %t.base -// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// See PR15589 for why this test fails. -// XFAIL: * - -#include "macro_problem.h" -#include "structures.h" - -void side_effect(const myns::MyType &T); - -void f() { - TypedefDerefContainer container; - for (TypedefDerefContainer::iterator I = container.begin(), - E = container.end(); I != E; ++I) { - myns::MyType &alias = *I; - // CHECK: myns::MyType &ref = *I; - side_effect(ref); - } -} Index: test/clang-modernize/LoopConvert/naming-alias.cpp =================================================================== --- test/clang-modernize/LoopConvert/naming-alias.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s - -#include "structures.h" - -const int N = 10; - -Val Arr[N]; -dependent v; -dependent *pv; -Val &func(Val &); -void sideEffect(int); - -void aliasing() { - // If the loop container is only used for a declaration of a temporary - // variable to hold each element, we can name the new variable for the - // converted range-based loop as the temporary variable's name. - - // In the following case, "t" is used as a temporary variable to hold each - // element, and thus we consider the name "t" aliased to the loop. - // The extra blank braces are left as a placeholder for after the variable - // declaration is deleted. - for (int i = 0; i < N; ++i) { - Val &t = Arr[i]; { } - int y = t.x; - } - // CHECK: for (auto & t : Arr) - // CHECK-NOT: Val &{{[a-z_]+}} = - // CHECK-NEXT: { } - // CHECK-NEXT: int y = t.x; - - // The container was not only used to initialize a temporary loop variable for - // the container's elements, so we do not alias the new loop variable. - for (int i = 0; i < N; ++i) { - Val &t = Arr[i]; - int y = t.x; - int z = Arr[i].x + t.x; - } - // CHECK: for (auto & elem : Arr) - // CHECK-NEXT: Val &t = elem; - // CHECK-NEXT: int y = t.x; - // CHECK-NEXT: int z = elem.x + t.x; - - for (int i = 0; i < N; ++i) { - Val t = Arr[i]; - int y = t.x; - int z = Arr[i].x + t.x; - } - // CHECK: for (auto & elem : Arr) - // CHECK-NEXT: Val t = elem; - // CHECK-NEXT: int y = t.x; - // CHECK-NEXT: int z = elem.x + t.x; - - // The same for pseudo-arrays like std::vector (or here dependent) - // which provide a subscript operator[]. - for (int i = 0; i < v.size(); ++i) { - Val &t = v[i]; { } - int y = t.x; - } - // CHECK: for (auto & t : v) - // CHECK-NEXT: { } - // CHECK-NEXT: int y = t.x; - - // The same with a call to at() - for (int i = 0; i < pv->size(); ++i) { - Val &t = pv->at(i); { } - int y = t.x; - } - // CHECK: for (auto & t : *pv) - // CHECK-NEXT: { } - // CHECK-NEXT: int y = t.x; - - for (int i = 0; i < N; ++i) { - Val &t = func(Arr[i]); - int y = t.x; - } - // CHECK: for (auto & elem : Arr) - // CHECK-NEXT: Val &t = func(elem); - // CHECK-NEXT: int y = t.x; - - int IntArr[N]; - for (unsigned i = 0; i < N; ++i) { - if (int alias = IntArr[i]) { - sideEffect(alias); - } - } - // CHECK: for (auto alias : IntArr) - // CHECK-NEXT: if (alias) { - - for (unsigned i = 0; i < N; ++i) { - while (int alias = IntArr[i]) { - sideEffect(alias); - } - } - // CHECK: for (auto alias : IntArr) - // CHECK-NEXT: while (alias) { - - for (unsigned i = 0; i < N; ++i) { - switch (int alias = IntArr[i]) { - default: - sideEffect(alias); - } - } - // CHECK: for (auto alias : IntArr) - // CHECK-NEXT: switch (alias) { - - for (unsigned i = 0; i < N; ++i) { - for (int alias = IntArr[i]; alias < N; ++alias) { - sideEffect(alias); - } - } - // CHECK: for (auto alias : IntArr) - // CHECK-NEXT: for (; alias < N; ++alias) { - - for (unsigned i = 0; i < N; ++i) { - for (unsigned j = 0; int alias = IntArr[i]; ++j) { - sideEffect(alias); - } - } - // CHECK: for (auto alias : IntArr) - // CHECK-NEXT: for (unsigned j = 0; alias; ++j) { -} - -void refs_and_vals() { - // The following tests check that the transform correctly preserves the - // reference or value qualifiers of the aliased variable. That is, if the - // variable was declared as a value, the loop variable will be declared as a - // value and vice versa for references. - - S s; - const S s_const = s; - - for (S::const_iterator it = s_const.begin(); it != s_const.end(); ++it) { - MutableVal alias = *it; { } - alias.x = 0; - } - // CHECK: for (auto alias : s_const) - // CHECK-NOT: MutableVal {{[a-z_]+}} = - // CHECK-NEXT: { } - // CHECK-NEXT: alias.x = 0; - - for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) { - MutableVal alias = *it; { } - alias.x = 0; - } - // CHECK: for (auto alias : s) - // CHECK-NOT: MutableVal {{[a-z_]+}} = - // CHECK-NEXT: { } - // CHECK-NEXT: alias.x = 0; - - for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) { - MutableVal &alias = *it; { } - alias.x = 0; - } - // CHECK: for (auto & alias : s) - // CHECK-NOT: MutableVal &{{[a-z_]+}} = - // CHECK-NEXT: { } - // CHECK-NEXT: alias.x = 0; -} Index: test/clang-modernize/LoopConvert/naming-conflict.cpp =================================================================== --- test/clang-modernize/LoopConvert/naming-conflict.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s - -#include "structures.h" - -#define MAX(a,b) (a > b) ? a : b -#define DEF 5 - -const int N = 10; -int nums[N]; -int sum = 0; - -namespace ns { - struct st { - int x; - }; -} - -void sameNames() { - int num = 0; - for (int i = 0; i < N; ++i) { - printf("Fibonacci number is %d\n", nums[i]); - sum += nums[i] + 2 + num; - (void) nums[i]; - } - // CHECK: for (auto & nums_i : nums) - // CHECK-NEXT: printf("Fibonacci number is %d\n", nums_i); - // CHECK-NEXT: sum += nums_i + 2 + num; - // CHECK-NOT: (void) num; -} - -void macroConflict() { - S MAXs; - for (S::iterator it = MAXs.begin(), e = MAXs.end(); it != e; ++it) { - printf("s has value %d\n", (*it).x); - printf("Max of 3 and 5: %d\n", MAX(3,5)); - } - // CHECK: for (auto & MAXs_it : MAXs) - // CHECK-NEXT: printf("s has value %d\n", (MAXs_it).x); - // CHECK-NEXT: printf("Max of 3 and 5: %d\n", MAX(3,5)); - - for (S::const_iterator it = MAXs.begin(), e = MAXs.end(); it != e; ++it) { - printf("s has value %d\n", (*it).x); - printf("Max of 3 and 5: %d\n", MAX(3,5)); - } - // CHECK: for (const auto & MAXs_it : MAXs) - // CHECK-NEXT: printf("s has value %d\n", (MAXs_it).x); - // CHECK-NEXT: printf("Max of 3 and 5: %d\n", MAX(3,5)); - - T DEFs; - for (T::iterator it = DEFs.begin(), e = DEFs.end(); it != e; ++it) { - if (*it == DEF) { - printf("I found %d\n", *it); - } - } - // CHECK: for (auto & DEFs_it : DEFs) - // CHECK-NEXT: if (DEFs_it == DEF) { - // CHECK-NEXT: printf("I found %d\n", DEFs_it); -} - -void keywordConflict() { - T ints; - for (T::iterator it = ints.begin(), e = ints.end(); it != e; ++it) { - *it = 5; - } - // CHECK: for (auto & ints_it : ints) - // CHECK-NEXT: ints_it = 5; - - U __FUNCTION__s; - for (U::iterator it = __FUNCTION__s.begin(), e = __FUNCTION__s.end(); - it != e; ++it) { - int __FUNCTION__s_it = (*it).x + 2; - } - // CHECK: for (auto & __FUNCTION__s_elem : __FUNCTION__s) - // CHECK-NEXT: int __FUNCTION__s_it = (__FUNCTION__s_elem).x + 2; -} - -void typeConflict() { - T Vals; - // Using the name "Val", although it is the name of an existing struct, is - // safe in this loop since it will only exist within this scope. - for (T::iterator it = Vals.begin(), e = Vals.end(); it != e; ++it) { - } - // CHECK: for (auto & Val : Vals) - - // We cannot use the name "Val" in this loop since there is a reference to - // it in the body of the loop. - for (T::iterator it = Vals.begin(), e = Vals.end(); it != e; ++it) { - *it = sizeof(Val); - } - // CHECK: for (auto & Vals_it : Vals) - // CHECK-NEXT: Vals_it = sizeof(Val); - - typedef struct Val TD; - U TDs; - // Naming the variable "TD" within this loop is safe because the typedef - // was never used within the loop. - for (U::iterator it = TDs.begin(), e = TDs.end(); it != e; ++it) { - } - // CHECK: for (auto & TD : TDs) - - // "TD" cannot be used in this loop since the typedef is being used. - for (U::iterator it = TDs.begin(), e = TDs.end(); it != e; ++it) { - TD V; - V.x = 5; - } - // CHECK: for (auto & TDs_it : TDs) - // CHECK-NEXT: TD V; - // CHECK-NEXT: V.x = 5; - - using ns::st; - T sts; - for (T::iterator it = sts.begin(), e = sts.end(); it != e; ++it) { - *it = sizeof(st); - } - // CHECK: for (auto & sts_it : sts) - // CHECK-NEXT: sts_it = sizeof(st); -} Index: test/clang-modernize/LoopConvert/negative-iterator.cpp =================================================================== --- test/clang-modernize/LoopConvert/negative-iterator.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s - -#include "structures.h" - -// Single FileCheck line to make sure that no loops are converted. -// CHECK-NOT: for ({{.*[^:]:[^:].*}}) - -S s; -T t; -U u; - -struct BadBeginEnd : T { - iterator notBegin(); - iterator notEnd(); -}; - -void notBeginOrEnd() { - BadBeginEnd Bad; - for (T::iterator i = Bad.notBegin(), e = Bad.end(); i != e; ++i) - int k = *i; - - for (T::iterator i = Bad.begin(), e = Bad.notEnd(); i != e; ++i) - int k = *i; -} - -void badLoopShapes() { - for (T::iterator i = t.begin(), e = t.end(), f = e; i != e; ++i) - int k = *i; - - for (T::iterator i = t.begin(), e = t.end(); i != e; ) - int k = *i; - - for (T::iterator i = t.begin(), e = t.end(); ; ++i) - int k = *i; - - T::iterator outsideI; - T::iterator outsideE; - - for (; outsideI != outsideE ; ++outsideI) - int k = *outsideI; -} - -void iteratorArrayMix() { - int lower; - const int N = 6; - for (T::iterator i = t.begin(), e = t.end(); lower < N; ++i) - int k = *i; - - for (T::iterator i = t.begin(), e = t.end(); lower < N; ++lower) - int k = *i; -} - -struct ExtraConstructor : T::iterator { - ExtraConstructor(T::iterator, int); - explicit ExtraConstructor(T::iterator); -}; - -void badConstructor() { - for (T::iterator i = ExtraConstructor(t.begin(), 0), e = t.end(); - i != e; ++i) - int k = *i; - for (T::iterator i = ExtraConstructor(t.begin()), e = t.end(); i != e; ++i) - int k = *i; -} - -void iteratorMemberUsed() { - for (T::iterator i = t.begin(), e = t.end(); i != e; ++i) - i.x = *i; - - for (T::iterator i = t.begin(), e = t.end(); i != e; ++i) - int k = i.x + *i; - - for (T::iterator i = t.begin(), e = t.end(); i != e; ++i) - int k = e.x + *i; -} - -void iteratorMethodCalled() { - for (T::iterator i = t.begin(), e = t.end(); i != e; ++i) - i.insert(3); - - for (T::iterator i = t.begin(), e = t.end(); i != e; ++i) - if (i != i) - int k = 3; -} - -void iteratorOperatorCalled() { - for (T::iterator i = t.begin(), e = t.end(); i != e; ++i) - int k = *(++i); - - for (S::iterator i = s.begin(), e = s.end(); i != e; ++i) - MutableVal k = *(++i); -} - -void differentContainers() { - T other; - for (T::iterator i = t.begin(), e = other.end(); i != e; ++i) - int k = *i; - - for (T::iterator i = other.begin(), e = t.end(); i != e; ++i) - int k = *i; - - S otherS; - for (S::iterator i = s.begin(), e = otherS.end(); i != e; ++i) - MutableVal k = *i; - - for (S::iterator i = otherS.begin(), e = s.end(); i != e; ++i) - MutableVal k = *i; -} - -void wrongIterators() { - T::iterator other; - for (T::iterator i = t.begin(), e = t.end(); i != other; ++i) - int k = *i; -} - -struct EvilArrow : U { - // Please, no one ever write code like this. - U* operator->(); -}; - -void differentMemberAccessTypes() { - EvilArrow A; - for (EvilArrow::iterator i = A.begin(), e = A->end(); i != e; ++i) - Val k = *i; - for (EvilArrow::iterator i = A->begin(), e = A.end(); i != e; ++i) - Val k = *i; -} - -void f(const T::iterator &it, int); -void f(const T &it, int); -void g(T &it, int); - -void iteratorPassedToFunction() { - for (T::iterator i = t.begin(), e = t.end(); i != e; ++i) - f(i, *i); -} - -// FIXME: Disallow this except for containers passed by value and/or const -// reference. Or maybe this is correct enough for any container? -void containerPassedToFunction() { -// for (T::iterator i = t.begin(), e = t.end(); i != e; ++i) -// f(t, *i); -// for (T::iterator i = t.begin(), e = t.end(); i != e; ++i) -// g(t, *i); -} - -// FIXME: These tests can be removed if this tool ever does enough analysis to -// decide that this is a safe transformation. -// Until then, we don't want it applied. -void iteratorDefinedOutside() { - T::iterator theEnd = t.end(); - for (T::iterator i = t.begin(); i != theEnd; ++i) - int k = *i; - - T::iterator theBegin = t.begin(); - for (T::iterator e = t.end(); theBegin != e; ++theBegin) - int k = *theBegin; -} Index: test/clang-modernize/LoopConvert/negative-multi-end-call.cpp =================================================================== --- test/clang-modernize/LoopConvert/negative-multi-end-call.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -loop-convert -risk=safe %t.cpp -- -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s - -#include "structures.h" - -// Single FileCheck line to make sure that no loops are converted. -// CHECK-NOT: for ({{.*[^:]:[^:].*}}) - -S s; -T t; -U u; - -void multipleEnd() { - for (S::iterator i = s.begin(); i != s.end(); ++i) - MutableVal k = *i; - - for (T::iterator i = t.begin(); i != t.end(); ++i) - int k = *i; - - for (U::iterator i = u.begin(); i != u.end(); ++i) - Val k = *i; -} - -void f(X); -void f(S); -void f(T); - -void complexContainer() { - X x; - for (S::iterator i = x.s.begin(), e = x.s.end(); i != e; ++i) { - f(x); - MutableVal k = *i; - } - - for (T::iterator i = x.t.begin(), e = x.t.end(); i != e; ++i) { - f(x); - int k = *i; - } - - for (S::iterator i = x.s.begin(), e = x.s.end(); i != e; ++i) { - f(x.s); - MutableVal k = *i; - } - - for (T::iterator i = x.t.begin(), e = x.t.end(); i != e; ++i) { - f(x.t); - int k = *i; - } - - for (S::iterator i = x.getS().begin(), e = x.getS().end(); i != e; ++i) { - f(x.getS()); - MutableVal k = *i; - } - - X exes[5]; - int index = 0; - - for (S::iterator i = exes[index].getS().begin(), - e = exes[index].getS().end(); i != e; ++i) { - index++; - MutableVal k = *i; - } -} Index: test/clang-modernize/LoopConvert/negative-pseudoarray-extra.cpp =================================================================== --- test/clang-modernize/LoopConvert/negative-pseudoarray-extra.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s - -#include "structures.h" - -// Single FileCheck line to make sure that no loops are converted. -// CHECK-NOT: for ({{.*[^:]:[^:].*}}) - -const int N = 6; -dependent v; -dependent *pv; - -int sum = 0; - -// Checks to see that non-const member functions are not called on the container -// object. -// These could be conceivably allowed with a lower required confidence level. -void memberFunctionCalled() { - for (int i = 0; i < v.size(); ++i) { - sum += v[i]; - v.foo(); - } - - for (int i = 0; i < v.size(); ++i) { - sum += v[i]; - dependent::iterator it = v.begin(); - } -} Index: test/clang-modernize/LoopConvert/negative-pseudoarray.cpp =================================================================== --- test/clang-modernize/LoopConvert/negative-pseudoarray.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s - -#include "structures.h" - -// Single FileCheck line to make sure that no loops are converted. -// CHECK-NOT: for ({{.*[^:]:[^:].*}}) - -const int N = 6; -dependent v; -dependent *pv; - -transparent > cv; -int sum = 0; - -// Checks for the index start and end: -void indexStartAndEnd() { - for (int i = 0; i < v.size() + 1; ++i) - sum += v[i]; - - for (int i = 0; i < v.size() - 1; ++i) - sum += v[i]; - - for (int i = 1; i < v.size(); ++i) - sum += v[i]; - - for (int i = 1; i < v.size(); ++i) - sum += v[i]; - - for (int i = 0; ; ++i) - sum += (*pv)[i]; -} - -// Checks for invalid increment steps: -void increment() { - for (int i = 0; i < v.size(); --i) - sum += v[i]; - - for (int i = 0; i < v.size(); i) - sum += v[i]; - - for (int i = 0; i < v.size();) - sum += v[i]; - - for (int i = 0; i < v.size(); i += 2) - sum ++; -} - -// Checks to make sure that the index isn't used outside of the container: -void indexUse() { - for (int i = 0; i < v.size(); ++i) - v[i] += 1 + i; -} - -// Checks for incorrect loop variables. -void mixedVariables() { - int badIndex; - for (int i = 0; badIndex < v.size(); ++i) - sum += v[i]; - - for (int i = 0; i < v.size(); ++badIndex) - sum += v[i]; - - for (int i = 0; badIndex < v.size(); ++badIndex) - sum += v[i]; - - for (int i = 0; badIndex < v.size(); ++badIndex) - sum += v[badIndex]; -} - -// Checks for an array indexed in addition to the container. -void multipleArrays() { - int badArr[N]; - - for (int i = 0; i < v.size(); ++i) - sum += v[i] + badArr[i]; - - for (int i = 0; i < v.size(); ++i) - sum += badArr[i]; - - for (int i = 0; i < v.size(); ++i) { - int k = badArr[i]; - sum += k + 2; - } - - for (int i = 0; i < v.size(); ++i) { - int k = badArr[i]; - sum += v[i] + k; - } -} - -// Checks for multiple containers being indexed container. -void multipleContainers() { - dependent badArr; - - for (int i = 0; i < v.size(); ++i) - sum += v[i] + badArr[i]; - - for (int i = 0; i < v.size(); ++i) - sum += badArr[i]; - - for (int i = 0; i < v.size(); ++i) { - int k = badArr[i]; - sum += k + 2; - } - - for (int i = 0; i < v.size(); ++i) { - int k = badArr[i]; - sum += v[i] + k; - } -} - -// Check to make sure that dereferenced pointers-to-containers behave nicely -void derefContainer() { - // Note the dependent::operator*() returns another dependent. - // This test makes sure that we don't allow an arbitrary number of *'s. - for (int i = 0; i < pv->size(); ++i) - sum += (**pv).at(i); - - for (int i = 0; i < pv->size(); ++i) - sum += (**pv)[i]; -} - -void wrongEnd() { - int bad; - for (int i = 0, e = v.size(); i < bad; ++i) - sum += v[i]; -} Index: test/clang-modernize/LoopConvert/negative.cpp =================================================================== --- test/clang-modernize/LoopConvert/negative.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/negative-header.h > \ -// RUN: %T/negative-header.h -// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs/ -// RUN: FileCheck -input-file=%t.cpp %s -// RUN: FileCheck -input-file=%T/negative-header.h %S/Inputs/negative-header.h - -#include "negative-header.h" -#include "structures.h" - -// Single FileCheck line to make sure that no loops are converted. -// CHECK-NOT: for ({{.*[^:]:[^:].*}}) - -const int N = 6; -int arr[N] = {1, 2, 3, 4, 5, 6}; -int (*pArr)[N] = &arr; -int sum = 0; - -// Checks for the index start and end: -void indexStartAndEnd() { - for (int i = 0; i < N + 1; ++i) - sum += arr[i]; - - for (int i = 0; i < N - 1; ++i) - sum += arr[i]; - - for (int i = 1; i < N; ++i) - sum += arr[i]; - - for (int i = 1; i < N; ++i) - sum += arr[i]; - - for (int i = 0; ; ++i) - sum += (*pArr)[i]; -} - -// Checks for invalid increment steps: -void increment() { - for (int i = 0; i < N; --i) - sum += arr[i]; - - for (int i = 0; i < N; i) - sum += arr[i]; - - for (int i = 0; i < N;) - sum += arr[i]; - - for (int i = 0; i < N; i += 2) - sum ++; -} - -// Checks to make sure that the index isn't used outside of the array: -void indexUse() { - for (int i = 0; i < N; ++i) - arr[i] += 1 + i; -} - -// Check for loops that don't mention arrays -void noArray() { - for (int i = 0; i < N; ++i) - sum += i; - - for (int i = 0; i < N; ++i) { } - - for (int i = 0; i < N; ++i) ; -} - -// Checks for incorrect loop variables. -void mixedVariables() { - int badIndex; - for (int i = 0; badIndex < N; ++i) - sum += arr[i]; - - for (int i = 0; i < N; ++badIndex) - sum += arr[i]; - - for (int i = 0; badIndex < N; ++badIndex) - sum += arr[i]; - - for (int i = 0; badIndex < N; ++badIndex) - sum += arr[badIndex]; -} - -// Checks for multiple arrays indexed. -void multipleArrays() { - int badArr[N]; - - for (int i = 0; i < N; ++i) - sum += arr[i] + badArr[i]; - - for (int i = 0; i < N; ++i) { - int k = badArr[i]; - sum += arr[i] + k; - } -} - -struct HasArr { - int Arr[N]; - Val ValArr[N]; -}; - -struct HasIndirectArr { - HasArr HA; - void implicitThis() { - for (int i = 0; i < N; ++i) { - printf("%d", HA.Arr[i]); - } - - for (int i = 0; i < N; ++i) { - printf("%d", HA.ValArr[i].x); - } - } - - void explicitThis() { - for (int i = 0; i < N; ++i) { - printf("%d", this->HA.Arr[i]); - } - - for (int i = 0; i < N; ++i) { - printf("%d", this->HA.ValArr[i].x); - } - } -}; Index: test/clang-modernize/LoopConvert/nesting.cpp =================================================================== --- test/clang-modernize/LoopConvert/nesting.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s - -#include "structures.h" - -void f() { - const int N = 10; - const int M = 15; - Val Arr[N]; - for (int i = 0; i < N; ++i) { - for (int j = 0; j < N; ++j) { - int k = Arr[i].x + Arr[j].x; - // The repeat is there to allow FileCheck to make sure the two variable - // names aren't the same. - int l = Arr[i].x + Arr[j].x; - } - } - // CHECK: for (auto & elem : Arr) - // CHECK-NEXT: for (auto & Arr_j : Arr) - // CHECK-NEXT: int k = elem.x + Arr_j.x; - // CHECK-NOT: int l = elem.x + elem.x; - - Val Nest[N][M]; - for (int i = 0; i < N; ++i) { - for (int j = 0; j < M; ++j) { - printf("Got item %d", Nest[i][j].x); - } - } - // The inner loop is also convertible, but doesn't need to be converted - // immediately. Update this test when that changes! - // CHECK: for (auto & elem : Nest) - // CHECK-NEXT: for (int j = 0; j < M; ++j) - // CHECK-NEXT: printf("Got item %d", elem[j].x); - - // Note that the order of M and N are switched for this test. - for (int j = 0; j < M; ++j) { - for (int i = 0; i < N; ++i) { - printf("Got item %d", Nest[i][j].x); - } - } - // CHECK-NOT: for (auto & {{[a-zA-Z_]+}} : Nest[i]) - // CHECK: for (int j = 0; j < M; ++j) - // CHECK-NEXT: for (auto & elem : Nest) - // CHECK-NEXT: printf("Got item %d", elem[j].x); - Nested NestT; - for (Nested::iterator I = NestT.begin(), E = NestT.end(); I != E; ++I) { - for (T::iterator TI = (*I).begin(), TE = (*I).end(); TI != TE; ++TI) { - printf("%d", *TI); - } - } - // The inner loop is also convertible, but doesn't need to be converted - // immediately. Update this test when that changes! - // CHECK: for (auto & elem : NestT) { - // CHECK-NEXT: for (T::iterator TI = (elem).begin(), TE = (elem).end(); TI != TE; ++TI) { - // CHECK-NEXT: printf("%d", *TI); - - Nested NestS; - for (Nested::const_iterator I = NestS.begin(), E = NestS.end(); I != E; ++I) { - for (S::const_iterator SI = (*I).begin(), SE = (*I).end(); SI != SE; ++SI) { - printf("%d", *SI); - } - } - // The inner loop is also convertible, but doesn't need to be converted - // immediately. Update this test when that changes! - // CHECK: for (const auto & elem : NestS) { - // CHECK-NEXT: for (S::const_iterator SI = (elem).begin(), SE = (elem).end(); SI != SE; ++SI) { - // CHECK-NEXT: printf("%d", *SI); -} Index: test/clang-modernize/LoopConvert/nocompile.cpp =================================================================== --- test/clang-modernize/LoopConvert/nocompile.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: not clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s - -void valid() { - const int arr[5]; - int sum = 0; - for (int i = 0; i < 5; ++i) { - sum += arr[i]; - } -} -void hasSyntaxError = 3; -// CHECK: void valid() { -// CHECK-NEXT: const int arr[5]; -// CHECK-NEXT: int sum = 0; -// CHECK-NEXT: for (int i = 0; i < 5; ++i) { -// CHECK-NEXT: sum += arr[i]; -// CHECK-NEXT: } -// CHECK-NEXT: } - -// CHECK-NEXT: void hasSyntaxError = 3; Index: test/clang-modernize/LoopConvert/pseudoarray.cpp =================================================================== --- test/clang-modernize/LoopConvert/pseudoarray.cpp +++ /dev/null @@ -1,105 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -std=c++11 -// RUN: FileCheck -input-file=%t.cpp %s -#include "structures.h" - -const int N = 6; -dependent v; -dependent *pv; - -transparent > cv; - -void f() { - int sum = 0; - for (int i = 0, e = v.size(); i < e; ++i) { - printf("Fibonacci number is %d\n", v[i]); - sum += v[i] + 2; - } - // CHECK: for (auto & elem : v) - // CHECK-NEXT: printf("Fibonacci number is %d\n", elem); - // CHECK-NEXT: sum += elem + 2; - - for (int i = 0, e = v.size(); i < e; ++i) { - printf("Fibonacci number is %d\n", v.at(i)); - sum += v.at(i) + 2; - } - // CHECK: for (auto & elem : v) - // CHECK-NEXT: printf("Fibonacci number is %d\n", elem); - // CHECK-NEXT: sum += elem + 2; - - for (int i = 0, e = pv->size(); i < e; ++i) { - printf("Fibonacci number is %d\n", pv->at(i)); - sum += pv->at(i) + 2; - } - // CHECK: for (auto & elem : *pv) - // CHECK-NEXT: printf("Fibonacci number is %d\n", elem); - // CHECK-NEXT: sum += elem + 2; - - // This test will fail if size() isn't called repeatedly, since it - // returns unsigned int, and 0 is deduced to be signed int. - // FIXME: Insert the necessary explicit conversion, or write out the types - // explicitly. - for (int i = 0; i < pv->size(); ++i) { - printf("Fibonacci number is %d\n", (*pv).at(i)); - sum += (*pv)[i] + 2; - } - // CHECK: for (auto & elem : *pv) - // CHECK-NEXT: printf("Fibonacci number is %d\n", elem); - // CHECK-NEXT: sum += elem + 2; - - for (int i = 0; i < cv->size(); ++i) { - printf("Fibonacci number is %d\n", cv->at(i)); - sum += cv->at(i) + 2; - } - // CHECK: for (auto & elem : *cv) - // CHECK-NEXT: printf("Fibonacci number is %d\n", elem); - // CHECK-NEXT: sum += elem + 2; -} - -// Check for loops that don't mention containers -void noContainer() { - for (auto i = 0; i < v.size(); ++i) { } - // CHECK: for (auto & elem : v) { } - - for (auto i = 0; i < v.size(); ++i) ; - // CHECK: for (auto & elem : v) ; -} - -struct NoBeginEnd { - unsigned size() const; -}; - -struct NoConstBeginEnd { - NoConstBeginEnd(); - unsigned size() const; - unsigned begin(); - unsigned end(); -}; - -struct ConstBeginEnd { - ConstBeginEnd(); - unsigned size() const; - unsigned begin() const; - unsigned end() const; -}; - -// Shouldn't transform pseudo-array uses if the container doesn't provide -// begin() and end() of the right const-ness. -void NoBeginEndTest() { - NoBeginEnd NBE; - for (unsigned i = 0, e = NBE.size(); i < e; ++i) {} - // CHECK: for (unsigned i = 0, e = NBE.size(); i < e; ++i) {} - - const NoConstBeginEnd const_NCBE; - for (unsigned i = 0, e = const_NCBE.size(); i < e; ++i) {} - // CHECK: for (unsigned i = 0, e = const_NCBE.size(); i < e; ++i) {} - - ConstBeginEnd CBE; - for (unsigned i = 0, e = CBE.size(); i < e; ++i) {} - // CHECK: for (auto & elem : CBE) {} - - const ConstBeginEnd const_CBE; - for (unsigned i = 0, e = const_CBE.size(); i < e; ++i) {} - // CHECK: for (auto & elem : const_CBE) {} -} - Index: test/clang-modernize/LoopConvert/single-iterator.cpp =================================================================== --- test/clang-modernize/LoopConvert/single-iterator.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -loop-convert %t.cpp -- -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s - -#include "structures.h" - -void complexContainer() { - X exes[5]; - int index = 0; - - for (S::iterator i = exes[index].getS().begin(), e = exes[index].getS().end(); i != e; ++i) { - MutableVal k = *i; - MutableVal j = *i; - } - // CHECK: for (auto & elem : exes[index].getS()) - // CHECK-NEXT: MutableVal k = elem; - // CHECK-NEXT: MutableVal j = elem; -} - -void f() { - /// begin()/end() - based for loops here: - T t; - for (T::iterator it = t.begin(); it != t.end(); ++it) { - printf("I found %d\n", *it); - } - // CHECK: for (auto & elem : t) - // CHECK-NEXT: printf("I found %d\n", elem); - - T *pt; - for (T::iterator it = pt->begin(); it != pt->end(); ++it) { - printf("I found %d\n", *it); - } - // CHECK: for (auto & elem : *pt) - // CHECK-NEXT: printf("I found %d\n", elem); - - S s; - for (S::iterator it = s.begin(); it != s.end(); ++it) { - printf("s has value %d\n", (*it).x); - } - // CHECK: for (auto & elem : s) - // CHECK-NEXT: printf("s has value %d\n", (elem).x); - - S *ps; - for (S::iterator it = ps->begin(); it != ps->end(); ++it) { - printf("s has value %d\n", (*it).x); - } - // CHECK: for (auto & p : *ps) - // CHECK-NEXT: printf("s has value %d\n", (p).x); - - for (S::iterator it = s.begin(); it != s.end(); ++it) { - printf("s has value %d\n", it->x); - } - // CHECK: for (auto & elem : s) - // CHECK-NEXT: printf("s has value %d\n", elem.x); - - for (S::iterator it = s.begin(); it != s.end(); ++it) { - it->x = 3; - } - // CHECK: for (auto & elem : s) - // CHECK-NEXT: elem.x = 3; - - for (S::iterator it = s.begin(); it != s.end(); ++it) { - (*it).x = 3; - } - // CHECK: for (auto & elem : s) - // CHECK-NEXT: (elem).x = 3; - - for (S::iterator it = s.begin(); it != s.end(); ++it) { - it->nonConstFun(4, 5); - } - // CHECK: for (auto & elem : s) - // CHECK-NEXT: elem.nonConstFun(4, 5); - - U u; - for (U::iterator it = u.begin(); it != u.end(); ++it) { - printf("s has value %d\n", it->x); - } - // CHECK: for (auto & elem : u) - // CHECK-NEXT: printf("s has value %d\n", elem.x); - - for (U::iterator it = u.begin(); it != u.end(); ++it) { - printf("s has value %d\n", (*it).x); - } - // CHECK: for (auto & elem : u) - // CHECK-NEXT: printf("s has value %d\n", (elem).x); - - U::iterator A; - for (U::iterator i = u.begin(); i != u.end(); ++i) - int k = A->x + i->x; - // CHECK: for (auto & elem : u) - // CHECK-NEXT: int k = A->x + elem.x; - - dependent v; - for (dependent::iterator it = v.begin(); - it != v.end(); ++it) { - printf("Fibonacci number is %d\n", *it); - } - // CHECK: for (auto & elem : v) { - // CHECK-NEXT: printf("Fibonacci number is %d\n", elem); - - for (dependent::iterator it(v.begin()); - it != v.end(); ++it) { - printf("Fibonacci number is %d\n", *it); - } - // CHECK: for (auto & elem : v) { - // CHECK-NEXT: printf("Fibonacci number is %d\n", elem); - - doublyDependent intmap; - for (doublyDependent::iterator it = intmap.begin(); - it != intmap.end(); ++it) { - printf("intmap[%d] = %d", it->first, it->second); - } - // CHECK: for (auto & elem : intmap) - // CHECK-NEXT: printf("intmap[%d] = %d", elem.first, elem.second); -} - -void different_type() { - // Tests to verify the proper use of auto where the init variable type and the - // initializer type differ or are mostly the same except for const qualifiers. - - // s.begin() returns a type 'iterator' which is just a non-const pointer and - // differs from const_iterator only on the const qualification. - S s; - for (S::const_iterator it = s.begin(); it != s.end(); ++it) { - printf("s has value %d\n", (*it).x); - } - // CHECK: for (const auto & elem : s) - // CHECK-NEXT: printf("s has value %d\n", (elem).x); - - S *ps; - for (S::const_iterator it = ps->begin(); it != ps->end(); ++it) { - printf("s has value %d\n", (*it).x); - } - // CHECK: for (const auto & p : *ps) - // CHECK-NEXT: printf("s has value %d\n", (p).x); - - // v.begin() returns a user-defined type 'iterator' which, since it's - // different from const_iterator, disqualifies these loops from - // transformation. - dependent v; - for (dependent::const_iterator it = v.begin(); it != v.end(); ++it) { - printf("Fibonacci number is %d\n", *it); - } - // CHECK: for (dependent::const_iterator it = v.begin(); it != v.end(); ++it) { - // CHECK-NEXT: printf("Fibonacci number is %d\n", *it); - - for (dependent::const_iterator it(v.begin()); it != v.end(); ++it) { - printf("Fibonacci number is %d\n", *it); - } - // CHECK: for (dependent::const_iterator it(v.begin()); it != v.end(); ++it) { - // CHECK-NEXT: printf("Fibonacci number is %d\n", *it); -} Index: test/clang-modernize/PassByValue/basic.h =================================================================== --- test/clang-modernize/PassByValue/basic.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef BASIC_H -#define BASIC_H - -// POD types are trivially move constructible -struct Movable { - int a, b, c; -}; - -struct NotMovable { - NotMovable() = default; - NotMovable(const NotMovable &) = default; - NotMovable(NotMovable &&) = delete; - int a, b, c; -}; - -// The test runs the migrator without header modifications enabled for this -// header making the constructor parameter M unmodifiable. -struct UnmodifiableClass { - UnmodifiableClass(const Movable &M); - Movable M; -}; - -#endif // BASIC_H Index: test/clang-modernize/PassByValue/basic.cpp =================================================================== --- test/clang-modernize/PassByValue/basic.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// Since -fdelayed-template-parsing is enabled by default on Windows (as a -// Microsoft extension), -fno-delayed-template-parsing is used for the tests in -// order to have the same behavior on all systems. -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -pass-by-value %t.cpp -- -std=c++11 -fno-delayed-template-parsing -I %S -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -pass-by-value %t.cpp -- -std=c++11 -fno-delayed-template-parsing -I %S -// RUN: FileCheck -check-prefix=SAFE_RISK -input-file=%t.cpp %s - -#include "basic.h" -// CHECK: #include - -// Test that when the class declaration can't be modified we won't modify the -// definition either. -UnmodifiableClass::UnmodifiableClass(const Movable &M) : M(M) {} -// CHECK: UnmodifiableClass::UnmodifiableClass(const Movable &M) : M(M) {} - -struct A { - A(const Movable &M) : M(M) {} - // CHECK: A(Movable M) : M(std::move(M)) {} - // SAFE_RISK: A(const Movable &M) : M(M) {} - Movable M; -}; - -// Test that we aren't modifying other things than a parameter -Movable GlobalObj; -struct B { - B(const Movable &M) : M(GlobalObj) {} - // CHECK: B(const Movable &M) : M(GlobalObj) {} - Movable M; -}; - -// Test that a parameter with more than one reference to it won't be changed. -struct C { - // Tests extra-reference in body - C(const Movable &M) : M(M) { this->i = M.a; } - // CHECK: C(const Movable &M) : M(M) { this->i = M.a; } - - // Tests extra-reference in init-list - C(const Movable &M, int) : M(M), i(M.a) {} - // CHECK: C(const Movable &M, int) : M(M), i(M.a) {} - Movable M; - int i; -}; - -// Test that both declaration and definition are updated -struct D { - D(const Movable &M); - // CHECK: D(Movable M); - Movable M; -}; -D::D(const Movable &M) : M(M) {} -// CHECK: D::D(Movable M) : M(std::move(M)) {} - -// Test with default parameter -struct E { - E(const Movable &M = Movable()) : M(M) {} - // CHECK: E(Movable M = Movable()) : M(std::move(M)) {} - Movable M; -}; - -// Test with object that can't be moved -struct F { - F(const NotMovable &NM) : NM(NM) {} - // CHECK: F(const NotMovable &NM) : NM(NM) {} - NotMovable NM; -}; - -// Test unnamed parameter in declaration -struct G { - G(const Movable &); - // CHECK: G(Movable ); - Movable M; -}; -G::G(const Movable &M) : M(M) {} -// CHECK: G::G(Movable M) : M(std::move(M)) {} - -// Test parameter with and without qualifier -namespace ns_H { -typedef ::Movable HMovable; -} -struct H { - H(const ns_H::HMovable &M); - // CHECK: H(ns_H::HMovable M); - ns_H::HMovable M; -}; -using namespace ns_H; -H::H(const HMovable &M) : M(M) {} -// CHECK: H(HMovable M) : M(std::move(M)) {} - -// Try messing up with macros -#define MOVABLE_PARAM(Name) const Movable & Name -// CHECK: #define MOVABLE_PARAM(Name) const Movable & Name -struct I { - I(MOVABLE_PARAM(M)) : M(M) {} - // CHECK: I(MOVABLE_PARAM(M)) : M(M) {} - Movable M; -}; -#undef MOVABLE_PARAM - -// Test that templates aren't modified -template struct J { - J(const T &M) : M(M) {} - // CHECK: J(const T &M) : M(M) {} - T M; -}; -J j1(Movable()); -J j2(NotMovable()); - -struct K_Movable { - K_Movable() = default; - K_Movable(const K_Movable &) = default; - K_Movable(K_Movable &&o) { dummy = o.dummy; } - int dummy; -}; - -// Test with movable type with an user defined move constructor. -struct K { - K(const K_Movable &M) : M(M) {} - // CHECK: K(K_Movable M) : M(std::move(M)) {} - K_Movable M; -}; - -template struct L { - L(const Movable &M) : M(M) {} - // CHECK: L(Movable M) : M(std::move(M)) {} - Movable M; -}; -L l(Movable()); - -// Test with a non-instantiated template class -template struct N { - N(const Movable &M) : M(M) {} - // CHECK: N(Movable M) : M(std::move(M)) {} - - Movable M; - T A; -}; - -// Test with value parameter -struct O { - O(Movable M) : M(M) {} - // CHECK: O(Movable M) : M(std::move(M)) {} - Movable M; -}; - -// Test with a const-value parameter -struct P { - P(const Movable M) : M(M) {} - // CHECK: P(const Movable M) : M(M) {} - Movable M; -}; - -// Test with multiples parameters where some need to be changed and some don't -// need to. -struct Q { - Q(const Movable &A, const Movable &B, const Movable &C, double D) - : A(A), B(B), C(C), D(D) {} - // CHECK: Q(const Movable &A, Movable B, Movable C, double D) - // CHECK-NEXT: : A(A), B(std::move(B)), C(std::move(C)), D(D) {} - const Movable &A; - Movable B; - Movable C; - double D; -}; - -// Test that value-parameters with a nested name specifier are left as-is -namespace ns_R { -typedef ::Movable RMovable; -} -struct R { - R(ns_R::RMovable M) : M(M) {} - // CHECK: R(ns_R::RMovable M) : M(std::move(M)) {} - ns_R::RMovable M; -}; - -// Test with rvalue parameter -struct S { - S(Movable &&M) : M(M) {} - // CHECK: S(Movable &&M) : M(M) {} - Movable M; -}; Index: test/clang-modernize/ReplaceAutoPtr/Inputs/basic.h =================================================================== --- test/clang-modernize/ReplaceAutoPtr/Inputs/basic.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef INPUTS_BASIC_H -#define INPUTS_BASIC_H - -#include "memory_stub.h" - -// Instrumentation for auto_ptr_ref test -// @{ -struct Base {}; -struct Derived : Base {}; -std::auto_ptr create_derived_ptr(); -// CHECK: std::unique_ptr create_derived_ptr(); -// } - -// Test function return values (declaration) -std::auto_ptr f_5(); -// CHECK: std::unique_ptr f_5() - -// Test function parameters -void f_6(std::auto_ptr); -// CHECK: void f_6(std::unique_ptr); -void f_7(const std::auto_ptr &); -// CHECK: void f_7(const std::unique_ptr &); - -// Test on record type fields -struct A { - std::auto_ptr field; - // CHECK: std::unique_ptr field; - - typedef std::auto_ptr int_ptr_type; - // CHECK: typedef std::unique_ptr int_ptr_type; -}; - -// Test template WITH instantiation -template struct B { - typedef typename std::auto_ptr created_type; - // CHECK: typedef typename std::unique_ptr created_type; - - created_type create() { return std::auto_ptr(new T()); } - // CHECK: created_type create() { return std::unique_ptr(new T()); } -}; - -// Test 'using' in a namespace (declaration) -namespace ns_1 { -// Test multiple using declarations -using std::auto_ptr; -using std::auto_ptr; -// CHECK: using std::unique_ptr; -// CHECK-NEXT: using std::unique_ptr; -} - -namespace ns_2 { -template struct auto_ptr {}; -// CHECK: template struct auto_ptr {}; -} - -#endif // INPUTS_BASIC_H Index: test/clang-modernize/ReplaceAutoPtr/Inputs/memory_stub.h =================================================================== --- test/clang-modernize/ReplaceAutoPtr/Inputs/memory_stub.h +++ /dev/null @@ -1,61 +0,0 @@ -//===-----------------------------------------------------------*- C++ -*--===// -// -// This file contains a shell implementation of the 'auto_ptr' type from the -// standard library. This shell aims to support the variations between standard -// library implementations. -// -// Variations for how 'auto_ptr' is presented: -// 1. Defined directly in namespace std -// 2. Use a versioned inline namespace in std (default on libc++). -// -// Use the preprocessor to define USE_INLINE_NAMESPACE=1 and use the second -// variation. -// -//===----------------------------------------------------------------------===// - -namespace std { - -#if USE_INLINE_NAMESPACE -inline namespace _1 { -#endif - -template struct auto_ptr_ref { - Y *y_; -}; - -template class auto_ptr { -public: - typedef X element_type; - // D.10.1.1 construct/copy/destroy: - explicit auto_ptr(X *p = 0) throw() {} - auto_ptr(auto_ptr &) throw() {} - template auto_ptr(auto_ptr &) throw() {} - auto_ptr &operator=(auto_ptr &) throw() { return *this; } - template auto_ptr &operator=(auto_ptr &) throw() { - return *this; - } - auto_ptr &operator=(auto_ptr_ref r) throw() { return *this; } - ~auto_ptr() throw() {} - // D.10.1.3 conversions: - auto_ptr(auto_ptr_ref r) throw() : x_(r.y_) {} - template operator auto_ptr_ref() throw() { - auto_ptr_ref r; - r.y_ = x_; - return r; - } - template operator auto_ptr() throw() { return auto_ptr(x_); } - -private: - X *x_; -}; - -template <> class auto_ptr { -public: - typedef void element_type; -}; - -#if USE_INLINE_NAMESPACE -} // namespace _1 -#endif - -} // end namespace std Index: test/clang-modernize/ReplaceAutoPtr/basic.cpp =================================================================== --- test/clang-modernize/ReplaceAutoPtr/basic.cpp +++ /dev/null @@ -1,154 +0,0 @@ -// RUN: mkdir -p %T/Inputs -// -// Without inline namespace: -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/basic.h > %T/Inputs/basic.h -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/memory_stub.h > %T/Inputs/memory_stub.h -// RUN: clang-modernize -include=%T -replace-auto_ptr %t.cpp -- \ -// RUN: -std=c++11 -I %T -// RUN: FileCheck -input-file=%t.cpp %s -// RUN: FileCheck -input-file=%T/Inputs/basic.h %S/Inputs/basic.h -// -// With inline namespace: -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/basic.h > %T/Inputs/basic.h -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/memory_stub.h > %T/Inputs/memory_stub.h -// RUN: clang-modernize -include=%T -replace-auto_ptr %t.cpp -- \ -// RUN: -DUSE_INLINE_NAMESPACE=1 -std=c++11 -I %T -// RUN: FileCheck -input-file=%t.cpp %s -// RUN: FileCheck -input-file=%T/Inputs/basic.h %S/Inputs/basic.h - -#include "Inputs/basic.h" - -void f_1() { - std::auto_ptr a; - // CHECK: std::unique_ptr a; - - // check that spaces aren't modified unnecessarily - std:: auto_ptr b; - // CHECK: std:: unique_ptr b; - std :: auto_ptr < char > c(new char()); - // CHECK: std :: unique_ptr < char > c(new char()); - - // Test construction from a temporary - std::auto_ptr d = std::auto_ptr(); - // CHECK: std::unique_ptr d = std::unique_ptr(); - - typedef std::auto_ptr int_ptr_t; - // CHECK: typedef std::unique_ptr int_ptr_t; - int_ptr_t e(new int()); - // CHECK: int_ptr_t e(new int()); - - // Test pointers - std::auto_ptr *f; - // CHECK: std::unique_ptr *f; - - // Test 'static' declarations - static std::auto_ptr g; - // CHECK: static std::unique_ptr g; - - // Test with cv-qualifiers - const std::auto_ptr h; - // CHECK: const std::unique_ptr h; - volatile std::auto_ptr i; - // CHECK: volatile std::unique_ptr i; - const volatile std::auto_ptr j; - // CHECK: const volatile std::unique_ptr j; - - // Test auto and initializer-list - auto k = std::auto_ptr{}; - // CHECK: auto k = std::unique_ptr{}; - std::auto_ptr l{std::auto_ptr()}; - // CHECK: std::unique_ptr l{std::unique_ptr()}; - - // Test interlocked auto_ptr - std::auto_ptr > m; - // CHECK: std::unique_ptr > m; - - // Test temporaries - std::auto_ptr(); - // CHECK: std::unique_ptr(); - - // Test void-specialization - std::auto_ptr n; - // CHECK: std::unique_ptr n; - - // Test template WITH instantiation (instantiation) - B o; - std::auto_ptr p(o.create()); - // CHECK: std::unique_ptr p(o.create()); - - // Test 'using' in a namespace ("definition") - ns_1::auto_ptr q; - // CHECK: ns_1::unique_ptr q; - - // Test construction with an 'auto_ptr_ref' - std::auto_ptr r(create_derived_ptr()); - // CHECK: std::unique_ptr r(create_derived_ptr()); -} - -// Test without the nested name specifiers -void f_2() { - using namespace std; - - auto_ptr a; - // CHECK: unique_ptr a; -} - -// Test using declaration -void f_3() { - using std::auto_ptr; - // CHECK: using std::unique_ptr; - - auto_ptr a; - // CHECK: unique_ptr a; -} - -// Test messing-up with macros -void f_4() { -#define MACRO_1 - std::auto_ptr MACRO_1 p(new char()); -// CHECK: std::unique_ptr MACRO_1 p(new char()); -#define MACRO_2 auto_ptr - std::MACRO_2 q; -// CHECK: #define MACRO_2 unique_ptr -#define MACRO_3(Type) std::auto_ptr - MACRO_3(float)r(new float()); -// CHECK: #define MACRO_3(Type) std::unique_ptr -#define MACRO_4 std::auto_ptr - using MACRO_4; -// CHECK: #define MACRO_4 std::unique_ptr -#undef MACRO_1 -#undef MACRO_2 -#undef MACRO_3 -#undef MACRO_4 -} - -// Test function return values (definition) -std::auto_ptr f_5() -// CHECK: std::unique_ptr f_5() -{ - // Test constructor - return std::auto_ptr(new char()); - // CHECK: return std::unique_ptr(new char()); -} - -// Test that non-std auto_ptr aren't replaced -void f_8() { - ns_2::auto_ptr a; - // CHECK: ns_2::auto_ptr a; - using namespace ns_2; - auto_ptr b; - // CHECK: auto_ptr b; -} - -namespace std { -template using aaaaaaaa = auto_ptr; -} -// We want to avoid replacing 'aaaaaaaa' by unique_ptr here. It's better to -// change the type alias directly. -// XXX: maybe another test will be more relevant to test this potential error. -std::aaaaaaaa d; -// CHECK: std::aaaaaaaa d; Index: test/clang-modernize/ReplaceAutoPtr/move.cpp =================================================================== --- test/clang-modernize/ReplaceAutoPtr/move.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// Without inline namespace: -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -replace-auto_ptr %t.cpp -- -I %S/Inputs std=c++11 -// RUN: FileCheck -input-file=%t.cpp %s -// -// With inline namespace: -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -replace-auto_ptr %t.cpp -- -I %S/Inputs std=c++11 \ -// RUN: -DUSE_INLINE_NAMESPACE=1 -// RUN: FileCheck -input-file=%t.cpp %s - -#include "memory_stub.h" - -void takes_ownership_fn(std::auto_ptr x); -// CHECK: void takes_ownership_fn(std::unique_ptr x); - -std::auto_ptr get_by_value(); -// CHECK: std::unique_ptr get_by_value(); - -class Wrapper { -public: - std::auto_ptr &get_wrapped(); - -private: - std::auto_ptr wrapped; -}; - -void f() { - std::auto_ptr a, b, c; - // CHECK: std::unique_ptr a, b, c; - Wrapper wrapper_a, wrapper_b; - - a = b; - // CHECK: a = std::move(b); - - wrapper_a.get_wrapped() = wrapper_b.get_wrapped(); - // CHECK: wrapper_a.get_wrapped() = std::move(wrapper_b.get_wrapped()); - - // Test that 'std::move()' is inserted when call to the - // copy-constructor are made. - takes_ownership_fn(c); - // CHECK: takes_ownership_fn(std::move(c)); - takes_ownership_fn(wrapper_a.get_wrapped()); - // CHECK: takes_ownership_fn(std::move(wrapper_a.get_wrapped())); - - std::auto_ptr d[] = { std::auto_ptr(new int(1)), - std::auto_ptr(new int(2)) }; - std::auto_ptr e = d[0]; - // CHECK: std::unique_ptr d[] = { std::unique_ptr(new int(1)), - // CHECK-NEXT: std::unique_ptr(new int(2)) }; - // CHECK-NEXT: std::unique_ptr e = std::move(d[0]); - - // Test that std::move() is not used when assigning an rvalue - std::auto_ptr f; - f = std::auto_ptr(new int(0)); - // CHECK: std::unique_ptr f; - // CHECK-NEXT: f = std::unique_ptr(new int(0)); - - std::auto_ptr g = get_by_value(); - // CHECK: std::unique_ptr g = get_by_value(); -} Index: test/clang-modernize/ReplaceAutoPtr/template_fail.cpp =================================================================== --- test/clang-modernize/ReplaceAutoPtr/template_fail.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// XFAIL: * -// -// Without inline namespace: -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -replace-auto_ptr %t.cpp -- -I %S/Inputs std=c++11 -// RUN: FileCheck -input-file=%t.cpp %s -// -// With inline namespace: -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -replace-auto_ptr %t.cpp -- -I %S/Inputs std=c++11 \ -// RUN: -DUSE_INLINE_NAMESPACE=1 -// RUN: FileCheck -input-file=%t.cpp %s - -#include "memory_stub.h" - -// Fail to modify when the template is never instantiated. -// -// This might not be an issue. If it's never used it doesn't really matter if -// it's changed or not. If it's a header and one of the source use it, then it -// will still be changed. -template -void f() { - std::auto_ptr p; - // CHECK: std::unique_ptr p; -} - -// Alias template could be replaced if a matcher existed. -template using aaaaaaaa = auto_ptr; -// CHECK: template using aaaaaaaa = unique_ptr; Index: test/clang-modernize/UseAuto/Inputs/test_std_container.h =================================================================== --- test/clang-modernize/UseAuto/Inputs/test_std_container.h +++ /dev/null @@ -1,119 +0,0 @@ -//===-----------------------------------------------------------*- C++ -*--===// -// -// This file contains a shell implementation of a standard container with -// iterators. This shell is targeted at supporting the container interfaces -// recognized by clang-modernize's use-auto transformation. It requires the -// preprocessor to parameterize the name of the container, and allows the -// preprocessor to parameterize various mechanisms used in the implementation -// of the container / iterator. -// -// 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++). -// -//===----------------------------------------------------------------------===// - -#ifndef CONTAINER -#error You must define CONTAINER to the name of the desired container. -#endif - -// If the test code needs multiple containers, only define our helpers once. -#ifndef TEST_STD_CONTAINER_HELPERS -#define TEST_STD_CONTAINER_HELPERS - -namespace internal { - -template -struct iterator_wrapper { - iterator_wrapper() {} - - // These are required for tests using iteration statements. - bool operator!=(const iterator_wrapper&) { return false; } - iterator_wrapper& operator++() { return *this; } - typename T::value_type operator*() { return typename T::value_type(); } -}; - -template -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 - -#endif // TEST_STD_CONTAINER_HELPERS - -namespace std { - -#if USE_INLINE_NAMESPACE -inline namespace _1 { -#endif - -template -class CONTAINER -#if USE_BASE_CLASS_ITERATORS - : internal::iterator_provider > -#endif -{ -public: - -#if USE_BASE_CLASS_ITERATORS - using typename internal::iterator_provider >::iterator; - using typename internal::iterator_provider >::const_iterator; - using typename internal::iterator_provider >::reverse_iterator; - using typename internal::iterator_provider >::const_reverse_iterator; -#elif USE_INNER_CLASS_ITERATORS - class iterator {}; - class const_iterator {}; - class reverse_iterator {}; - class const_reverse_iterator {}; -#else - typedef T value_type; - typedef typename internal::iterator_wrapper, 0> iterator; - typedef typename internal::iterator_wrapper, 1> const_iterator; - typedef typename internal::iterator_wrapper, 3> reverse_iterator; - typedef typename internal::iterator_wrapper, 2> const_reverse_iterator; -#endif - - // Every class requires these functions. - CONTAINER() {} - - iterator begin() { return iterator(); } - iterator end() { return iterator(); } - - const_iterator begin() const { return const_iterator(); } - const_iterator end() const { return const_iterator(); } - - reverse_iterator rbegin() { return reverse_iterator(); } - reverse_iterator rend() { return reverse_iterator(); } - - const_reverse_iterator rbegin() const { return const_reverse_iterator(); } - const_reverse_iterator rend() const { return const_reverse_iterator(); } - - template - iterator find(const K &Key) { return iterator(); } -}; - -#if USE_INLINE_NAMESPACE -} // namespace _1 -#endif - -} // namespace std Index: test/clang-modernize/UseAuto/basic_iterator_tests.cpp =================================================================== --- test/clang-modernize/UseAuto/basic_iterator_tests.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// 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 -// * Different patterns of defining iterators and containers -// -// // The most basic test. -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=array -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// -// Test variations on how the container and its iterators might be defined. -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=array \ -// RUN: -DUSE_INLINE_NAMESPACE=1 -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=array \ -// RUN: -DUSE_BASE_CLASS_ITERATORS=1 -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=array \ -// RUN: -DUSE_INNER_CLASS_ITERATORS=1 -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// -// Test all of the other container names in a basic configuration. -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=deque -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=forward_list -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=list -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=vector -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=map -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=multimap -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=set -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=multiset -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=unordered_map -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=unordered_multimap -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=unordered_set -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=unordered_multiset -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=queue -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=priority_queue -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -DCONTAINER=stack -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s - -#ifndef CONTAINER -#error You must define CONTAINER to the name of the container for testing. -#endif - -#include "test_std_container.h" - -int main(int argc, char **argv) { - { - std::CONTAINER C; - std::CONTAINER::iterator I = C.begin(); - // CHECK: auto I = C.begin(); - } - { - std::CONTAINER C; - std::CONTAINER::reverse_iterator I = C.rbegin(); - // CHECK: auto I = C.rbegin(); - } - { - const std::CONTAINER C; - std::CONTAINER::const_iterator I = C.begin(); - // CHECK: auto I = C.begin(); - } - { - const std::CONTAINER C; - std::CONTAINER::const_reverse_iterator I = C.rbegin(); - // CHECK: auto I = C.rbegin(); - } - - return 0; -} Index: test/clang-modernize/UseAuto/iterator.cpp =================================================================== --- test/clang-modernize/UseAuto/iterator.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- --std=c++11 -I %S/Inputs -// RUN: FileCheck -input-file=%t.cpp %s -// -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- --std=c++11 -I %S/Inputs \ -// RUN: -DUSE_INLINE_NAMESPACE=1 -// RUN: FileCheck -input-file=%t.cpp %s - - -#define CONTAINER array -#include "test_std_container.h" -#undef CONTAINER - -#define CONTAINER vector -#include "test_std_container.h" -#undef CONTAINER - -#define CONTAINER unordered_map -#define USE_BASE_CLASS_ITERATORS 1 -#include "test_std_container.h" -#undef USE_BASE_CLASS_ITERATORS -#undef CONTAINER - -typedef std::vector::iterator int_iterator; - -namespace foo { - template - class vector { - public: - class iterator {}; - - iterator begin() { return iterator(); } - }; -} // namespace foo - -int main(int argc, char **argv) { - std::vector Vec; - // CHECK: std::vector Vec; - - std::unordered_map Map; - // CHECK: std::unordered_map 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, 0> less_sugar = Vec.begin(); - // CHECK: internal::iterator_wrapper, 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::iterator I{Map.begin()}; - // CHECK: std::unordered_map::iterator I{Map.begin()}; - - std::unordered_map::iterator I2 = {Map.begin()}; - // CHECK: std::unordered_map::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::iterator copy(Map.begin()); - // CHECK: auto copy(Map.begin()); - - std::unordered_map::iterator def; - // CHECK: std::unordered_map::iterator def; - - // const_iterator has no default constructor, just one that has >0 params - // with defaults. - std::unordered_map::const_iterator constI; - // CHECK: std::unordered_map::const_iterator constI; - - // Uses iterator_provider::const_iterator's conversion constructor. - - std::unordered_map::const_iterator constI2 = def; - // CHECK: std::unordered_map::const_iterator constI2 = def; - - std::unordered_map::const_iterator constI3(def); - // CHECK: std::unordered_map::const_iterator constI3(def); - - // Explicit use of conversion constructor - - std::unordered_map::const_iterator constI4 = std::unordered_map::const_iterator(def); - // CHECK: auto constI4 = std::unordered_map::const_iterator(def); - - // Uses iterator_provider::iterator's const_iterator conversion operator. - - std::unordered_map::iterator I = constI; - // CHECK: std::unordered_map::iterator I = constI; - - std::unordered_map::iterator I2(constI); - // CHECK: std::unordered_map::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::iterator I = Vec.begin(); I != Vec.end(); ++I) { - // CHECK: for (auto I = Vec.begin(); I != Vec.end(); ++I) { - } - - // Range-based for loops. - std::array::iterator> iter_arr; - for (std::vector::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 foo_vec; - vector::iterator I = foo_vec.begin(); - // CHECK: vector::iterator I = foo_vec.begin(); - } - - // Ensure using directives don't interfere with replacement. - { - using namespace std; - vector std_vec; - vector::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(); - } - - // Passing a string as an argument to introduce a temporary object - // that will create an expression with cleanups. Bugzilla: 15550 - { - std::unordered_map MapFind; - std::unordered_map::iterator I = MapFind.find("foo"); - // CHECK: auto I = MapFind.find("foo"); - } - - // Test for declaration lists - { - // Ensusre declaration lists that matches the declaration type with written - // no-list initializer are transformed. - std::vector::iterator I = Vec.begin(), E = Vec.end(); - // CHECK: auto I = Vec.begin(), E = Vec.end(); - - // Declaration lists with non-initialized variables should not be - // transformed. - std::vector::iterator J = Vec.begin(), K; - // CHECK: std::vector::iterator J = Vec.begin(), K; - } - return 0; -} Index: test/clang-modernize/UseAuto/new.cpp =================================================================== --- test/clang-modernize/UseAuto/new.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%t.cpp %s - -class MyType { -}; - -class MyDerivedType : public MyType { -}; - -int main(int argc, char **argv) { - MyType *a = new MyType(); - // CHECK: auto a = new MyType(); - - static MyType *a_static = new MyType(); - // CHECK: static auto a_static = new MyType(); - - MyType *b = new MyDerivedType(); - // CHECK: MyType *b = new MyDerivedType(); - - void *c = new MyType(); - // CHECK: void *c = new MyType(); - - // CV-qualifier tests. - // - // NOTE : the form "type const" is expected here because of a deficiency in - // TypeLoc where CV qualifiers are not considered part of the type location - // info. That is, all that is being replaced in each case is "MyType *" and - // not "MyType * const". - { - static MyType * const d_static = new MyType(); - // CHECK: static auto const d_static = new MyType(); - - MyType * const d3 = new MyType(); - // CHECK: auto const d3 = new MyType(); - - MyType * volatile d4 = new MyType(); - // CHECK: auto volatile d4 = new MyType(); - } - - int (**func)(int, int) = new (int(*[5])(int,int)); - // CHECK: int (**func)(int, int) = new (int(*[5])(int,int)); - - int *e = new int[5]; - // CHECK: auto e = new int[5]; - - MyType *f(new MyType); - // CHECK: auto f(new MyType); - - MyType *g{new MyType}; - // CHECK: MyType *g{new MyType}; - - // Test for declaration lists. - { - MyType *a = new MyType(), *b = new MyType(), *c = new MyType(); - // CHECK: auto a = new MyType(), b = new MyType(), c = new MyType(); - - // Non-initialized declaration should not be transformed. - MyType *d = new MyType(), *e; - // CHECK: MyType *d = new MyType(), *e; - - MyType **f = new MyType*(), **g = new MyType*(); - // CHECK: auto f = new MyType*(), g = new MyType*(); - - // Mismatching types in declaration lists should not be transformed. - MyType *h = new MyType(), **i = new MyType*(); - // CHECK: MyType *h = new MyType(), **i = new MyType*(); - - // '*' shouldn't be removed in case of mismatching types with multiple - // declarations. - MyType *j = new MyType(), *k = new MyType(), **l = new MyType*(); - // CHECK: MyType *j = new MyType(), *k = new MyType(), **l = new MyType*(); - } - - // Test for typedefs. - { - typedef int * int_p; - - int_p a = new int; - // CHECK: auto a = new int; - int_p *b = new int*; - // CHECK: auto b = new int*; - - // Test for typedefs in declarations lists. - int_p c = new int, d = new int; - // CHECK: auto c = new int, d = new int; - - // Different types should not be transformed. - int_p e = new int, *f = new int_p; - // CHECK: int_p e = new int, *f = new int_p; - - int_p *g = new int*, *h = new int_p; - // CHECK: auto g = new int*, h = new int_p; - } - - return 0; -} Index: test/clang-modernize/UseAuto/new_cv_failing.cpp =================================================================== --- test/clang-modernize/UseAuto/new_cv_failing.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-auto %t.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%t.cpp %s -// XFAIL: * - -// None of these tests can pass right now because TypeLoc information where CV -// qualifiers are concerned is not reliable/available. - -class MyType { -}; - -int main (int argc, char **argv) { - const MyType *d = new MyType(); - // CHECK: const auto *d = new MyType(); - - volatile MyType *d2 = new MyType(); - // CHECK: volatile auto *d2 = new MyType(); - - const MyType * volatile e = new MyType(); - // CHECK: const auto * volatile d = new MyType(); - - volatile MyType * const f = new MyType(); - // CHECK: volatile auto * const d2 = new MyType(); - - const MyType *d5 = new const MyType(); - // CHECK: auto d5 = new const MyType(); - - volatile MyType *d6 = new volatile MyType(); - // CHECK: auto d6 = new volatile MyType(); - - const MyType * const d7 = new const MyType(); - // CHECK: const auto d7 = new const MyType(); - - volatile MyType * volatile d8 = new volatile MyType(); - // CHECK: volatile auto d8 = new volatile MyType(); -} Index: test/clang-modernize/UseNullptr/Inputs/basic.h =================================================================== --- test/clang-modernize/UseNullptr/Inputs/basic.h +++ /dev/null @@ -1,2 +0,0 @@ -int *global_p = 0; -// CHECK: int *global_p = nullptr; Index: test/clang-modernize/UseNullptr/basic.cpp =================================================================== --- test/clang-modernize/UseNullptr/basic.cpp +++ /dev/null @@ -1,291 +0,0 @@ -// RUN: mkdir -p %T/Inputs -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/basic.h > %T/Inputs/basic.h -// RUN: clang-modernize -use-nullptr -include=%T %t.cpp -- -std=c++98 -I %T -Wno-non-literal-null-conversion -// RUN: FileCheck -input-file=%t.cpp %s -// RUN: FileCheck -input-file=%T/Inputs/basic.h %S/Inputs/basic.h - -#include "Inputs/basic.h" - -const unsigned int g_null = 0; -#define NULL 0 -// CHECK: #define NULL 0 - -void test_assignment() { - int *p1 = 0; - // CHECK: int *p1 = nullptr; - p1 = 0; - // CHECK: p1 = nullptr; - - int *p2 = NULL; - // CHECK: int *p2 = nullptr; - - p2 = p1; - // CHECK: p2 = p1; - - const int null = 0; - int *p3 = null; - // CHECK: int *p3 = nullptr; - - p3 = NULL; - // CHECK: p3 = nullptr; - - int *p4 = p3; - // CHECK: int *p4 = p3; - - p4 = null; - // CHECK: p4 = nullptr; - - int i1 = 0; - // CHECK: int i1 = 0; - - int i2 = NULL; - // CHECK: int i2 = NULL; - - int i3 = null; - // CHECK: int i3 = null; - - int *p5, *p6, *p7; - p5 = p6 = p7 = NULL; - // CHECK: p5 = p6 = p7 = nullptr; -} - -struct Foo { - Foo(int *p = NULL) : m_p1(p) {} - // CHECK: Foo(int *p = nullptr) : m_p1(p) {} - - void bar(int *p = 0) {} - // CHECK: void bar(int *p = nullptr) {} - - void baz(int i = 0) {} - // CHECK: void baz(int i = 0) {} - - int *m_p1; - static int *m_p2; -}; - -int *Foo::m_p2 = NULL; -// CHECK: int *Foo::m_p2 = nullptr; - -template -struct Bar { - Bar(T *p) : m_p(p) { - m_p = static_cast(NULL); - // CHECK: m_p = static_cast(nullptr); - - m_p = static_cast(reinterpret_cast((void*)NULL)); - // CHECK: m_p = static_cast(nullptr); - - m_p = static_cast(p ? p : static_cast(g_null)); - // CHECK: m_p = static_cast(p ? p : static_cast(nullptr)); - - T *p2 = static_cast(reinterpret_cast((void*)NULL)); - // CHECK: T *p2 = static_cast(nullptr); - - m_p = NULL; - // CHECK: m_p = nullptr; - - int i = static_cast(0.f); - // CHECK: int i = static_cast(0.f); - T *i2 = static_cast(0.f); - // CHECK: T *i2 = nullptr; - } - - T *m_p; -}; - -struct Baz { - Baz() : i(0) {} - int i; -}; - -void test_cxx_cases() { - Foo f(g_null); - // CHECK: Foo f(nullptr); - - f.bar(NULL); - // CHECK: f.bar(nullptr); - - f.baz(g_null); - // CHECK: f.baz(g_null); - - f.m_p1 = 0; - // CHECK: f.m_p1 = nullptr; - - Bar b(g_null); - // CHECK: Bar b(nullptr); - - Baz b2; - int Baz::*memptr(0); - // CHECK: int Baz::*memptr(nullptr); - - memptr = 0; - // CHECK: memptr = nullptr; -} - -void test_function_default_param1(void *p = 0); -// CHECK: void test_function_default_param1(void *p = nullptr); - -void test_function_default_param2(void *p = NULL); -// CHECK: void test_function_default_param2(void *p = nullptr); - -void test_function_default_param3(void *p = g_null); -// CHECK: void test_function_default_param3(void *p = nullptr); - -void test_function(int *p) {} -// CHECK: void test_function(int *p) {} - -void test_function_no_ptr_param(int i) {} - -void test_function_call() { - test_function(0); - // CHECK: test_function(nullptr); - - test_function(NULL); - // CHECK: test_function(nullptr); - - test_function(g_null); - // CHECK: test_function(nullptr); - - test_function_no_ptr_param(0); - // CHECK: test_function_no_ptr_param(0); -} - -char *test_function_return1() { - return 0; - // CHECK: return nullptr; -} - -void *test_function_return2() { - return NULL; - // CHECK: return nullptr; -} - -long *test_function_return3() { - return g_null; - // CHECK: return nullptr; -} - -int test_function_return4() { - return 0; - // CHECK: return 0; -} - -int test_function_return5() { - return NULL; - // CHECK: return NULL; -} - -int test_function_return6() { - return g_null; - // CHECK: return g_null; -} - -int *test_function_return_cast1() { - return(int)0; - // CHECK: return nullptr; -} - -int *test_function_return_cast2() { - #define RET return - RET(int)0; - // CHECK: RET nullptr; - #undef RET -} - -// Test parentheses expressions resulting in a nullptr. -int *test_parentheses_expression1() { - return(0); - // CHECK: return(nullptr); -} - -int *test_parentheses_expression2() { - return(int(0.f)); - // CHECK: return(nullptr); -} - -int *test_nested_parentheses_expression() { - return((((0)))); - // CHECK: return((((nullptr)))); -} - -void *test_parentheses_explicit_cast() { - return(static_cast(0)); - // CHECK: return(static_cast(nullptr)); -} - -void *test_parentheses_explicit_cast_sequence1() { - return(static_cast(static_cast((void*)NULL))); - // CHECK: return(static_cast(nullptr)); -} - -void *test_parentheses_explicit_cast_sequence2() { - return(static_cast(reinterpret_cast((float*)int(0.f)))); - // CHECK: return(static_cast(nullptr)); -} - -// Test explicit cast expressions resulting in nullptr -struct Bam { - Bam(int *a) {} - Bam(float *a) {} - Bam operator=(int *a) { return Bam(a); } - Bam operator=(float *a) { return Bam(a); } -}; - -void ambiguous_function(int *a) {} -void ambiguous_function(float *a) {} -void const_ambiguous_function(const int *p) {} -void const_ambiguous_function(const float *p) {} - -void test_explicit_cast_ambiguous1() { - ambiguous_function((int*)0); - // CHECK: ambiguous_function((int*)nullptr); -} - -void test_explicit_cast_ambiguous2() { - ambiguous_function((int*)(0)); - // CHECK: ambiguous_function((int*)nullptr); -} - -void test_explicit_cast_ambiguous3() { - ambiguous_function(static_cast(reinterpret_cast((float*)0))); - // CHECK: ambiguous_function(static_cast(nullptr)); -} - -Bam test_explicit_cast_ambiguous4() { - return(((int*)(0))); - // CHECK: return(((int*)nullptr)); -} - -void test_explicit_cast_ambiguous5() { - // Test for ambiguous overloaded constructors - Bam k((int*)(0)); - // CHECK: Bam k((int*)nullptr); - - // Test for ambiguous overloaded operators - k = (int*)0; - // CHECK: k = (int*)nullptr; -} - -void test_const_pointers_abiguous() { - const_ambiguous_function((int*)0); - // CHECK: const_ambiguous_function((int*)nullptr); -} - -// Test where the implicit cast to null is surrounded by another implict cast -// with possible explict casts in-between. -void test_const_pointers() { - const int *const_p1 = 0; - // CHECK: const int *const_p1 = nullptr; - const int *const_p2 = NULL; - // CHECK: const int *const_p2 = nullptr; - const int *const_p3 = (int)0; - // CHECK: const int *const_p3 = nullptr; - const int *const_p4 = (int)0.0f; - // CHECK: const int *const_p4 = nullptr; - const int *const_p5 = (int*)0; - // CHECK: const int *const_p5 = (int*)nullptr; - int *t; - const int *const_p6 = static_cast(t ? t : static_cast(0)); - // CHECK: const int *const_p6 = static_cast(t ? t : static_cast(nullptr)); -} Index: test/clang-modernize/UseNullptr/basic_failing.cpp =================================================================== --- test/clang-modernize/UseNullptr/basic_failing.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-nullptr %t.cpp -- -I %S -// RUN: FileCheck -input-file=%t.cpp %s -// XFAIL: * - -#define NULL 0 - -template -class A { -public: - A(T *p = NULL) {} - // CHECK: A(T *p = nullptr) {} - - void f() { - Ptr = NULL; - // CHECK: Ptr = nullptr; - } - - T *Ptr; -}; - -template -T *f2(T *a = NULL) { - // CHECK: T *f2(T *a = nullptr) { - return a ? a : NULL; - // CHECK: return a ? a : nullptr; -} Index: test/clang-modernize/UseNullptr/macros.cpp =================================================================== --- test/clang-modernize/UseNullptr/macros.cpp +++ /dev/null @@ -1,164 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -use-nullptr %t.cpp -- -I %S -// RUN: FileCheck -input-file=%t.cpp %s -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t2.cpp -// RUN: clang-modernize -use-nullptr -user-null-macros=MY_NULL %t2.cpp -- -I %S -// RUN: FileCheck -check-prefix=USER-SUPPLIED-NULL -input-file=%t2.cpp %s - -#define NULL 0 -// CHECK: #define NULL 0 - -void dummy(int*) {} -void side_effect() {} - -#define MACRO_EXPANSION_HAS_NULL \ - void foo() { \ - dummy(0); \ - dummy(NULL); \ - side_effect(); \ - } - // CHECK: void foo() { \ - // CHECK-NEXT: dummy(0); \ - // CHECK-NEXT: dummy(NULL); \ - -MACRO_EXPANSION_HAS_NULL; -// CHECK: MACRO_EXPANSION_HAS_NULL; -#undef MACRO_EXPANSION_HAS_NULL - - -void test_macro_expansion1() { -#define MACRO_EXPANSION_HAS_NULL \ - dummy(NULL); \ - side_effect(); - // CHECK: dummy(NULL); \ - // CHECK-NEXT: side_effect(); - - MACRO_EXPANSION_HAS_NULL; - // CHECK: MACRO_EXPANSION_HAS_NULL; - -#undef MACRO_EXPANSION_HAS_NULL -} - -// Test macro expansion with cast sequence, PR15572 -void test_macro_expansion2() { -#define MACRO_EXPANSION_HAS_NULL \ - dummy((int*)0); \ - side_effect(); - // CHECK: dummy((int*)0); \ - // CHECK-NEXT: side_effect(); - - MACRO_EXPANSION_HAS_NULL; - // CHECK: MACRO_EXPANSION_HAS_NULL; - -#undef MACRO_EXPANSION_HAS_NULL -} - -void test_macro_expansion3() { -#define MACRO_EXPANSION_HAS_NULL \ - dummy(NULL); \ - side_effect(); - // CHECK: dummy(NULL); \ - // CHECK-NEXT: side_effect(); - -#define OUTER_MACRO \ - MACRO_EXPANSION_HAS_NULL; \ - side_effect(); - - OUTER_MACRO; - // CHECK: OUTER_MACRO; - -#undef OUTER_MACRO -#undef MACRO_EXPANSION_HAS_NULL -} - -void test_macro_expansion4() { -#define MY_NULL NULL - int *p = MY_NULL; - // CHECK: int *p = MY_NULL; - // USER-SUPPLIED-NULL: int *p = nullptr; -#undef MY_NULL -} - -#define IS_EQ(x, y) if (x != y) return; -void test_macro_args() { - int i = 0; - int *Ptr; - - IS_EQ(static_cast(0), Ptr); - // CHECK: IS_EQ(static_cast(nullptr), Ptr); - IS_EQ(0, Ptr); // literal - // CHECK: IS_EQ(nullptr, Ptr); - IS_EQ(NULL, Ptr); // macro - // CHECK: IS_EQ(nullptr, Ptr); - - // These are ok since the null literal is not spelled within a macro. -#define myassert(x) if (!(x)) return; - myassert(0 == Ptr); - // CHECK: myassert(nullptr == Ptr); - myassert(NULL == Ptr); - // CHECK: myassert(nullptr == Ptr); - - // These are bad as the null literal is buried in a macro. -#define BLAH(X) myassert(0 == (X)); - // CHECK: #define BLAH(X) myassert(0 == (X)); -#define BLAH2(X) myassert(NULL == (X)); - // CHECK: #define BLAH2(X) myassert(NULL == (X)); - BLAH(Ptr); - // CHECK: BLAH(Ptr); - BLAH2(Ptr); - // CHECK: BLAH2(Ptr); - - // Same as above but testing extra macro expansion. -#define EXPECT_NULL(X) IS_EQ(0, X); - // CHECK: #define EXPECT_NULL(X) IS_EQ(0, X); -#define EXPECT_NULL2(X) IS_EQ(NULL, X); - // CHECK: #define EXPECT_NULL2(X) IS_EQ(NULL, X); - EXPECT_NULL(Ptr); - // CHECK: EXPECT_NULL(Ptr); - EXPECT_NULL2(Ptr); - // CHECK: EXPECT_NULL2(Ptr); - - // Almost the same as above but now null literal is not in a macro so ok - // to transform. -#define EQUALS_PTR(X) IS_EQ(X, Ptr); - EQUALS_PTR(0); - EQUALS_PTR(NULL); - - // Same as above but testing extra macro expansion. -#define EQUALS_PTR_I(X) EQUALS_PTR(X) - EQUALS_PTR_I(0); - // CHECK: EQUALS_PTR_I(nullptr); - EQUALS_PTR_I(NULL); - // CHECK: EQUALS_PTR_I(nullptr); - - // Ok since null literal not within macro. However, now testing macro - // used as arg to another macro. -#define decorate(EXPR) side_effect(); EXPR; - decorate(IS_EQ(NULL, Ptr)); - // CHECK: decorate(IS_EQ(nullptr, Ptr)); - decorate(IS_EQ(0, Ptr)); - // CHECK: decorate(IS_EQ(nullptr, Ptr)); - - // This macro causes a NullToPointer cast to happen where 0 is assigned to z - // but the 0 literal cannot be replaced because it is also used as an - // integer in the comparison. -#define INT_AND_PTR_USE(X) do { int *z = X; if (X == 4) break; } while(false) - INT_AND_PTR_USE(0); - // CHECK: INT_AND_PTR_USE(0); - - // Both uses of X in this case result in NullToPointer casts so replacement - // is possible. -#define PTR_AND_PTR_USE(X) do { int *z = X; if (X != z) break; } while(false) - PTR_AND_PTR_USE(0); - // CHECK: PTR_AND_PTR_USE(nullptr); - PTR_AND_PTR_USE(NULL); - // CHECK: PTR_AND_PTR_USE(nullptr); - -#define OPTIONAL_CODE(...) __VA_ARGS__ -#define NOT_NULL dummy(0) -#define CALL(X) X - OPTIONAL_CODE(NOT_NULL); - // CHECK: OPTIONAL_CODE(NOT_NULL); - CALL(NOT_NULL); - // CHECK: CALL(NOT_NULL); -} Index: test/clang-modernize/UseNullptr/nullptr_t.cpp =================================================================== --- test/clang-modernize/UseNullptr/nullptr_t.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp -// RUN: clang-modernize -final-syntax-check -use-nullptr %t.cpp -- --std=c++11 -I %S -// RUN: FileCheck -input-file=%t.cpp %s - -namespace std { - -typedef decltype(nullptr) nullptr_t; - -} // namespace std - -// Just to make sure make_null() could have side effects. -void external(); - -std::nullptr_t make_null() { - external(); - return nullptr; -} - -void func() { - void *CallTest = make_null(); - // CHECK: void *CallTest = make_null(); - - int var = 1; - void *CommaTest = (var+=2, make_null()); - // CHECK: void *CommaTest = (var+=2, make_null()); - - int *CastTest = static_cast(make_null()); - // CHECK: int *CastTest = static_cast(make_null()); -} Index: unittests/CMakeLists.txt =================================================================== --- unittests/CMakeLists.txt +++ unittests/CMakeLists.txt @@ -6,7 +6,6 @@ endfunction() add_subdirectory(clang-apply-replacements) -add_subdirectory(clang-modernize) add_subdirectory(clang-rename) add_subdirectory(clang-query) add_subdirectory(clang-tidy) Index: unittests/Makefile =================================================================== --- unittests/Makefile +++ unittests/Makefile @@ -10,6 +10,6 @@ CLANG_LEVEL := ../../.. include $(CLANG_LEVEL)/../../Makefile.config -PARALLEL_DIRS := clang-apply-replacements clang-modernize clang-query clang-tidy clang-rename +PARALLEL_DIRS := clang-apply-replacements clang-query clang-tidy clang-rename include $(CLANG_LEVEL)/Makefile Index: unittests/clang-modernize/CMakeLists.txt =================================================================== --- unittests/clang-modernize/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -set(LLVM_LINK_COMPONENTS - support - ) - -get_filename_component(CLANG_MODERNIZE_SOURCE_DIR - ${CMAKE_CURRENT_SOURCE_DIR}/../../clang-modernize REALPATH) -get_filename_component(ClangReplaceLocation - "${CMAKE_CURRENT_SOURCE_DIR}/../../clang-apply-replacements/include" REALPATH) -get_filename_component(CommonIncLocation - "${CMAKE_CURRENT_SOURCE_DIR}/../include" REALPATH) -include_directories( - ${CLANG_MODERNIZE_SOURCE_DIR} - ${ClangReplaceLocation} - ${CommonIncLocation} - ) - -add_extra_unittest(ClangModernizeTests - IncludeExcludeTest.cpp - PerfSupportTest.cpp - TransformTest.cpp - UniqueHeaderNameTest.cpp - IncludeDirectivesTest.cpp - ) - -target_link_libraries(ClangModernizeTests - clangAST - clangASTMatchers - clangBasic - clangFrontend - clangTooling - clangToolingCore - modernizeCore - ) Index: unittests/clang-modernize/IncludeDirectivesTest.cpp =================================================================== --- unittests/clang-modernize/IncludeDirectivesTest.cpp +++ /dev/null @@ -1,410 +0,0 @@ -//===- clang-modernize/IncludeDirectivesTest.cpp --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Core/IncludeDirectives.h" -#include "common/VirtualFileHelper.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendActions.h" -#include "llvm/Support/Path.h" -#include "gtest/gtest.h" - -using namespace llvm; -using namespace clang; - -/// \brief A convenience method around \c tooling::runToolOnCodeWithArgs() that -/// adds the current directory to the include search paths. -static void applyActionOnCode(FrontendAction *ToolAction, StringRef Code) { - SmallString<128> CurrentDir; - ASSERT_FALSE(llvm::sys::fs::current_path(CurrentDir)); - - // Add the current directory to the header search paths so angled includes can - // find them. - std::vector Args; - Args.push_back("-I"); - Args.push_back(CurrentDir.str().str()); - - // mapVirtualFile() needs absolute path for the input file as well. - SmallString<128> InputFile(CurrentDir); - sys::path::append(InputFile, "input.cc"); - - ASSERT_TRUE( - tooling::runToolOnCodeWithArgs(ToolAction, Code, Args, InputFile.str())); -} - -namespace { -class TestAddIncludeAction : public PreprocessOnlyAction { -public: - TestAddIncludeAction(StringRef Include, tooling::Replacements &Replaces, - const char *HeaderToModify = nullptr) - : Include(Include), Replaces(Replaces), HeaderToModify(HeaderToModify) { - // some headers that the tests can include - mapVirtualHeader("foo-inner.h", "#pragma once\n"); - mapVirtualHeader("foo.h", "#pragma once\n" - "#include \n"); - mapVirtualHeader("bar-inner.h", "#pragma once\n"); - mapVirtualHeader("bar.h", "#pragma once\n" - "#include \n"); - mapVirtualHeader("xmacro.def", "X(Val1)\n" - "X(Val2)\n" - "X(Val3)\n"); - } - - /// \brief Make \p FileName an absolute path. - /// - /// Header files are mapped in the current working directory. The current - /// working directory is used because it's important to map files with - /// absolute paths. - /// - /// When used in conjunction with \c applyActionOnCode() (which adds the - /// current working directory to the header search paths) it is possible to - /// refer to the headers by using '\'. - std::string makeHeaderFileName(StringRef FileName) const { - SmallString<128> Path; - std::error_code EC = llvm::sys::fs::current_path(Path); - assert(!EC); - (void)EC; - - sys::path::append(Path, FileName); - return Path.str().str(); - } - - /// \brief Map additional header files. - /// - /// \sa makeHeaderFileName() - void mapVirtualHeader(StringRef FileName, StringRef Content) { - VFHelper.mapFile(makeHeaderFileName(FileName), Content); - } - -private: - bool BeginSourceFileAction(CompilerInstance &CI, - StringRef FileName) override { - if (!PreprocessOnlyAction::BeginSourceFileAction(CI, FileName)) - return false; - VFHelper.mapVirtualFiles(CI.getSourceManager()); - - FileToModify = - HeaderToModify ? makeHeaderFileName(HeaderToModify) : FileName.str(); - - FileIncludes.reset(new IncludeDirectives(CI)); - return true; - } - - void EndSourceFileAction() override { - const tooling::Replacement &Replace = - FileIncludes->addAngledInclude(FileToModify, Include); - if (Replace.isApplicable()) - Replaces.insert(Replace); - } - - StringRef Include; - VirtualFileHelper VFHelper; - tooling::Replacements &Replaces; - std::unique_ptr FileIncludes; - std::string FileToModify; - // if non-null, add the include directives in this file instead of the main - // file. - const char *HeaderToModify; -}; - -std::string addIncludeInCode(StringRef Include, StringRef Code) { - tooling::Replacements Replaces; - - applyActionOnCode(new TestAddIncludeAction(Include, Replaces), Code); - - if (::testing::Test::HasFailure()) - return "<>"; - - return tooling::applyAllReplacements(Code, Replaces); -} -} // end anonymous namespace - -TEST(IncludeDirectivesTest2, endOfLinesVariants) { - EXPECT_EQ("#include \n" - "#include \n", - addIncludeInCode("bar", "#include \n")); - EXPECT_EQ("#include \r\n" - "#include \r\n", - addIncludeInCode("bar", "#include \r\n")); - EXPECT_EQ("#include \r" - "#include \r", - addIncludeInCode("bar", "#include \r")); -} - -TEST(IncludeDirectivesTest, ppToken) { - EXPECT_EQ("#define FOO \n" - "#include FOO\n" - "#include \n" - "int i;\n", - addIncludeInCode("bar", "#define FOO \n" - "#include FOO\n" - "int i;\n")); -} - -TEST(IncludeDirectivesTest, noFileHeader) { - EXPECT_EQ("#include \n" - "\n" - "int foo;\n", - addIncludeInCode("bar", "int foo;\n")); -} - -TEST(IncludeDirectivesTest, commentBeforeTopMostCode) { - EXPECT_EQ("#include \n" - "\n" - "// Foo\n" - "int foo;\n", - addIncludeInCode("bar", "// Foo\n" - "int foo;\n")); -} - -TEST(IncludeDirectivesTest, multiLineComment) { - EXPECT_EQ("#include /* \n */\n" - "#include \n", - addIncludeInCode("bar", "#include /* \n */\n")); - EXPECT_EQ("#include /* \n */" - "\n#include ", - addIncludeInCode("bar", "#include /* \n */")); -} - -TEST(IncludeDirectivesTest, multilineCommentWithTrailingSpace) { - EXPECT_EQ("#include /*\n*/ \n" - "#include \n", - addIncludeInCode("bar", "#include /*\n*/ \n")); - EXPECT_EQ("#include /*\n*/ " - "\n#include ", - addIncludeInCode("bar", "#include /*\n*/ ")); -} - -TEST(IncludeDirectivesTest, fileHeaders) { - EXPECT_EQ("// this is a header\n" - "// some license stuff here\n" - "\n" - "#include \n" - "\n" - "/// \\brief Foo\n" - "int foo;\n", - addIncludeInCode("bar", "// this is a header\n" - "// some license stuff here\n" - "\n" - "/// \\brief Foo\n" - "int foo;\n")); -} - -TEST(IncludeDirectivesTest, preferablyAngledNextToAngled) { - EXPECT_EQ("#include \n" - "#include \n" - "#include \"bar.h\"\n", - addIncludeInCode("bar", "#include \n" - "#include \"bar.h\"\n")); - EXPECT_EQ("#include \"foo.h\"\n" - "#include \"bar.h\"\n" - "#include \n", - addIncludeInCode("bar", "#include \"foo.h\"\n" - "#include \"bar.h\"\n")); -} - -TEST(IncludeDirectivesTest, avoidDuplicates) { - EXPECT_EQ("#include \n", - addIncludeInCode("foo.h", "#include \n")); -} - -// Tests includes in the middle of the code are ignored. -TEST(IncludeDirectivesTest, ignoreHeadersMeantForMultipleInclusion) { - std::string Expected = "#include \"foo.h\"\n" - "#include \n" - "\n" - "enum Kind {\n" - "#define X(A) K_##A,\n" - "#include \"xmacro.def\"\n" - "#undef X\n" - " K_NUM_KINDS\n" - "};\n"; - std::string Result = addIncludeInCode("bar", "#include \"foo.h\"\n" - "\n" - "enum Kind {\n" - "#define X(A) K_##A,\n" - "#include \"xmacro.def\"\n" - "#undef X\n" - " K_NUM_KINDS\n" - "};\n"); - EXPECT_EQ(Expected, Result); -} - -namespace { -TestAddIncludeAction *makeIndirectTestsAction(const char *HeaderToModify, - tooling::Replacements &Replaces) { - StringRef IncludeToAdd = "c.h"; - TestAddIncludeAction *TestAction = - new TestAddIncludeAction(IncludeToAdd, Replaces, HeaderToModify); - TestAction->mapVirtualHeader("c.h", "#pragma once\n"); - TestAction->mapVirtualHeader("a.h", "#pragma once\n" - "#include \n"); - TestAction->mapVirtualHeader("b.h", "#pragma once\n"); - return TestAction; -} -} // end anonymous namespace - -TEST(IncludeDirectivesTest, indirectIncludes) { - // In TestAddIncludeAction 'foo.h' includes 'foo-inner.h'. Check that we - // aren't including foo-inner.h again. - EXPECT_EQ("#include \n", - addIncludeInCode("foo-inner.h", "#include \n")); - - tooling::Replacements Replaces; - StringRef Code = "#include \n" - "#include \n"; - - // a.h already includes c.h - { - FrontendAction *Action = makeIndirectTestsAction("a.h", Replaces); - ASSERT_NO_FATAL_FAILURE(applyActionOnCode(Action, Code)); - EXPECT_EQ(unsigned(0), Replaces.size()); - } - - // c.h is included before b.h but b.h doesn't include c.h directly, so check - // that it will be inserted. - { - FrontendAction *Action = makeIndirectTestsAction("b.h", Replaces); - ASSERT_NO_FATAL_FAILURE(applyActionOnCode(Action, Code)); - EXPECT_EQ("#include \n\n\n", - tooling::applyAllReplacements("\n", Replaces)); - } -} - -/// \brief Convenience method to test header guards detection implementation. -static std::string addIncludeInGuardedHeader(StringRef IncludeToAdd, - StringRef GuardedHeaderCode) { - const char *GuardedHeaderName = "guarded.h"; - tooling::Replacements Replaces; - TestAddIncludeAction *TestAction = - new TestAddIncludeAction(IncludeToAdd, Replaces, GuardedHeaderName); - TestAction->mapVirtualHeader(GuardedHeaderName, GuardedHeaderCode); - - applyActionOnCode(TestAction, "#include \n"); - if (::testing::Test::HasFailure()) - return "<>"; - - return tooling::applyAllReplacements(GuardedHeaderCode, Replaces); -} - -TEST(IncludeDirectivesTest, insertInsideIncludeGuard) { - EXPECT_EQ("#ifndef GUARD_H\n" - "#define GUARD_H\n" - "\n" - "#include \n" - "\n" - "struct foo {};\n" - "\n" - "#endif // GUARD_H\n", - addIncludeInGuardedHeader("foo", "#ifndef GUARD_H\n" - "#define GUARD_H\n" - "\n" - "struct foo {};\n" - "\n" - "#endif // GUARD_H\n")); -} - -TEST(IncludeDirectivesTest, guardAndHeader) { - EXPECT_EQ("// File header\n" - "\n" - "#ifndef GUARD_H\n" - "#define GUARD_H\n" - "\n" - "#include \n" - "\n" - "struct foo {};\n" - "\n" - "#endif // GUARD_H\n", - addIncludeInGuardedHeader("foo", "// File header\n" - "\n" - "#ifndef GUARD_H\n" - "#define GUARD_H\n" - "\n" - "struct foo {};\n" - "\n" - "#endif // GUARD_H\n")); -} - -TEST(IncludeDirectivesTest, fullHeaderFitsAsAPreamble) { - EXPECT_EQ("#ifndef GUARD_H\n" - "#define GUARD_H\n" - "\n" - "#include \n" - "\n" - "#define FOO 1\n" - "\n" - "#endif // GUARD_H\n", - addIncludeInGuardedHeader("foo", "#ifndef GUARD_H\n" - "#define GUARD_H\n" - "\n" - "#define FOO 1\n" - "\n" - "#endif // GUARD_H\n")); -} - -TEST(IncludeDirectivesTest, codeBeforeIfndef) { - EXPECT_EQ("#include \n" - "\n" - "int bar;\n" - "\n" - "#ifndef GUARD_H\n" - "#define GUARD_H\n" - "\n" - "struct foo;" - "\n" - "#endif // GUARD_H\n", - addIncludeInGuardedHeader("foo", "int bar;\n" - "\n" - "#ifndef GUARD_H\n" - "#define GUARD_H\n" - "\n" - "struct foo;" - "\n" - "#endif // GUARD_H\n")); -} - -TEST(IncludeDirectivesTest, codeAfterEndif) { - EXPECT_EQ("#include \n" - "\n" - "#ifndef GUARD_H\n" - "#define GUARD_H\n" - "\n" - "struct foo;" - "\n" - "#endif // GUARD_H\n" - "\n" - "int bar;\n", - addIncludeInGuardedHeader("foo", "#ifndef GUARD_H\n" - "#define GUARD_H\n" - "\n" - "struct foo;" - "\n" - "#endif // GUARD_H\n" - "\n" - "int bar;\n")); -} - -TEST(IncludeDirectivesTest, headerGuardWithInclude) { - EXPECT_EQ("#ifndef GUARD_H\n" - "#define GUARD_H\n" - "\n" - "#include \n" - "#include \n" - "\n" - "struct foo;\n" - "\n" - "#endif // GUARD_H\n", - addIncludeInGuardedHeader("foo", "#ifndef GUARD_H\n" - "#define GUARD_H\n" - "\n" - "#include \n" - "\n" - "struct foo;\n" - "\n" - "#endif // GUARD_H\n")); -} Index: unittests/clang-modernize/IncludeExcludeTest.cpp =================================================================== --- unittests/clang-modernize/IncludeExcludeTest.cpp +++ /dev/null @@ -1,149 +0,0 @@ -//===- clang-modernize/IncludeExcludeTest.cpp - IncludeExclude unit tests -===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "common/Utility.h" -#include "Core/IncludeExcludeInfo.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "gtest/gtest.h" -#include - -TEST(IncludeExcludeTest, ParseString) { - IncludeExcludeInfo IEManager; - std::error_code Err = IEManager.readListFromString( - /*include=*/ "a,b/b2,c/c2,d/../d2/../d3", - /*exclude=*/ "a/af.cpp,a/a2,b/b2/b2f.cpp,c/c2"); - - ASSERT_EQ(Err, std::error_code()); - - // If the file does not appear on the include list then it is not safe to - // transform. Files are not safe to transform by default. - EXPECT_FALSE(IEManager.isFileIncluded("f.cpp")); - EXPECT_FALSE(IEManager.isFileIncluded("b/dir/f.cpp")); - EXPECT_FALSE(IEManager.isFileIncluded("d/f.cpp")); - EXPECT_FALSE(IEManager.isFileIncluded("d2/f.cpp")); - - // If the file appears on only the include list then it is safe to transform. - EXPECT_TRUE(IEManager.isFileIncluded("a/f.cpp")); - EXPECT_TRUE(IEManager.isFileIncluded("a/dir/f.cpp")); - EXPECT_TRUE(IEManager.isFileIncluded("b/b2/f.cpp")); - EXPECT_TRUE(IEManager.isFileIncluded("d3/f.cpp")); - - // If the file appears on both the include or exclude list then it is not - // safe to transform. - EXPECT_FALSE(IEManager.isFileIncluded("a/af.cpp")); - EXPECT_FALSE(IEManager.isFileIncluded("a/a2/f.cpp")); - EXPECT_FALSE(IEManager.isFileIncluded("a/a2/dir/f.cpp")); - EXPECT_FALSE(IEManager.isFileIncluded("b/b2/b2f.cpp")); - EXPECT_FALSE(IEManager.isFileIncluded("c/c2/c3/f.cpp")); - -#ifdef LLVM_ON_WIN32 - // Check for cases when the path separators are different between the path - // that was read and the path that we are checking for. This can happen on - // windows where lit provides "\" and the test has "/". - ASSERT_NO_ERROR(IEManager.readListFromString( - /*include=*/ "C:\\foo,a\\b/c,a/../b\\c/..\\d", - /*exclude=*/ "C:\\bar" - )); - EXPECT_TRUE(IEManager.isFileIncluded("C:/foo/code.h")); - EXPECT_FALSE(IEManager.isFileIncluded("C:/bar/code.h")); - EXPECT_TRUE(IEManager.isFileIncluded("a/b\\c/code.h")); - EXPECT_FALSE(IEManager.isFileIncluded("b\\c/code.h")); - EXPECT_TRUE(IEManager.isFileIncluded("b/d\\code.h")); -#endif -} - -TEST(IncludeExcludeTest, ParseStringCases) { - IncludeExcludeInfo IEManager; - std::error_code Err = IEManager.readListFromString( - /*include=*/ "a/.,b/b2/,c/c2/c3/../../c4/,d/d2/./d3/,/e/e2/.", - /*exclude=*/ ""); - - ASSERT_EQ(Err, std::error_code()); - - EXPECT_TRUE(IEManager.isFileIncluded("a/f.cpp")); - EXPECT_TRUE(IEManager.isFileIncluded("b/b2/f.cpp")); - EXPECT_TRUE(IEManager.isFileIncluded("c/c4/f.cpp")); - EXPECT_TRUE(IEManager.isFileIncluded("d/d2/d3/f.cpp")); - EXPECT_TRUE(IEManager.isFileIncluded("/e/e2/f.cpp")); - - EXPECT_FALSE(IEManager.isFileIncluded("c/c2/c3/f.cpp")); -} - -// Utility for creating and filling files with data for IncludeExcludeFileTest -// tests. -struct InputFiles { - - // This function uses fatal assertions. The caller is responsible for making - // sure fatal assertions propagate. - void CreateFiles(bool UnixMode) { - llvm::SmallString<128> Path; - int FD; - - ASSERT_NO_ERROR( - llvm::sys::fs::createTemporaryFile("include", "", FD, Path)); - IncludeDataPath = Path.str(); - { - llvm::raw_fd_ostream IncludeDataFile(FD, true); - for (unsigned i = 0; i < sizeof(IncludeData) / sizeof(char *); ++i) { - IncludeDataFile << IncludeData[i] << (UnixMode ? "\n" : "\r\n"); - } - } - - ASSERT_NO_ERROR( - llvm::sys::fs::createTemporaryFile("exclude", "", FD, Path)); - ExcludeDataPath = Path.str(); - { - llvm::raw_fd_ostream ExcludeDataFile(FD, true); - for (unsigned i = 0; i < sizeof(ExcludeData) / sizeof(char *); ++i) { - ExcludeDataFile << ExcludeData[i] << (UnixMode ? "\n" : "\r\n"); - } - } - } - - static const char *IncludeData[3]; - static const char *ExcludeData[4]; - - std::string IncludeDataPath; - std::string ExcludeDataPath; -}; - -const char *InputFiles::IncludeData[3] = { "a", "b/b2", "c/c2" }; -const char *InputFiles::ExcludeData[4] = { "a/af.cpp", "a/a2", "b/b2/b2f.cpp", - "c/c2" }; - -TEST(IncludeExcludeFileTest, UNIXFile) { - InputFiles UnixFiles; - ASSERT_NO_FATAL_FAILURE(UnixFiles.CreateFiles(/* UnixMode= */true)); - - IncludeExcludeInfo IEManager; - std::error_code Err = IEManager.readListFromFile( - UnixFiles.IncludeDataPath.c_str(), UnixFiles.ExcludeDataPath.c_str()); - - ASSERT_EQ(Err, std::error_code()); - - EXPECT_FALSE(IEManager.isFileIncluded("f.cpp")); - EXPECT_TRUE(IEManager.isFileIncluded("a/f.cpp")); - EXPECT_FALSE(IEManager.isFileIncluded("a/af.cpp")); -} - -TEST(IncludeExcludeFileTest, DOSFile) { - InputFiles DOSFiles; - ASSERT_NO_FATAL_FAILURE(DOSFiles.CreateFiles(/* UnixMode= */false)); - - IncludeExcludeInfo IEManager; - std::error_code Err = IEManager.readListFromFile( - DOSFiles.IncludeDataPath.c_str(), DOSFiles.ExcludeDataPath.c_str()); - - ASSERT_EQ(Err, std::error_code()); - - EXPECT_FALSE(IEManager.isFileIncluded("f.cpp")); - EXPECT_TRUE(IEManager.isFileIncluded("a/f.cpp")); - EXPECT_FALSE(IEManager.isFileIncluded("a/af.cpp")); -} Index: unittests/clang-modernize/Makefile =================================================================== --- unittests/clang-modernize/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -##===- unittests/clang-modernize/Makefile ------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL = ../../../.. -include $(CLANG_LEVEL)/../../Makefile.config - -TESTNAME = ClangModernizeTests -LINK_COMPONENTS := asmparser bitreader support MC MCParser option \ - TransformUtils -USEDLIBS = modernizeCore.a clangFormat.a clangApplyReplacements.a \ - clangTooling.a clangToolingCore.a clangFrontend.a \ - clangSerialization.a clangDriver.a clangRewriteFrontend.a \ - clangRewrite.a clangParse.a clangSema.a clangAnalysis.a \ - clangAST.a clangASTMatchers.a clangEdit.a clangLex.a \ - clangBasic.a - -include $(CLANG_LEVEL)/Makefile -MAKEFILE_UNITTEST_NO_INCLUDE_COMMON := 1 -CPP.Flags += -I$(PROJ_SRC_DIR)/../../clang-modernize -I$(PROJ_SRC_DIR)/../../clang-apply-replacements/include \ - -I$(PROJ_SRC_DIR)/../include -include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest Index: unittests/clang-modernize/PerfSupportTest.cpp =================================================================== --- unittests/clang-modernize/PerfSupportTest.cpp +++ /dev/null @@ -1,97 +0,0 @@ -//===- clang-modernize/PerfSupportTest.cpp - PerfSupport unit tests -------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "gtest/gtest.h" -#include "Core/PerfSupport.h" - -using namespace llvm; -using namespace clang; - -class TransformA : public Transform { -public: - TransformA(const TransformOptions &Options) - : Transform("TransformA", Options) {} - - int apply(const tooling::CompilationDatabase &, - const std::vector &) override { - return 0; - } - - void addTiming(StringRef Label, TimeRecord Duration) { - Transform::addTiming(Label, Duration); - } -}; - -class TransformB : public Transform { -public: - TransformB(const TransformOptions &Options) - : Transform("TransformB", Options) {} - - int apply(const tooling::CompilationDatabase &, - const std::vector &) override { - return 0; - } - - void addTiming(StringRef Label, TimeRecord Duration) { - Transform::addTiming(Label, Duration); - } -}; - -struct ExpectedResults { - const char *SourceName; - unsigned DataCount; - struct Datum { - const char *Label; - float Duration; - } Data[2]; -}; - -TEST(PerfSupport, collectSourcePerfData) { - TransformOptions Options; - TransformA A(Options); - TransformB B(Options); - - // The actual durations don't matter. Below only their relative ordering is - // tested to ensure times, labels, and sources all stay together properly. - A.addTiming("FileA.cpp", TimeRecord::getCurrentTime(/*Start=*/true)); - A.addTiming("FileC.cpp", TimeRecord::getCurrentTime(/*Start=*/true)); - B.addTiming("FileC.cpp", TimeRecord::getCurrentTime(/*Start=*/true)); - B.addTiming("FileB.cpp", TimeRecord::getCurrentTime(/*Start=*/true)); - - SourcePerfData PerfData; - collectSourcePerfData(A, PerfData); - - SourcePerfData::const_iterator FileAI = PerfData.find("FileA.cpp"); - EXPECT_NE(FileAI, PerfData.end()); - SourcePerfData::const_iterator FileCI = PerfData.find("FileC.cpp"); - EXPECT_NE(FileCI, PerfData.end()); - EXPECT_EQ(2u, PerfData.size()); - - EXPECT_EQ(1u, FileAI->second.size()); - EXPECT_EQ("TransformA", FileAI->second[0].Label); - EXPECT_EQ(1u, FileCI->second.size()); - EXPECT_EQ("TransformA", FileCI->second[0].Label); - EXPECT_LE(FileAI->second[0].Duration, FileCI->second[0].Duration); - - collectSourcePerfData(B, PerfData); - - SourcePerfData::const_iterator FileBI = PerfData.find("FileB.cpp"); - EXPECT_NE(FileBI, PerfData.end()); - EXPECT_EQ(3u, PerfData.size()); - - EXPECT_EQ(1u, FileAI->second.size()); - EXPECT_EQ("TransformA", FileAI->second[0].Label); - EXPECT_EQ(2u, FileCI->second.size()); - EXPECT_EQ("TransformA", FileCI->second[0].Label); - EXPECT_EQ("TransformB", FileCI->second[1].Label); - EXPECT_LE(FileCI->second[0].Duration, FileCI->second[1].Duration); - EXPECT_EQ(1u, FileBI->second.size()); - EXPECT_EQ("TransformB", FileBI->second[0].Label); - EXPECT_LE(FileCI->second[1].Duration, FileBI->second[0].Duration); -} Index: unittests/clang-modernize/TransformTest.cpp =================================================================== --- unittests/clang-modernize/TransformTest.cpp +++ /dev/null @@ -1,299 +0,0 @@ -//===- clang-modernize/TransformTest.cpp - Transform unit tests -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "gtest/gtest.h" -#include "Core/Transform.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/DeclGroup.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/ASTMatchers/ASTMatchers.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" - -using namespace clang; -using namespace ast_matchers; - -class DummyTransform : public Transform { -public: - DummyTransform(llvm::StringRef Name, const TransformOptions &Options) - : Transform(Name, Options) {} - - int apply(const tooling::CompilationDatabase &, - const std::vector &) override { - return 0; - } - - void setAcceptedChanges(unsigned Changes) { - Transform::setAcceptedChanges(Changes); - } - void setRejectedChanges(unsigned Changes) { - Transform::setRejectedChanges(Changes); - } - void setDeferredChanges(unsigned Changes) { - Transform::setDeferredChanges(Changes); - } - -}; - -TEST(Transform, Interface) { - TransformOptions Options; - DummyTransform T("my_transform", Options); - - ASSERT_EQ("my_transform", T.getName()); - ASSERT_EQ(0u, T.getAcceptedChanges()); - ASSERT_EQ(0u, T.getRejectedChanges()); - ASSERT_EQ(0u, T.getDeferredChanges()); - ASSERT_FALSE(T.getChangesMade()); - ASSERT_FALSE(T.getChangesNotMade()); - - T.setAcceptedChanges(1); - ASSERT_TRUE(T.getChangesMade()); - - T.setDeferredChanges(1); - ASSERT_TRUE(T.getChangesNotMade()); - - T.setRejectedChanges(1); - ASSERT_TRUE(T.getChangesNotMade()); - - T.Reset(); - ASSERT_EQ(0u, T.getAcceptedChanges()); - ASSERT_EQ(0u, T.getRejectedChanges()); - ASSERT_EQ(0u, T.getDeferredChanges()); - - T.setRejectedChanges(1); - ASSERT_TRUE(T.getChangesNotMade()); -} - -class TimePassingASTConsumer : public ASTConsumer { -public: - TimePassingASTConsumer(bool *Called) : Called(Called) {} - - bool HandleTopLevelDecl(DeclGroupRef DeclGroup) override { - llvm::sys::TimeValue UserStart; - llvm::sys::TimeValue SystemStart; - llvm::sys::TimeValue UserNow; - llvm::sys::TimeValue SystemNow; - llvm::sys::TimeValue Wall; - - // Busy-wait until the user/system time combined is more than 1ms - llvm::sys::TimeValue OneMS(0, 1000000); - llvm::sys::Process::GetTimeUsage(Wall, UserStart, SystemStart); - do { - llvm::sys::Process::GetTimeUsage(Wall, UserNow, SystemNow); - } while (UserNow - UserStart + SystemNow - SystemStart < OneMS); - *Called = true; - return true; - } - bool *Called; -}; - -struct ConsumerFactory { - std::unique_ptr newASTConsumer() { - return llvm::make_unique(&Called); - } - bool Called; -}; - -struct CallbackForwarder : public clang::tooling::SourceFileCallbacks { - CallbackForwarder(Transform &Callee) : Callee(Callee) {} - - bool handleBeginSource(CompilerInstance &CI, StringRef Filename) override { - return Callee.handleBeginSource(CI, Filename); - } - - void handleEndSource() override { Callee.handleEndSource(); } - - Transform &Callee; -}; - -TEST(Transform, Timings) { - TransformOptions Options; - Options.EnableTiming = true; - DummyTransform T("timing_transform", Options); - - // All the path stuff is to make the test work independently of OS. - - // The directory used is not important since the path gets mapped to a virtual - // file anyway. What is important is that we have an absolute path with which - // to use with mapVirtualFile(). - SmallString<128> CurrentDir; - std::error_code EC = llvm::sys::fs::current_path(CurrentDir); - assert(!EC); - (void)EC; - - SmallString<128> FileA = CurrentDir; - llvm::sys::path::append(FileA, "a.cc"); - - SmallString<128> FileB = CurrentDir; - llvm::sys::path::append(FileB, "b.cc"); - - tooling::FixedCompilationDatabase Compilations(CurrentDir.str(), - std::vector()); - std::vector Sources; - Sources.push_back(FileA.str()); - Sources.push_back(FileB.str()); - tooling::ClangTool Tool(Compilations, Sources); - - Tool.mapVirtualFile(FileA, "void a() {}"); - Tool.mapVirtualFile(FileB, "void b() {}"); - - // Factory to create TimePassingASTConsumer for each source file the tool - // runs on. - ConsumerFactory Factory; - - // We don't care about any of Transform's functionality except to get it to - // record timings. For that, we need to forward handleBeginSource() and - // handleEndSource() calls to it. - CallbackForwarder Callbacks(T); - - Tool.run( - clang::tooling::newFrontendActionFactory(&Factory, &Callbacks).get()); - - EXPECT_TRUE(Factory.Called); - Transform::TimingVec::const_iterator I = T.timing_begin(); - EXPECT_GT(I->second.getProcessTime(), 0.0); - - // The success of the test shouldn't depend on the order of iteration through - // timers. - StringRef FirstFile = I->first; - if (FileA == FirstFile) { - ++I; - EXPECT_EQ(FileB, I->first); - EXPECT_GT(I->second.getProcessTime(), 0.0); - } else if (FileB == FirstFile) { - ++I; - EXPECT_EQ(FileA, I->first); - EXPECT_GT(I->second.getProcessTime(), 0.0); - } else { - FAIL() << "Unexpected file name " << I->first << " in timing data."; - } - ++I; - EXPECT_EQ(T.timing_end(), I); -} - -class ModifiableCallback - : public clang::ast_matchers::MatchFinder::MatchCallback { -public: - ModifiableCallback(const Transform &Owner) - : Owner(Owner) {} - - void - run(const clang::ast_matchers::MatchFinder::MatchResult &Result) override { - const VarDecl *Decl = Result.Nodes.getNodeAs("decl"); - ASSERT_TRUE(Decl != nullptr); - - const SourceManager &SM = *Result.SourceManager; - - // Decl 'a' comes from the main source file. This test should always pass. - if (Decl->getName().equals("a")) - EXPECT_TRUE(Owner.isFileModifiable(SM, Decl->getLocStart())); - - // Decl 'c' comes from an excluded header. This test should never pass. - else if (Decl->getName().equals("c")) - EXPECT_FALSE(Owner.isFileModifiable(SM, Decl->getLocStart())); - - // Decl 'b' comes from an included header. - else if (Decl->getName().equals("b")) - EXPECT_TRUE(Owner.isFileModifiable(SM, Decl->getLocStart())); - - // Make sure edge cases are handled gracefully (they should never be - // allowed). - SourceLocation DummyLoc; - EXPECT_FALSE(Owner.isFileModifiable(SM, DummyLoc)); - } - -private: - const Transform &Owner; -}; - -TEST(Transform, isFileModifiable) { - TransformOptions Options; - - /// - /// SETUP - /// - /// To test Transform::isFileModifiable() we need a SourceManager primed with - /// actual files and SourceLocations to test. Easiest way to accomplish this - /// is to use Tooling classes. - /// - /// 1) Simulate a source file that includes two headers, one that is allowed - /// to be modified and the other that is not allowed. Each of the three - /// files involved will declare a single variable with a different name. - /// 2) A matcher is created to find VarDecls. - /// 3) A MatchFinder callback calls Transform::isFileModifiable() with the - /// SourceLocations of found VarDecls and thus tests the function. - /// - - // All the path stuff is to make the test work independently of OS. - - // The directory used is not important since the path gets mapped to a virtual - // file anyway. What is important is that we have an absolute path with which - // to use with mapVirtualFile(). - SmallString<128> CurrentDir; - std::error_code EC = llvm::sys::fs::current_path(CurrentDir); - assert(!EC); - (void)EC; - - SmallString<128> SourceFile = CurrentDir; - llvm::sys::path::append(SourceFile, "a.cc"); - - SmallString<128> HeaderFile = CurrentDir; - llvm::sys::path::append(HeaderFile, "a.h"); - - SmallString<128> HeaderBFile = CurrentDir; - llvm::sys::path::append(HeaderBFile, "temp"); - llvm::sys::path::append(HeaderBFile, "b.h"); - - StringRef ExcludeDir = llvm::sys::path::parent_path(HeaderBFile); - - IncludeExcludeInfo IncInfo; - Options.ModifiableFiles.readListFromString(CurrentDir, ExcludeDir); - - tooling::FixedCompilationDatabase Compilations(CurrentDir.str(), - std::vector()); - std::vector Sources; - Sources.push_back(SourceFile.str()); - tooling::ClangTool Tool(Compilations, Sources); - - Tool.mapVirtualFile(SourceFile, - "#include \"a.h\"\n" - "#include \"temp/b.h\"\n" - "int a;"); - Tool.mapVirtualFile(HeaderFile, "int b;"); - Tool.mapVirtualFile(HeaderBFile, "int c;"); - - DummyTransform T("dummy", Options); - MatchFinder Finder; - ModifiableCallback Callback(T); - Finder.addMatcher(varDecl().bind("decl"), &Callback); - Tool.run(tooling::newFrontendActionFactory(&Finder).get()); -} - -TEST(VersionTest, Interface) { - Version V; - - ASSERT_TRUE(V.isNull()); - ASSERT_TRUE(Version(1) < Version(1, 1)); - ASSERT_TRUE(Version(1) < Version(2)); - ASSERT_TRUE(Version(1, 1) < Version(2)); - ASSERT_TRUE(Version(1, 1) == Version(1, 1)); - ASSERT_EQ(Version(1).getMajor(), unsigned(1)); - ASSERT_EQ(Version(1).getMinor(), unsigned(0)); - ASSERT_EQ(Version(1, 2).getMinor(), unsigned(2)); -} - -TEST(VersionTest, getFromString) { - ASSERT_EQ(Version(1), Version::getFromString("1")); - ASSERT_EQ(Version(1, 2), Version::getFromString("1.2")); - ASSERT_TRUE(Version::getFromString("foo").isNull()); - ASSERT_TRUE(Version::getFromString("1bar").isNull()); - // elements after major.minor are ignored - ASSERT_EQ(Version(1, 2), Version::getFromString("1.2.3")); -} Index: unittests/clang-modernize/UniqueHeaderNameTest.cpp =================================================================== --- unittests/clang-modernize/UniqueHeaderNameTest.cpp +++ /dev/null @@ -1,61 +0,0 @@ -//===- unittests/clang-modernize/UniqueHeaderNameTest.cpp -----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Test for the generateReplacementsFileName() in FileOverrides.h -// -//===----------------------------------------------------------------------===// - -#include "gtest/gtest.h" -#include "Core/ReplacementHandling.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Regex.h" -#include - -TEST(UniqueHeaderName, testUniqueHeaderName) { - using namespace llvm::sys::path; - - llvm::SmallString<32> TmpDir; - system_temp_directory(true, TmpDir); - - llvm::SmallString<128> SourceFile(TmpDir); - append(SourceFile, "project/lib/feature.cpp"); - native(SourceFile.str().str(), SourceFile); - - llvm::SmallString<128> DestDir(TmpDir); - append(DestDir, "replacements"); - - llvm::SmallString<128> FullActualPath; - llvm::SmallString<128> Error; - bool Result = ReplacementHandling::generateReplacementsFileName( - DestDir, SourceFile, FullActualPath, Error); - - ASSERT_TRUE(Result); - EXPECT_TRUE(Error.empty()); - - // We need to check the directory name and filename separately since on - // Windows, the path separator is '\' which is a regex escape character. - llvm::SmallString<128> ExpectedPath = - llvm::sys::path::parent_path(SourceFile); - llvm::SmallString<128> ActualPath = - llvm::sys::path::parent_path(FullActualPath); - llvm::SmallString<128> ActualName = - llvm::sys::path::filename(FullActualPath); - - EXPECT_STREQ(DestDir.c_str(), ActualPath.c_str()); - - llvm::StringRef ExpectedName = - "^feature.cpp_[0-9a-f]{2}_[0-9a-f]{2}_[0-9a-f]{2}_[0-9a-f]{2}_[" - "0-9a-f]{2}_[0-9a-f]{2}.yaml$"; - llvm::Regex R(ExpectedName); - ASSERT_TRUE(R.match(ActualName)) - << "ExpectedName: " << ExpectedName.data() - << "\nActualName: " << ActualName.c_str(); - ASSERT_TRUE(Error.empty()) << "Error: " << Error.c_str(); -} Index: unittests/include/common/Utility.h =================================================================== --- unittests/include/common/Utility.h +++ /dev/null @@ -1,25 +0,0 @@ -//=-- clang-modernize/Utility.h - Utility functions and macros---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_MODERNIZE_UNITTESTS_UTILITY_H -#define CLANG_MODERNIZE_UNITTESTS_UTILITY_H - -// FIXME: copied from unittests/Support/Path.cpp -#define ASSERT_NO_ERROR(x) \ - if (std::error_code ASSERT_NO_ERROR_ec = x) { \ - llvm::SmallString<128> MessageStorage; \ - llvm::raw_svector_ostream Message(MessageStorage); \ - Message << #x ": did not return errc::success.\n" \ - << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \ - << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \ - GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \ - } else { \ - } - -#endif // CLANG_MODERNIZE_UNITTESTS_UTILITY_H