diff options
author | Chandler Carruth <chandlerc@gmail.com> | 2013-09-04 17:35:07 +0000 |
---|---|---|
committer | Chandler Carruth <chandlerc@gmail.com> | 2013-09-04 17:35:07 +0000 |
commit | d9063c46f59f4bec47bcbeddca8ca2f789348c03 (patch) | |
tree | 76505542df7a05016dc71ffe44ed3ba264fb54be /clang-tools-extra/cpp11-migrate | |
parent | 6a23d212897d5402035cfaea82260f6dae1c8f2a (diff) | |
download | bcm5719-llvm-d9063c46f59f4bec47bcbeddca8ca2f789348c03.tar.gz bcm5719-llvm-d9063c46f59f4bec47bcbeddca8ca2f789348c03.zip |
Rename cpp11-migrate to clang-modernize.
There is no reason to expect this tool to be limited to C++11, it seems
very likely to be of on-going interest. It seems likely to be useful for
modernizing even as new libraries come out in TSes and other formats
than a complete standard. Fundamentally, we need something a bit more
general. After some discussion on the list, going with
'clang-modernize'.
I've tried to do a reasonably comprehensive job of fixing up the names,
but I may still have missed some. Feel free to poke me if you spot any
fallout here. Things I've tried reasonably hard to find and fix:
- cpp11-migrate -> clang-modernize
- Migrator -> Modernizer
- Clean up the introductory documentation that was C++11 specific.
I'll also point out that this tool continues to delight me. =] Also,
a huge thanks to those who have so carefully, thoroughly documented the
tool. The docs here are simply phenomenal. Every tool should be this
well documented. I hope I have updated the documentation reasonably
well, but I'm not very good at documentation, so review much
appreciated.
llvm-svn: 189960
Diffstat (limited to 'clang-tools-extra/cpp11-migrate')
65 files changed, 0 insertions, 7878 deletions
diff --git a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.cpp b/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.cpp deleted file mode 100644 index 9a13c044e5d..00000000000 --- a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.cpp +++ /dev/null @@ -1,87 +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<bool> DetectMacros( - "override-macros", - cl::desc("Detect and use macros that expand to the 'override' keyword."), - cl::cat(TransformsOptionsCategory)); - -int AddOverrideTransform::apply(const FileOverrides &InputStates, - const CompilationDatabase &Database, - const std::vector<std::string> &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; - - setOverrides(InputStates); - - if (int result = AddOverrideTool.run(createActionFactory(Finder))) { - llvm::errs() << "Error encountered during translation.\n"; - return result; - } - - setAcceptedChanges(AcceptedChanges); - return 0; -} - -bool AddOverrideTransform::handleBeginSource(clang::CompilerInstance &CI, - llvm::StringRef Filename) { - assert(Fixer != NULL && "Fixer must be set"); - Fixer->setPreprocessor(CI.getPreprocessor()); - return Transform::handleBeginSource(CI, Filename); -} - -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) LLVM_OVERRIDE { - return new AddOverrideTransform(Opts); - } -}; - -// Register the factory using this statically initialized variable. -static TransformFactoryRegistry::Add<AddOverrideFactory> -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; diff --git a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.h b/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.h deleted file mode 100644 index 8c39775e48d..00000000000 --- a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.h +++ /dev/null @@ -1,45 +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 CPP11_MIGRATE_ADD_OVERRIDE_H -#define CPP11_MIGRATE_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(). - virtual int apply(const FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, - const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE; - - virtual bool handleBeginSource(clang::CompilerInstance &CI, - llvm::StringRef Filename) LLVM_OVERRIDE; - -private: - AddOverrideFixer *Fixer; -}; - -#endif // CPP11_MIGRATE_ADD_OVERRIDE_H diff --git a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverrideActions.cpp b/clang-tools-extra/cpp11-migrate/AddOverride/AddOverrideActions.cpp deleted file mode 100644 index 134318ed386..00000000000 --- a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverrideActions.cpp +++ /dev/null @@ -1,101 +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/Basic/CharInfo.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Attr.h" -#include "clang/AST/RecursiveASTVisitor.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<CXXMethodDecl>(MethodId); - assert(M && "Bad Callback. No node provided"); - - if (const FunctionDecl *TemplateMethod = M->getTemplateInstantiationPattern()) - M = cast<CXXMethodDecl>(TemplateMethod); - - if (!Owner.isFileModifiable(SM, M->getLocStart())) - return; - - // First check that there isn't already an override attribute. - if (M->hasAttr<OverrideAttr>()) - 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 != 0 && "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; -} diff --git a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverrideActions.h b/clang-tools-extra/cpp11-migrate/AddOverride/AddOverrideActions.h deleted file mode 100644 index afcebeffd4b..00000000000 --- a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverrideActions.h +++ /dev/null @@ -1,45 +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 CPP11_MIGRATE_ADD_OVERRIDE_ACTIONS_H -#define CPP11_MIGRATE_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. - virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result); - - void setPreprocessor(clang::Preprocessor &PP) { this->PP = &PP; } - -private: - clang::Preprocessor *PP; - unsigned &AcceptedChanges; - bool DetectMacros; - Transform &Owner; -}; - -#endif // CPP11_MIGRATE_ADD_OVERRIDE_ACTIONS_H diff --git a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverrideMatchers.cpp b/clang-tools-extra/cpp11-migrate/AddOverride/AddOverrideMatchers.cpp deleted file mode 100644 index e323b5d5726..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 methodDecl(hasParent(recordDecl()), - isOverride(), - unless(destructorDecl())).bind(MethodId); -} - diff --git a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverrideMatchers.h b/clang-tools-extra/cpp11-migrate/AddOverride/AddOverrideMatchers.h deleted file mode 100644 index 0a81e546e85..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 CPP11_MIGRATE_ADD_OVERRIDE_MATCHERS_H -#define CPP11_MIGRATE_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 // CPP11_MIGRATE_ADD_OVERRIDE_MATCHERS_H diff --git a/clang-tools-extra/cpp11-migrate/CMakeLists.txt b/clang-tools-extra/cpp11-migrate/CMakeLists.txt deleted file mode 100644 index 5413edc2abc..00000000000 --- a/clang-tools-extra/cpp11-migrate/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -get_filename_component(ClangReplaceLocation - "${CMAKE_CURRENT_SOURCE_DIR}/../clang-apply-replacements/include" ABSOLUTE) - -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${ClangReplaceLocation} - ) - -add_subdirectory(tool) -add_subdirectory(Core) diff --git a/clang-tools-extra/cpp11-migrate/Core/CMakeLists.txt b/clang-tools-extra/cpp11-migrate/Core/CMakeLists.txt deleted file mode 100644 index 0ac52230e6a..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -set(LLVM_LINK_COMPONENTS support) - -add_clang_library(migrateCore - FileOverrides.cpp - SyntaxCheck.cpp - Transforms.cpp - Transform.cpp - IncludeExcludeInfo.cpp - PerfSupport.cpp - Reformatting.cpp - IncludeDirectives.cpp - ) -target_link_libraries(migrateCore - clangFormat - clangTooling - clangBasic - clangASTMatchers - clangRewriteFrontend - ) diff --git a/clang-tools-extra/cpp11-migrate/Core/CustomMatchers.h b/clang-tools-extra/cpp11-migrate/Core/CustomMatchers.h deleted file mode 100644 index 9af04977996..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 CPP11_MIGRATE_CUSTOMMATCHERS_H -#define CPP11_MIGRATE_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<NamespaceDecl>(D)->getIdentifier(); - - return Info && Info->isStr("std"); -} -} // namespace ast_matchers -} // namespace clang - -#endif // CPP11_MIGRATE_CUSTOMMATCHERS_H diff --git a/clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp b/clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp deleted file mode 100644 index 7ab7e91c30c..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp +++ /dev/null @@ -1,198 +0,0 @@ -//===-- Core/FileOverrides.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 types and functionality for dealing with source -/// and header file content overrides. -/// -//===----------------------------------------------------------------------===// - -#include "Core/FileOverrides.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Rewrite/Core/Rewriter.h" -#include "clang/Tooling/Tooling.h" -#include "clang/Tooling/ReplacementsYaml.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" -#include <algorithm> - -using namespace clang; -using namespace clang::tooling; - -bool generateReplacementsFileName(const llvm::StringRef MainSourceFile, - llvm::SmallVectorImpl<char> &Result, - llvm::SmallVectorImpl<char> &Error) { - using namespace llvm::sys; - - Error.clear(); - if (llvm::error_code EC = fs::createUniqueFile( - MainSourceFile + "_%%_%%_%%_%%_%%_%%.yaml", Result)) { - Error.append(EC.message().begin(), EC.message().end()); - return false; - } - - return true; -} - -namespace { - -/// \brief Comparator to be able to order tooling::Range based on their offset. -bool rangeLess(clang::tooling::Range A, clang::tooling::Range B) { - if (A.getOffset() == B.getOffset()) - return A.getLength() < B.getLength(); - return A.getOffset() < B.getOffset(); -} - -/// \brief Functor that returns the given range without its overlaps with the -/// replacement given in the constructor. -struct RangeReplacedAdjuster { - RangeReplacedAdjuster(const tooling::Replacement &Replace) - : Replace(Replace.getOffset(), Replace.getLength()), - ReplaceNewSize(Replace.getReplacementText().size()) {} - - tooling::Range operator()(clang::tooling::Range Range) const { - if (!Range.overlapsWith(Replace)) - return Range; - // range inside replacement -> make the range length null - if (Replace.contains(Range)) - return tooling::Range(Range.getOffset(), 0); - // replacement inside range -> resize the range - if (Range.contains(Replace)) { - int Difference = ReplaceNewSize - Replace.getLength(); - return tooling::Range(Range.getOffset(), Range.getLength() + Difference); - } - // beginning of the range replaced -> truncate range beginning - if (Range.getOffset() > Replace.getOffset()) { - unsigned ReplaceEnd = Replace.getOffset() + Replace.getLength(); - unsigned RangeEnd = Range.getOffset() + Range.getLength(); - return tooling::Range(ReplaceEnd, RangeEnd - ReplaceEnd); - } - // end of the range replaced -> truncate range end - if (Range.getOffset() < Replace.getOffset()) - return tooling::Range(Range.getOffset(), - Replace.getOffset() - Range.getOffset()); - llvm_unreachable("conditions not handled properly"); - } - - const tooling::Range Replace; - const unsigned ReplaceNewSize; -}; - -} // end anonymous namespace - -void -ChangedRanges::adjustChangedRanges(const tooling::ReplacementsVec &Replaces) { - // first adjust existing ranges in case they overlap with the replacements - for (ReplacementsVec::const_iterator I = Replaces.begin(), E = Replaces.end(); - I != E; ++I) { - const tooling::Replacement &Replace = *I; - - std::transform(Ranges.begin(), Ranges.end(), Ranges.begin(), - RangeReplacedAdjuster(Replace)); - } - - // then shift existing ranges to reflect the new positions - for (RangeVec::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { - unsigned ShiftedOffset = - tooling::shiftedCodePosition(Replaces, I->getOffset()); - *I = tooling::Range(ShiftedOffset, I->getLength()); - } - - // then generate the new ranges from the replacements - for (ReplacementsVec::const_iterator I = Replaces.begin(), E = Replaces.end(); - I != E; ++I) { - const tooling::Replacement &R = *I; - unsigned Offset = tooling::shiftedCodePosition(Replaces, R.getOffset()); - unsigned Length = R.getReplacementText().size(); - - Ranges.push_back(tooling::Range(Offset, Length)); - } - - // cleanups unecessary ranges to finish - coalesceRanges(); -} - -void ChangedRanges::coalesceRanges() { - // sort the ranges by offset and then for each group of adjacent/overlapping - // ranges the first one in the group is extended to cover the whole group. - std::sort(Ranges.begin(), Ranges.end(), &rangeLess); - RangeVec::iterator FirstInGroup = Ranges.begin(); - assert(!Ranges.empty() && "unexpected empty vector"); - for (RangeVec::iterator I = Ranges.begin() + 1, E = Ranges.end(); I != E; - ++I) { - unsigned GroupEnd = FirstInGroup->getOffset() + FirstInGroup->getLength(); - - // no contact - if (I->getOffset() > GroupEnd) - FirstInGroup = I; - else { - unsigned GrpBegin = FirstInGroup->getOffset(); - unsigned GrpEnd = std::max(GroupEnd, I->getOffset() + I->getLength()); - *FirstInGroup = tooling::Range(GrpBegin, GrpEnd - GrpBegin); - } - } - - // remove the ranges that are covered by the first member of the group - Ranges.erase(std::unique(Ranges.begin(), Ranges.end(), - std::mem_fun_ref(&Range::contains)), - Ranges.end()); -} - -void FileOverrides::applyOverrides(clang::SourceManager &SM) const { - FileManager &FM = SM.getFileManager(); - - for (FileStateMap::const_iterator I = FileStates.begin(), - E = FileStates.end(); - I != E; ++I) { - SM.overrideFileContents(FM.getFile(I->getKey()), - llvm::MemoryBuffer::getMemBuffer(I->getValue())); - } -} - -void FileOverrides::adjustChangedRanges( - const clang::replace::FileToReplacementsMap &Replaces) { - - for (replace::FileToReplacementsMap::const_iterator I = Replaces.begin(), - E = Replaces.end(); I != E; ++I) { - ChangeTracking[I->getKey()].adjustChangedRanges(I->getValue()); - } -} - -void FileOverrides::updateState(const clang::Rewriter &Rewrites) { - for (Rewriter::const_buffer_iterator BufferI = Rewrites.buffer_begin(), - BufferE = Rewrites.buffer_end(); - BufferI != BufferE; ++BufferI) { - const char *FileName = - Rewrites.getSourceMgr().getFileEntryForID(BufferI->first)->getName(); - const RewriteBuffer &RewriteBuf = BufferI->second; - FileStates[FileName].assign(RewriteBuf.begin(), RewriteBuf.end()); - } -} - -bool FileOverrides::writeToDisk(DiagnosticsEngine &Diagnostics) const { - bool Errors = false; - for (FileStateMap::const_iterator I = FileStates.begin(), - E = FileStates.end(); - I != E; ++I) { - std::string ErrorInfo; - // The extra transform through std::string is to ensure null-termination - // of the filename stored as the key of the StringMap. - llvm::raw_fd_ostream FileStream(I->getKey().str().c_str(), ErrorInfo); - if (!ErrorInfo.empty()) { - llvm::errs() << "Failed to write new state for " << I->getKey() << ".\n"; - Errors = true; - } - FileStream << I->getValue(); - } - return !Errors; -} diff --git a/clang-tools-extra/cpp11-migrate/Core/FileOverrides.h b/clang-tools-extra/cpp11-migrate/Core/FileOverrides.h deleted file mode 100644 index 8ed2914f0d2..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/FileOverrides.h +++ /dev/null @@ -1,129 +0,0 @@ -//===-- Core/FileOverrides.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 types and functionality for dealing with source -/// and header file content overrides. -/// -//===----------------------------------------------------------------------===// - -#ifndef CPP11_MIGRATE_FILE_OVERRIDES_H -#define CPP11_MIGRATE_FILE_OVERRIDES_H - -#include "Core/Refactoring.h" -#include "clang-apply-replacements/Tooling/ApplyReplacements.h" -#include "clang/Tooling/ReplacementsYaml.h" -#include "llvm/ADT/StringMap.h" - -// Forward Declarations -namespace llvm { -template <typename T> -class SmallVectorImpl; -} // namespace llvm -namespace clang { -class SourceManager; -class Rewriter; -} // namespace clang - -/// \brief Class encapsulating a list of \c tooling::Range with some -/// convenience methods. -/// -/// The ranges stored are used to keep track of the overriden parts of a file. -class ChangedRanges { - typedef std::vector<clang::tooling::Range> RangeVec; - -public: - typedef RangeVec::const_iterator const_iterator; - - /// \brief Create new ranges from the replacements and adjust existing one - /// to remove replaced parts. - /// - /// Note that all replacements should come from the same file. - void adjustChangedRanges(const clang::tooling::ReplacementsVec &Replaces); - - /// \brief Iterators. - /// \{ - const_iterator begin() const { return Ranges.begin(); } - const_iterator end() const { return Ranges.end(); } - /// \} - -private: - void coalesceRanges(); - - RangeVec Ranges; -}; - -/// \brief Maintains current state of transformed files and tracks source ranges -/// where changes have been made. -class FileOverrides { -public: - /// \brief Maps file names to file contents. - typedef llvm::StringMap<std::string> FileStateMap; - - /// \brief Maps file names to change tracking info for a file. - typedef llvm::StringMap<ChangedRanges> ChangeMap; - - - /// \brief Override file contents seen by \c SM for all files stored by this - /// object. - void applyOverrides(clang::SourceManager &SM) const; - - /// \brief Update change tracking information based on replacements stored in - /// \c Replaces. - void - adjustChangedRanges(const clang::replace::FileToReplacementsMap &Replaces); - - /// \brief Accessor for change tracking information. - const ChangeMap &getChangedRanges() const { - return ChangeTracking; - } - - /// \brief Coalesce changes stored in \c Rewrites and replace file contents - /// overrides stored in this object. - /// - /// \param Rewrites Rewriter containing changes to files. - void updateState(const clang::Rewriter &Rewrites); - - /// \brief Accessor for current file state. - const FileStateMap &getState() const { return FileStates; } - - /// \brief Write all file contents overrides to disk. - /// - /// \param Diagnostics DiagnosticsEngine for error output. - /// - /// \returns \li true if all files with overridden file contents were written - /// to disk successfully. - /// \li false if any failure occurred. - bool writeToDisk(clang::DiagnosticsEngine &Diagnostics) const; - -private: - FileStateMap FileStates; - ChangeMap ChangeTracking; -}; - -/// \brief Generate a unique filename to store the replacements. -/// -/// Generates a unique filename in the same directory as \c MainSourceFile. The -/// filename is generated following this pattern: -/// -/// MainSourceFile_%%_%%_%%_%%_%%_%%.yaml -/// -/// where all '%' will be replaced by a randomly chosen hex number. -/// -/// \param[in] MainSourceFile Full path to the source file. -/// \param[out] Result The resulting unique filename in the same directory as -/// the \c MainSourceFile. -/// \param[out] Error If an error occurs a description of that error is -/// placed in this string. -/// \returns true on success, false if a unique file name could not be created. -bool generateReplacementsFileName(const llvm::StringRef MainSourceFile, - llvm::SmallVectorImpl<char> &Result, - llvm::SmallVectorImpl<char> &Error); - -#endif // CPP11_MIGRATE_FILE_OVERRIDES_H diff --git a/clang-tools-extra/cpp11-migrate/Core/IncludeDirectives.cpp b/clang-tools-extra/cpp11-migrate/Core/IncludeDirectives.cpp deleted file mode 100644 index f240950790b..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/IncludeDirectives.cpp +++ /dev/null @@ -1,474 +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 <stack> - -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(0), 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(0) {} - -private: - virtual ~IncludeDirectivesPPCallback() {} - void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, - StringRef FileName, bool IsAngled, - CharSourceRange FilenameRange, const FileEntry *File, - StringRef SearchPath, StringRef RelativePath, - const Module *Imported) LLVM_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 - virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType, - FileID PrevFID) { - 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 <built-in> 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), 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; - } - - virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok, - const MacroDirective *MD) { - 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 == 0) { - IdentifierInfo *MII = MacroNameTok.getIdentifierInfo(); - - if (MII->hasMacroDefinition()) - return; - Guard->IfndefLoc = Loc; - Guard->TheMacro = MII; - } - } - - virtual void MacroDefined(const Token &MacroNameTok, - const MacroDirective *MD) { - 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 != 0) { - 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(); - } - } - - virtual void Endif(SourceLocation Loc, SourceLocation IfLoc) { - 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; - } - - virtual void MacroExpands(const Token &, const MacroDirective *, SourceRange, - const MacroArgs *) { - Guard->Count++; - } - virtual void MacroUndefined(const Token &, const MacroDirective *) { - Guard->Count++; - } - virtual void Defined(const Token &, const MacroDirective *, SourceRange) { - Guard->Count++; - } - virtual void If(SourceLocation, SourceRange, bool) { Guard->Count++; } - virtual void Elif(SourceLocation, SourceRange, bool, SourceLocation) { - Guard->Count++; - } - virtual void Ifdef(SourceLocation, const Token &, const MacroDirective *) { - Guard->Count++; - } - virtual void Else(SourceLocation, SourceLocation) { Guard->Count++; } - - IncludeDirectives *Self; - // keep track of the guard info through the include stack - std::stack<GuardDetection> 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<StringRef>(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<unsigned, bool> 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 <foo> /* 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(new IncludeDirectivesPPCallback(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<LocationVec>::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.isInvalid() && "Invalid file entry given!"); - - if (hasInclude(File, Include)) - return Replacement(); - - unsigned Offset, NLFlags; - llvm::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<unsigned, unsigned> -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<unsigned, unsigned> -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); -} diff --git a/clang-tools-extra/cpp11-migrate/Core/IncludeDirectives.h b/clang-tools-extra/cpp11-migrate/Core/IncludeDirectives.h deleted file mode 100644 index c1c5a7acf77..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 CPP11_MIGRATE_INCLUDE_DIRECTIVES_H -#define CPP11_MIGRATE_INCLUDE_DIRECTIVES_H - -#include "clang/Basic/SourceLocation.h" -#include "clang/Tooling/Refactoring.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/SmallPtrSet.h" -#include <vector> - -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 - /// \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<Entry> EntryVec; - - // A list of source locations. - typedef std::vector<clang::SourceLocation> LocationVec; - - // Associates files to their includes. - typedef llvm::DenseMap<const clang::FileEntry *, EntryVec> FileToEntriesMap; - - // Associates headers to their include guards if any. The location is the - // location of the hash from the #define. - typedef llvm::DenseMap<const clang::FileEntry *, clang::SourceLocation> - HeaderToGuardMap; - - /// \brief Type used by \c lookForInclude() to keep track of the files that - /// have already been processed. - typedef llvm::SmallPtrSet<const clang::FileEntry *, 32> 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 preferrably be put after this. - std::pair<unsigned, unsigned> - findFileHeaderEndOffset(clang::FileID FID) const; - - /// \brief Finds the offset where an angled include should be added and - /// returns a pair (FileOffset, NewLineFlags). - std::pair<unsigned, unsigned> - 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<LocationVec> IncludeAsWrittenToLocationsMap; - HeaderToGuardMap HeaderToGuard; -}; - -#endif // CPP11_MIGRATE_INCLUDE_DIRECTIVES_H diff --git a/clang-tools-extra/cpp11-migrate/Core/IncludeExcludeInfo.cpp b/clang-tools-extra/cpp11-migrate/Core/IncludeExcludeInfo.cpp deleted file mode 100644 index e3f07c5f0d3..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/IncludeExcludeInfo.cpp +++ /dev/null @@ -1,169 +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<StringRef, 16> 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<StringRef>::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. -error_code parseCLInput(StringRef Line, std::vector<std::string> &List, - StringRef Separator) { - SmallVector<StringRef, 32> Tokens; - Line.split(Tokens, Separator, /*MaxSplit=*/ -1, /*KeepEmpty=*/ false); - for (SmallVectorImpl<StringRef>::iterator I = Tokens.begin(), - E = Tokens.end(); - I != E; ++I) { - // Convert each path to its absolute path. - PathString Path = I->rtrim(); - if (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: " <<List.back() << "\n"; - } - return error_code::success(); -} -} // end anonymous namespace - -error_code IncludeExcludeInfo::readListFromString(StringRef IncludeString, - StringRef ExcludeString) { - if (error_code Err = parseCLInput(IncludeString, IncludeList, - /*Separator=*/ ",")) - return Err; - if (error_code Err = parseCLInput(ExcludeString, ExcludeList, - /*Separator=*/ ",")) - return Err; - return error_code::success(); -} - -error_code IncludeExcludeInfo::readListFromFile(StringRef IncludeListFile, - StringRef ExcludeListFile) { - if (!IncludeListFile.empty()) { - OwningPtr<MemoryBuffer> FileBuf; - if (error_code Err = MemoryBuffer::getFile(IncludeListFile, FileBuf)) { - errs() << "Unable to read from include file.\n"; - return Err; - } - if (error_code Err = parseCLInput(FileBuf->getBuffer(), IncludeList, - /*Separator=*/ "\n")) - return Err; - } - if (!ExcludeListFile.empty()) { - OwningPtr<MemoryBuffer> FileBuf; - if (error_code Err = MemoryBuffer::getFile(ExcludeListFile, FileBuf)) { - errs() << "Unable to read from exclude file.\n"; - return Err; - } - if (error_code Err = parseCLInput(FileBuf->getBuffer(), ExcludeList, - /*Separator=*/ "\n")) - return Err; - } - return error_code::success(); -} - -bool IncludeExcludeInfo::isFileIncluded(StringRef FilePath) const { - bool InIncludeList = false; - - for (std::vector<std::string>::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; - - for (std::vector<std::string>::const_iterator I = ExcludeList.begin(), - E = ExcludeList.end(); - I != E; ++I) - if (fileHasPathPrefix(FilePath, *I)) - return false; - - // If the file is in the included list but not in the excluded list, then - // it is safe to transform. - return true; -} diff --git a/clang-tools-extra/cpp11-migrate/Core/IncludeExcludeInfo.h b/clang-tools-extra/cpp11-migrate/Core/IncludeExcludeInfo.h deleted file mode 100644 index a5e73efae0f..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/IncludeExcludeInfo.h +++ /dev/null @@ -1,56 +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 CPP11_MIGRATE_INCLUDEEXCLUDEINFO_H -#define CPP11_MIGRATE_INCLUDEEXCLUDEINFO_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/system_error.h" -#include <vector> - -/// \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-seperated 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. - llvm::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. - llvm::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; - -private: - std::vector<std::string> IncludeList; - std::vector<std::string> ExcludeList; -}; - -#endif // CPP11_MIGRATE_INCLUDEEXCLUDEINFO_H diff --git a/clang-tools-extra/cpp11-migrate/Core/Makefile b/clang-tools-extra/cpp11-migrate/Core/Makefile deleted file mode 100644 index e60e11364f6..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- cpp11-migrate/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 := migrateCore - -include $(CLANG_LEVEL)/Makefile - -CPP.Flags += -I$(PROJ_SRC_DIR)/.. -I$(PROJ_SRC_DIR)/../../clang-apply-replacements/include diff --git a/clang-tools-extra/cpp11-migrate/Core/PerfSupport.cpp b/clang-tools-extra/cpp11-migrate/Core/PerfSupport.cpp deleted file mode 100644 index e074bd123ef..00000000000 --- a/clang-tools-extra/cpp11-migrate/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/raw_ostream.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/Path.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<PerfItem>())).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<int>(T.getWallTime()) << "_" << Pid - << ".json"; - - std::string ErrorInfo; - llvm::raw_fd_ostream FileStream(SS.str().c_str(), ErrorInfo); - 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<PerfItem>::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<PerfItem>::const_iterator VecI = I->second.begin(), - VecE = I->second.end(); - VecI != VecE; ++VecI) { - llvm::errs() << " " << VecI->Label << ": " - << llvm::format("%.1f", VecI->Duration) << "ms\n"; - } - } -} diff --git a/clang-tools-extra/cpp11-migrate/Core/PerfSupport.h b/clang-tools-extra/cpp11-migrate/Core/PerfSupport.h deleted file mode 100644 index 58ddded2207..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/PerfSupport.h +++ /dev/null @@ -1,57 +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 CPP11_MIGRATE_PERFSUPPORT_H -#define CPP11_MIGRATE_PERFSUPPORT_H - -#include "Transform.h" -#include "llvm/ADT/StringRef.h" - -#include <map> -#include <vector> - -/// \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<std::string, std::vector<PerfItem> > 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 // CPP11_MIGRATE_PERFSUPPORT_H diff --git a/clang-tools-extra/cpp11-migrate/Core/Refactoring.h b/clang-tools-extra/cpp11-migrate/Core/Refactoring.h deleted file mode 100644 index a15634a3704..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 CPP11_MIGRATE_REPLACEMENTS_VEC_H -#define CPP11_MIGRATE_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<clang::tooling::Replacement> ReplacementsVec; -} -} - -#endif // CPP11_MIGRATE_REPLACEMENTS_VEC_H diff --git a/clang-tools-extra/cpp11-migrate/Core/Reformatting.cpp b/clang-tools-extra/cpp11-migrate/Core/Reformatting.cpp deleted file mode 100644 index 50ba1f19f7a..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/Reformatting.cpp +++ /dev/null @@ -1,62 +0,0 @@ -//===-- Core/Reformatting.cpp - LibFormat integration ---------------------===// -// -// 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 LibFormat integration used to reformat -/// migrated code. -/// -//===----------------------------------------------------------------------===// - -#include "Core/Reformatting.h" -#include "Core/FileOverrides.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/Lexer.h" - -using namespace clang; - -void Reformatter::reformatChanges(const FileOverrides &FileStates, - clang::SourceManager &SM, - clang::tooling::ReplacementsVec &Replaces) { - FileStates.applyOverrides(SM); - - for (FileOverrides::ChangeMap::const_iterator - I = FileStates.getChangedRanges().begin(), - E = FileStates.getChangedRanges().end(); - I != E; ++I) { - reformatSingleFile(I->getKey(), I->getValue(), SM, Replaces); - } -} - -void Reformatter::reformatSingleFile( - const llvm::StringRef FileName, const ChangedRanges &Changes, - SourceManager &SM, clang::tooling::ReplacementsVec &FormatReplacements) { - - const clang::FileEntry *Entry = SM.getFileManager().getFile(FileName); - assert(Entry && "expected an existing file"); - - FileID ID = SM.translateFile(Entry); - if (ID.isInvalid()) - ID = SM.createFileID(Entry, SourceLocation(), clang::SrcMgr::C_User); - - std::vector<CharSourceRange> ReformatRanges; - SourceLocation StartOfFile = SM.getLocForStartOfFile(ID); - for (ChangedRanges::const_iterator I = Changes.begin(), E = Changes.end(); - I != E; ++I) { - SourceLocation Start = StartOfFile.getLocWithOffset(I->getOffset()); - SourceLocation End = Start.getLocWithOffset(I->getLength()); - ReformatRanges.push_back(CharSourceRange::getCharRange(Start, End)); - } - - Lexer Lex(ID, SM.getBuffer(ID), SM, getFormattingLangOpts(Style.Standard)); - const tooling::Replacements &R = - format::reformat(Style, Lex, SM, ReformatRanges); - std::copy(R.begin(), R.end(), std::back_inserter(FormatReplacements)); -} diff --git a/clang-tools-extra/cpp11-migrate/Core/Reformatting.h b/clang-tools-extra/cpp11-migrate/Core/Reformatting.h deleted file mode 100644 index 9a10171a742..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/Reformatting.h +++ /dev/null @@ -1,60 +0,0 @@ -//===-- Core/Reformatting.h - LibFormat integration -------------*- 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 LibFormat integration used to reformat -/// migrated code. -/// -//===----------------------------------------------------------------------===// - -#ifndef CPP11_MIGRATE_REFORMATTING_H -#define CPP11_MIGRATE_REFORMATTING_H - -#include "Core/Refactoring.h" -#include "clang/Format/Format.h" - -class FileOverrides; -class ChangedRanges; - -class Reformatter { -public: - Reformatter(const clang::format::FormatStyle &Style) : Style(Style) {} - - /// \brief Reformat the changes made to the file overrides. - /// - /// This function will apply the state of files stored in \c FileState to \c - /// SM. - /// - /// \param[in] FileState Files to reformat. - /// \param[in] SM SourceManager for access to source files. - /// \param[out] Replaces Container to store all reformatting replacements. - void reformatChanges(const FileOverrides &FileState, clang::SourceManager &SM, - clang::tooling::ReplacementsVec &Replaces); - - /// \brief Produce a list of replacements to apply on \p FileName, only the - /// ranges in \p Changes are replaced. - /// - /// Since this routine use \c clang::format::reformat() the rules that - /// function applies to ranges also apply here. - /// - /// \param[in] FileName Name of file to reformat. - /// \param[in] Changes Description of where changes were made to the file. - /// \param[in] SM SourceManager required to create replacements. - /// \param[out] FormatReplacements New reformatting replacements are appended - /// to this container. - void reformatSingleFile(const llvm::StringRef FileName, - const ChangedRanges &Changes, - clang::SourceManager &SM, - clang::tooling::ReplacementsVec &FormatReplacements); - -private: - clang::format::FormatStyle Style; -}; - -#endif // CPP11_MIGRATE_REFORMATTING_H diff --git a/clang-tools-extra/cpp11-migrate/Core/SyntaxCheck.cpp b/clang-tools-extra/cpp11-migrate/Core/SyntaxCheck.cpp deleted file mode 100644 index bd2eb63044f..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/SyntaxCheck.cpp +++ /dev/null @@ -1,73 +0,0 @@ -//===-- Core/SyntaxCheck.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 exposes functionaliy for doing a syntax-only check on -/// files with overridden contents. -/// -//===----------------------------------------------------------------------===// - -#include "Core/SyntaxCheck.h" -#include "Core/FileOverrides.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Tooling/Tooling.h" - -using namespace clang; -using namespace tooling; - -class SyntaxCheck : public SyntaxOnlyAction { -public: - SyntaxCheck(const FileOverrides &Overrides) : Overrides(Overrides) {} - - virtual bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) { - if (!SyntaxOnlyAction::BeginSourceFileAction(CI, Filename)) - return false; - - Overrides.applyOverrides(CI.getSourceManager()); - - return true; - } - -private: - const FileOverrides &Overrides; -}; - -class SyntaxCheckFactory : public FrontendActionFactory { -public: - SyntaxCheckFactory(const FileOverrides &Overrides) - : Overrides(Overrides) {} - - virtual FrontendAction *create() { return new SyntaxCheck(Overrides); } - -private: - const FileOverrides &Overrides; -}; - -class SyntaxArgumentsAdjuster : public ArgumentsAdjuster { - CommandLineArguments Adjust(const CommandLineArguments &Args) { - CommandLineArguments AdjustedArgs = Args; - AdjustedArgs.push_back("-fsyntax-only"); - AdjustedArgs.push_back("-std=c++11"); - return AdjustedArgs; - } -}; - -bool doSyntaxCheck(const CompilationDatabase &Database, - const std::vector<std::string> &SourcePaths, - const FileOverrides &Overrides) { - ClangTool SyntaxTool(Database, SourcePaths); - - // Ensure C++11 support is enabled. - // FIXME: This isn't necessary anymore since the Migrator requires C++11 - // to be enabled in the CompilationDatabase. Remove later. - SyntaxTool.setArgumentsAdjuster(new SyntaxArgumentsAdjuster); - - return SyntaxTool.run(new SyntaxCheckFactory(Overrides)) == 0; -} diff --git a/clang-tools-extra/cpp11-migrate/Core/SyntaxCheck.h b/clang-tools-extra/cpp11-migrate/Core/SyntaxCheck.h deleted file mode 100644 index 1651a7e7acc..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/SyntaxCheck.h +++ /dev/null @@ -1,38 +0,0 @@ -//===-- Core/SyntaxCheck.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 exposes functionaliy for doing a syntax-only check on -/// files with overridden contents. -/// -//===----------------------------------------------------------------------===// - -#ifndef CPP11_MIGRATE_SYNTAX_CHECK_H -#define CPP11_MIGRATE_SYNTAX_CHECK_H - -#include <string> -#include <vector> - -// Forward Declarations -namespace clang { -namespace tooling { -class CompilationDatabase; -} // namespace tooling -} // namespace clang - -class FileOverrides; - -/// \brief Perform a syntax-only check over all files in \c SourcePaths using -/// options provided by \c Database using file contents from \c Overrides if -/// available. -extern bool doSyntaxCheck(const clang::tooling::CompilationDatabase &Database, - const std::vector<std::string> &SourcePaths, - const FileOverrides &Overrides); - -#endif // CPP11_MIGRATE_SYNTAX_CHECK_H diff --git a/clang-tools-extra/cpp11-migrate/Core/Transform.cpp b/clang-tools-extra/cpp11-migrate/Core/Transform.cpp deleted file mode 100644 index cd76723d316..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/Transform.cpp +++ /dev/null @@ -1,172 +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 "Core/FileOverrides.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" - -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) {} - - virtual FrontendAction *create() LLVM_OVERRIDE { - return new FactoryAdaptor(Finder, Owner); - } - -private: - class FactoryAdaptor : public ASTFrontendAction { - public: - FactoryAdaptor(MatchFinder &Finder, Transform &Owner) - : Finder(Finder), Owner(Owner) {} - - ASTConsumer *CreateASTConsumer(CompilerInstance &, StringRef) { - return Finder.newASTConsumer(); - } - - virtual bool BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) LLVM_OVERRIDE { - if (!ASTFrontendAction::BeginSourceFileAction(CI, Filename)) - return false; - - return Owner.handleBeginSource(CI, Filename); - } - - virtual void EndSourceFileAction() LLVM_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), Overrides(0) { - Reset(); -} - -Transform::~Transform() {} - -bool Transform::isFileModifiable(const SourceManager &SM, - const SourceLocation &Loc) const { - if (SM.isWrittenInMainFile(Loc)) - return true; - - if (!GlobalOptions.EnableHeaderModifications) - return false; - - const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Loc)); - if (!FE) - return false; - - return GlobalOptions.ModifiableHeaders.isFileIncluded(FE->getName()); -} - -bool Transform::handleBeginSource(CompilerInstance &CI, StringRef Filename) { - assert(Overrides != 0 && "Subclass transform didn't provide InputState"); - - Overrides->applyOverrides(CI.getSourceManager()); - 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; -} - -FrontendActionFactory *Transform::createActionFactory(MatchFinder &Finder) { - return new ActionFactory(Finder, /*Owner=*/ *this); -} - -Version Version::getFromString(llvm::StringRef VersionStr) { - llvm::StringRef MajorStr, MinorStr; - Version V; - - llvm::tie(MajorStr, MinorStr) = VersionStr.split('.'); - if (!MinorStr.empty()) { - llvm::StringRef Ignore; - llvm::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); -} diff --git a/clang-tools-extra/cpp11-migrate/Core/Transform.h b/clang-tools-extra/cpp11-migrate/Core/Transform.h deleted file mode 100644 index 45e470d64e4..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/Transform.h +++ /dev/null @@ -1,344 +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 CPP11_MIGRATE_TRANSFORM_H -#define CPP11_MIGRATE_TRANSFORM_H - -#include "Core/IncludeExcludeInfo.h" -#include "Core/Refactoring.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Registry.h" -#include "llvm/Support/Timer.h" -#include <string> -#include <vector> - -/// \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 - -class FileOverrides; - - -// \brief Maps main source file names to a TranslationUnitReplacements -// structure storing replacements for that translation unit. -typedef llvm::StringMap<clang::tooling::TranslationUnitReplacements> -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 Allow changes to headers included from the main source file. - /// Transform sub-classes should use ModifiableHeaders to determine which - /// headers are modifiable and which are not. - bool EnableHeaderModifications; - - /// \brief Contains information on which headers are safe to transform and - /// which aren't. - IncludeExcludeInfo ModifiableHeaders; - - /// \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. - /// - /// \p Database must contain information for how to compile all files in \p - /// SourcePaths. \p InputStates contains the file contents of files in \p - /// SourcePaths and should take precedence over content of files on disk. - /// Upon return, \p ResultStates shall contain the result of performing this - /// transform on the files listed in \p SourcePaths. - virtual int apply(const FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, - const std::vector<std::string> &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 Migrator. - bool isFileModifiable(const clang::SourceManager &SM, - const 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<std::pair<std::string, llvm::TimeRecord> > 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 \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 Affords a subclass to provide file contents overrides before - /// applying frontend actions. - /// - /// It is an error not to call this function before calling ClangTool::run() - /// with the factory provided by createActionFactory(). - void setOverrides(const FileOverrides &Overrides) { - this->Overrides = &Overrides; - } - - /// \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(). - clang::tooling::FrontendActionFactory * - createActionFactory(clang::ast_matchers::MatchFinder &Finder); - -private: - const std::string Name; - const TransformOptions &GlobalOptions; - const FileOverrides *Overrides; - 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) LLVM_OVERRIDE { -/// return new MyTransform(Opts); -/// } -/// }; -/// -/// // Register the factory using this statically initialized variable. -/// static TransformFactoryRegistry::Add<MyFactory> -/// X("my-transform", "<Short description of 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<TransformFactory> TransformFactoryRegistry; - -#endif // CPP11_MIGRATE_TRANSFORM_H diff --git a/clang-tools-extra/cpp11-migrate/Core/Transforms.cpp b/clang-tools-extra/cpp11-migrate/Core/Transforms.cpp deleted file mode 100644 index 93701796e24..00000000000 --- a/clang-tools-extra/cpp11-migrate/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; - -static cl::OptionCategory TransformCategory("Transforms"); - -Transforms::~Transforms() { - for (std::vector<Transform *>::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<bool>( - 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; - - llvm::OwningPtr<TransformFactory> 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"; - } -} diff --git a/clang-tools-extra/cpp11-migrate/Core/Transforms.h b/clang-tools-extra/cpp11-migrate/Core/Transforms.h deleted file mode 100644 index 18369407dda..00000000000 --- a/clang-tools-extra/cpp11-migrate/Core/Transforms.h +++ /dev/null @@ -1,82 +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 CPP11_MIGRATE_TRANSFORMS_H -#define CPP11_MIGRATE_TRANSFORMS_H - -#include "llvm/Support/CommandLine.h" -#include "llvm/ADT/StringRef.h" - -#include <vector> - -// Forward declarations -namespace llvm { -namespace cl { -class Option; -} // namespace cl -} // namespace llvm -class Transform; -struct TransformOptions; -struct CompilerVersions; - -typedef Transform *(*TransformCreator)(const TransformOptions &); -template <typename T> -Transform *ConstructTransform(const TransformOptions &Options) { - return new T(Options); -} - -/// \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<Transform*> 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<llvm::cl::opt<bool> *> OptionMap; - -private: - TransformVec ChosenTransforms; - OptionMap Options; -}; - -#endif // CPP11_MIGRATE_TRANSFORMS_H diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopActions.cpp b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopActions.cpp deleted file mode 100644 index 0ba49d8ad4f..00000000000 --- a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopActions.cpp +++ /dev/null @@ -1,1135 +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 cpp11-migrate -/// 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<ForLoopIndexUseVisitor> { - 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(NULL), ConfidenceLevel(RL_Safe), - NextStmtParent(NULL), CurrStmtParent(NULL), 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<Stmt *>(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<ForLoopIndexUseVisitor> VisitorBase; - friend class RecursiveASTVisitor<ForLoopIndexUseVisitor>; - - /// 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<const Expr *, llvm::FoldingSetNodeID>, 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 NULL; - - 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<DeclRefExpr>(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<VarDecl>(DRE->getDecl()); - return NULL; -} - -/// \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<MemberExpr>(E->IgnoreParenImpCasts())) - return isa<CXXThisExpr>(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<int> v; -/// we consider either of these initializations -/// vector<int>::iterator it = v.begin(); -/// vector<int>::iterator it(v.begin()); -/// and retrieve `v.begin()` as the expression used to initialize `it` but do -/// not include -/// vector<int>::iterator it; -/// vector<int>::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 NULL; - E = E->IgnoreParenImpCasts(); - if (const CXXConstructExpr *ConstructExpr = dyn_cast<CXXConstructExpr>(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 NULL; - E = ConstructExpr->getArg(0); - if (const MaterializeTemporaryExpr *Temp = - dyn_cast<MaterializeTemporaryExpr>(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<UnaryOperator>(E)) - return Uop->getOpcode() == UO_Deref ? Uop->getSubExpr() : NULL; - - if (const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(E)) - return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1 ? - OpCall->getArg(0) : NULL; - - return NULL; -} - -/// \brief Returns true when the Container contains an Expr equivalent to E. -template<typename ContainerT> -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<VarDecl>(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<ArraySubscriptExpr>(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<UnaryOperator>(Init), IndexVar); - - case Stmt::CXXOperatorCallExprClass: { - const CXXOperatorCallExpr *OpCall = cast<CXXOperatorCallExpr>(Init); - if (OpCall->getOperator() == OO_Star) - return isDereferenceOfOpCall(OpCall, IndexVar); - break; - } - - 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<Foo> v; -/// \endcode -/// the following uses will be considered convertible: -/// \code -/// for (vector<Foo>::iterator i = v.begin(), e = v.end(); i != e; ++i) { -/// int b = i->bar(); -/// int k = i->x + 1; -/// } -/// \endcode -/// though -/// \code -/// for (vector<Foo>::iterator i = v.begin(), e = v.end(); i != e; ++i) { -/// int k = i.insert(1); -/// } -/// for (vector<Foo>::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<CXXOperatorCallExpr>(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<Foo>::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(); - } - } - - 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.isInvalid()) { - 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<MemberExpr>(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<Foo> v; -/// void f(Foo); -/// \endcode -/// the following uses will be considered convertible: -/// \code -/// for (vector<Foo>::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<int>::iterator i = container.begin(), e = container.end(); -/// i != e; ++i) -/// i.insert(0); -/// for (vector<int>::iterator i = container.begin(), e = container.end(); -/// i != e; ++i) -/// i.insert(0); -/// for (vector<int>::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<IfStmt>(CurrStmtParent) || - isa<WhileStmt>(CurrStmtParent) || - isa<SwitchStmt>(CurrStmtParent)) - ReplaceWithAliasUse = true; - else if (isa<ForStmt>(CurrStmtParent)) { - if (cast<ForStmt>(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<VarDecl>(AliasDecl->getSingleDecl()); - VarName = AliasVar->getName().str(); - AliasVarIsRef = AliasVar->getType()->isReferenceType(); - - // We keep along the entire DeclStmt to keep the correct range here. - const 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(GeneratedDecls, &ParentFinder->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; - ReplacedVarRanges->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)); - GeneratedDecls->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<CXXMemberCallExpr>(digThroughConstructors(Init)); - if (!TheCall || TheCall->getNumArgs() != 0) - return NULL; - - const MemberExpr *Member = dyn_cast<MemberExpr>(TheCall->getCallee()); - if (!Member) - return NULL; - const std::string Name = Member->getMemberDecl()->getName(); - const std::string TargetName = IsBegin ? "begin" : "end"; - if (Name != TargetName) - return NULL; - - const Expr *SourceExpr = Member->getBase(); - if (!SourceExpr) - return NULL; - - *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 NULL; - - 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 NULL; - - *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 (ReplacedVarRanges->count(TheLoop)) { - ++*DeferredChanges; - return ""; - } - - ParentFinder->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(&ParentFinder->getStmtToParentStmtMap(), - &ParentFinder->getDeclToParentStmtMap(), - ReplacedVarRanges, 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<CXXThisExpr>(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<ForStmt>(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<VarDecl>(IncrementVarName); - const VarDecl *CondVar = Nodes.getDeclAs<VarDecl>(ConditionVarName); - const VarDecl *InitVar = Nodes.getDeclAs<VarDecl>(InitVarName); - if (!areSameVariable(LoopVar, CondVar) || !areSameVariable(LoopVar, InitVar)) - return; - const VarDecl *EndVar = Nodes.getDeclAs<VarDecl>(EndVarName); - const VarDecl *ConditionEndVar = - Nodes.getDeclAs<VarDecl>(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<CXXMemberCallExpr>(EndCallName); - const Expr *BoundExpr = Nodes.getStmtAs<Expr>(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 = NULL; - 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<CXXMemberCallExpr>(BeginCallName); - assert(BeginCall != 0 && "Bad Callback. No begin call expression."); - QualType CanonicalBeginType = - BeginCall->getMethodDecl()->getResultType().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<QualType>(DerefByValueResultName) != 0; - if (!DerefByValue) { - if (const QualType *DerefType = - Nodes.getNodeAs<QualType>(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<ReferenceType>()->getPointeeType() - .isConstQualified(); - } else { - // By nature of the matcher this case is triggered only for built-in - // iterator types (i.e. pointers). - assert(isa<PointerType>(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 de-referece operator return 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<MemberExpr>(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); -} diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopActions.h b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopActions.h deleted file mode 100644 index b72576bde82..00000000000 --- a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopActions.h +++ /dev/null @@ -1,105 +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 CPP11_MIGRATE_LOOP_ACTIONS_H -#define CPP11_MIGRATE_LOOP_ACTIONS_H - -#include "StmtAncestor.h" -#include "Core/Transform.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<Usage, 8> UsageResult; - -enum LoopFixerKind { - LFK_Array, - LFK_Iterator, - LFK_PseudoArray -}; - -/// \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(StmtAncestorASTVisitor *ParentFinder, - StmtGeneratedVarNameMap *GeneratedDecls, - ReplacedVarsMap *ReplacedVarRanges, unsigned *AcceptedChanges, - unsigned *DeferredChanges, unsigned *RejectedChanges, - RiskLevel MaxRisk, LoopFixerKind FixerKind, Transform &Owner) - : ParentFinder(ParentFinder), - GeneratedDecls(GeneratedDecls), ReplacedVarRanges(ReplacedVarRanges), - AcceptedChanges(AcceptedChanges), DeferredChanges(DeferredChanges), - RejectedChanges(RejectedChanges), MaxRisk(MaxRisk), - FixerKind(FixerKind), Owner(Owner) {} - - virtual void - run(const clang::ast_matchers::MatchFinder::MatchResult &Result); - - private: - StmtAncestorASTVisitor *ParentFinder; - StmtGeneratedVarNameMap *GeneratedDecls; - ReplacedVarsMap *ReplacedVarRanges; - 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 // CPP11_MIGRATE_LOOP_ACTIONS_H diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.cpp b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.cpp deleted file mode 100644 index 2dfa4562929..00000000000 --- a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.cpp +++ /dev/null @@ -1,89 +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 FileOverrides &InputStates, - const CompilationDatabase &Database, - const std::vector<std::string> &SourcePaths) { - ClangTool LoopTool(Database, SourcePaths); - - StmtAncestorASTVisitor ParentFinder; - StmtGeneratedVarNameMap GeneratedDecls; - ReplacedVarsMap ReplacedVars; - unsigned AcceptedChanges = 0; - unsigned DeferredChanges = 0; - unsigned RejectedChanges = 0; - - MatchFinder Finder; - LoopFixer ArrayLoopFixer(&ParentFinder, &GeneratedDecls, &ReplacedVars, - &AcceptedChanges, &DeferredChanges, &RejectedChanges, - Options().MaxRiskLevel, LFK_Array, - /*Owner=*/ *this); - Finder.addMatcher(makeArrayLoopMatcher(), &ArrayLoopFixer); - LoopFixer IteratorLoopFixer(&ParentFinder, &GeneratedDecls, &ReplacedVars, - &AcceptedChanges, &DeferredChanges, - &RejectedChanges, Options().MaxRiskLevel, - LFK_Iterator, /*Owner=*/ *this); - Finder.addMatcher(makeIteratorLoopMatcher(), &IteratorLoopFixer); - LoopFixer PseudoarrrayLoopFixer(&ParentFinder, &GeneratedDecls, &ReplacedVars, - &AcceptedChanges, &DeferredChanges, - &RejectedChanges, Options().MaxRiskLevel, - LFK_PseudoArray, /*Owner=*/ *this); - Finder.addMatcher(makePseudoArrayLoopMatcher(), &PseudoarrrayLoopFixer); - - setOverrides(InputStates); - - if (int result = LoopTool.run(createActionFactory(Finder))) { - llvm::errs() << "Error encountered during translation.\n"; - return result; - } - - setAcceptedChanges(AcceptedChanges); - setRejectedChanges(RejectedChanges); - setDeferredChanges(DeferredChanges); - - return 0; -} - -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) LLVM_OVERRIDE { - return new LoopConvertTransform(Opts); - } -}; - -// Register the factory using this statically initialized variable. -static TransformFactoryRegistry::Add<LoopConvertFactory> -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; diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.h b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.h deleted file mode 100644 index b45d9555b3d..00000000000 --- a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.h +++ /dev/null @@ -1,36 +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 CPP11_MIGRATE_LOOP_CONVERT_H -#define CPP11_MIGRATE_LOOP_CONVERT_H - -#include "Core/Transform.h" -#include "llvm/Support/Compiler.h" // For LLVM_OVERRIDE - -/// \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(). - virtual int apply(const FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, - const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE; -}; - -#endif // CPP11_MIGRATE_LOOP_CONVERT_H diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopMatchers.cpp b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopMatchers.cpp deleted file mode 100644 index 719c2069fbe..00000000000 --- a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopMatchers.cpp +++ /dev/null @@ -1,346 +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 identifers are bound to the 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 = - memberCallExpr( - argumentCountIs(0), - callee( - methodDecl(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 = - memberCallExpr(argumentCountIs(0), callee(methodDecl(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 = operatorCallExpr( - 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<VarDecl> TestDerefReturnsByValue = - hasType( - recordDecl( - 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) - )) - ) - ), - operatorCallExpr( - 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( - recordDecl( - hasMethod( - methodDecl( - hasName("begin"), - isConst() - ) - ), - hasMethod( - methodDecl( - hasName("end"), - isConst() - ) - ) - ) - ) // hasDeclaration - ), // qualType - qualType( - unless(isConstQualified()), - hasDeclaration( - recordDecl( - hasMethod(hasName("begin")), - hasMethod(hasName("end")) - ) - ) - ) // qualType - ) - ); - - StatementMatcher SizeCallMatcher = - memberCallExpr(argumentCountIs(0), - callee(methodDecl(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); -} diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopMatchers.h b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopMatchers.h deleted file mode 100644 index b0cd8a5a7cc..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 CPP11_MIGRATE_LOOP_MATCHERS_H -#define CPP11_MIGRATE_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 // CPP11_MIGRATE_LOOP_MATCHERS_H diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/StmtAncestor.cpp b/clang-tools-extra/cpp11-migrate/LoopConvert/StmtAncestor.cpp deleted file mode 100644 index 33f576bd814..00000000000 --- a/clang-tools-extra/cpp11-migrate/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<StmtAncestorASTVisitor>::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<VarDecl>(*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<VarDecl>(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 != NULL) { - 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<NamedDecl>(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; -} diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/StmtAncestor.h b/clang-tools-extra/cpp11-migrate/LoopConvert/StmtAncestor.h deleted file mode 100644 index 24079097652..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 CPP11_MIGRATE_STMT_ANCESTOR_H -#define CPP11_MIGRATE_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<const clang::Stmt*, const clang::Stmt*> StmtParentMap; - -/// A map used to walk the AST in reverse: -/// maps VarDecl to the to parent DeclStmt. -typedef -llvm::DenseMap<const clang::VarDecl*, const clang::DeclStmt*> 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<const clang::ForStmt*, const clang::VarDecl*> ReplacedVarsMap; - -/// A map used to remember the variable names generated in a Stmt -typedef llvm::DenseMap<const clang::Stmt*, std::string> StmtGeneratedVarNameMap; - -/// A vector used to store the AST subtrees of an Expr. -typedef llvm::SmallVector<const clang::Expr*, 16> ComponentVector; - -/// \brief Class used build the reverse AST properties needed to detect -/// name conflicts and free variables. -class StmtAncestorASTVisitor : - public clang::RecursiveASTVisitor<StmtAncestorASTVisitor> { -public: - StmtAncestorASTVisitor() { - StmtStack.push_back(NULL); - } - - /// \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<clang::TranslationUnitDecl*>(T)); - } - - /// Accessor for StmtAncestors. - const StmtParentMap &getStmtToParentStmtMap() { - return StmtAncestors; - } - - /// Accessor for DeclParents. - const DeclParentMap &getDeclToParentStmtMap() { - return DeclParents; - } - - friend class clang::RecursiveASTVisitor<StmtAncestorASTVisitor>; - -private: - StmtParentMap StmtAncestors; - DeclParentMap DeclParents; - llvm::SmallVector<const clang::Stmt*, 16> 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<ComponentFinderASTVisitor> { -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<clang::Expr *>(SourceExpr); - TraverseStmt(E); - } - - /// Accessor for Components. - const ComponentVector &getComponents() { - return Components; - } - - friend class clang::RecursiveASTVisitor<ComponentFinderASTVisitor>; - -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<DependencyFinderASTVisitor> { -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<clang::Stmt *>(Body)); - return DependsOnInsideVariable; - } - - friend class clang::RecursiveASTVisitor<DependencyFinderASTVisitor>; - -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<DeclFinderASTVisitor> { -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<clang::Stmt *>(Body)); - return Found; - } - - friend class clang::RecursiveASTVisitor<DeclFinderASTVisitor>; - -private: - std::string Name; - /// GeneratedDecls keeps track of ForStmts which have been tranformed, 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 // CPP11_MIGRATE_STMT_ANCESTOR_H diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/VariableNaming.cpp b/clang-tools-extra/cpp11-migrate/LoopConvert/VariableNaming.cpp deleted file mode 100644 index 853e4830ca6..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 != 0 && "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 != NULL; 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); -} diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/VariableNaming.h b/clang-tools-extra/cpp11-migrate/LoopConvert/VariableNaming.h deleted file mode 100644 index 066ed1e5af4..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 CPP11_MIGRATE_VARIABLE_NAMING_H -#define CPP11_MIGRATE_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 // CPP11_MIGRATE_VARIABLE_NAMING_H diff --git a/clang-tools-extra/cpp11-migrate/Makefile b/clang-tools-extra/cpp11-migrate/Makefile deleted file mode 100644 index f19a25b83af..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 diff --git a/clang-tools-extra/cpp11-migrate/PassByValue/PassByValue.cpp b/clang-tools-extra/cpp11-migrate/PassByValue/PassByValue.cpp deleted file mode 100644 index fbd641233af..00000000000 --- a/clang-tools-extra/cpp11-migrate/PassByValue/PassByValue.cpp +++ /dev/null @@ -1,79 +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 FileOverrides &InputStates, - const tooling::CompilationDatabase &Database, - const std::vector<std::string> &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; - - setOverrides(InputStates); - - if (Tool.run(createActionFactory(Finder))) { - 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); -} - -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) LLVM_OVERRIDE { - return new PassByValueTransform(Opts); - } -}; - -// Register the factory using this statically initialized variable. -static TransformFactoryRegistry::Add<PassByValueFactory> -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; diff --git a/clang-tools-extra/cpp11-migrate/PassByValue/PassByValue.h b/clang-tools-extra/cpp11-migrate/PassByValue/PassByValue.h deleted file mode 100644 index 6dad5497c99..00000000000 --- a/clang-tools-extra/cpp11-migrate/PassByValue/PassByValue.h +++ /dev/null @@ -1,74 +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 CPP11_MIGRATE_PASS_BY_VALUE_H -#define CPP11_MIGRATE_PASS_BY_VALUE_H - -#include "Core/Transform.h" -#include "Core/IncludeDirectives.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 <string> -/// -/// class A { -/// std::string S; -/// public: -/// A(const std::string &S) : S(S) {} -/// }; -/// \endcode -/// the code is transformed to: -/// \code -/// #include <string> -/// -/// 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(0) {} - - /// \see Transform::apply(). - virtual int apply(const FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, - const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE; - -private: - /// \brief Setups the \c IncludeDirectives for the replacer. - virtual bool handleBeginSource(clang::CompilerInstance &CI, - llvm::StringRef Filename) LLVM_OVERRIDE; - - llvm::OwningPtr<IncludeDirectives> IncludeManager; - ConstructorParamReplacer *Replacer; -}; - -#endif // CPP11_MIGRATE_PASS_BY_VALUE_H diff --git a/clang-tools-extra/cpp11-migrate/PassByValue/PassByValueActions.cpp b/clang-tools-extra/cpp11-migrate/PassByValue/PassByValueActions.cpp deleted file mode 100644 index 63189219294..00000000000 --- a/clang-tools-extra/cpp11-migrate/PassByValue/PassByValueActions.cpp +++ /dev/null @@ -1,171 +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 "PassByValueMatchers.h" -#include "Core/IncludeDirectives.h" -#include "Core/Transform.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<ExactlyOneUsageVisitor> { - friend class RecursiveASTVisitor<ExactlyOneUsageVisitor>; - -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<CXXConstructorDecl *>(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<ParmVarDecl>(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 accross all of the -/// redeclarations of \p Ctor. -static void -collectParamDecls(const CXXConstructorDecl *Ctor, const ParmVarDecl *ParamDecl, - llvm::SmallVectorImpl<const ParmVarDecl *> &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<CXXConstructorDecl>(PassByValueCtorId); - const ParmVarDecl *ParamDecl = - Result.Nodes.getNodeAs<ParmVarDecl>(PassByValueParamId); - const CXXCtorInitializer *Initializer = - Result.Nodes.getNodeAs<CXXCtorInitializer>(PassByValueInitializerId); - assert(Ctor && ParamDecl && Initializer && "Bad Callback, missing node."); - - // Check this now to avoid unecessary 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<const ParmVarDecl *, 2> AllParamDecls; - collectParamDecls(Ctor, ParamDecl, AllParamDecls); - - // Generate all replacements for the params. - llvm::SmallVector<Replacement, 2> ParamReplaces(AllParamDecls.size()); - for (unsigned I = 0, E = AllParamDecls.size(); I != E; ++I) { - TypeLoc ParamTL = AllParamDecls[I]->getTypeSourceInfo()->getTypeLoc(); - SourceRange Range(AllParamDecls[I]->getLocStart(), ParamTL.getLocEnd()); - CharSourceRange CharRange = Lexer::makeFileCharRange( - CharSourceRange::getTokenRange(Range), SM, LangOptions()); - TypeLoc ValueTypeLoc = ParamTL; - // transform non-value parameters (e.g: const-ref) to values - if (!ParamTL.getNextTypeLoc().isNull()) - ValueTypeLoc = ParamTL.getNextTypeLoc(); - 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[I] = 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 <utility> 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; -} diff --git a/clang-tools-extra/cpp11-migrate/PassByValue/PassByValueActions.h b/clang-tools-extra/cpp11-migrate/PassByValue/PassByValueActions.h deleted file mode 100644 index 5aeaae4f9fb..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 CPP11_MIGRATE_PASS_BY_VALUE_ACTIONS_H -#define CPP11_MIGRATE_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 \<utility\> 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 <utility> -/// -/// 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(0) {} - - void setIncludeDirectives(IncludeDirectives *Includes) { - IncludeManager = Includes; - } - -private: - /// \brief Entry point to the callback called when matches are made. - virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) - LLVM_OVERRIDE; - - unsigned &AcceptedChanges; - unsigned &RejectedChanges; - Transform &Owner; - IncludeDirectives *IncludeManager; -}; - -#endif // CPP11_MIGRATE_PASS_BY_VALUE_ACTIONS_H diff --git a/clang-tools-extra/cpp11-migrate/PassByValue/PassByValueMatchers.cpp b/clang-tools-extra/cpp11-migrate/PassByValue/PassByValueMatchers.cpp deleted file mode 100644 index 32095e167b7..00000000000 --- a/clang-tools-extra/cpp11-migrate/PassByValue/PassByValueMatchers.cpp +++ /dev/null @@ -1,80 +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; -} - -/// \brief Matches non-deleted copy constructors. -/// -/// Given -/// \code -/// struct Foo { Foo(const Foo &) = default; }; -/// struct Bar { Bar(const Bar &) = deleted; }; -/// \endcode -/// constructorDecl(isNonDeletedCopyConstructor()) -/// matches "Foo(const Foo &)". -AST_MATCHER(CXXConstructorDecl, isNonDeletedCopyConstructor) { - return Node.isCopyConstructor() && !Node.isDeleted(); -} -} // namespace ast_matchers -} // namespace clang - -using namespace clang; -using namespace clang::ast_matchers; - -DeclarationMatcher makePassByValueCtorParamMatcher() { - return constructorDecl( - forEachConstructorInitializer(ctorInitializer( - // 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(constructExpr( - has(declRefExpr(to(parmVarDecl().bind(PassByValueParamId)))), - hasDeclaration(constructorDecl( - isNonDeletedCopyConstructor(), - hasDeclContext(recordDecl(isMoveConstructible()))))))) - .bind(PassByValueInitializerId))) - .bind(PassByValueCtorId); -} diff --git a/clang-tools-extra/cpp11-migrate/PassByValue/PassByValueMatchers.h b/clang-tools-extra/cpp11-migrate/PassByValue/PassByValueMatchers.h deleted file mode 100644 index 8c2bade4385..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 CPP11_MIGRATE_REPLACE_AUTO_PTR_MATCHERS_H -#define CPP11_MIGRATE_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 // CPP11_MIGRATE_REPLACE_AUTO_PTR_MATCHERS_H diff --git a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.cpp b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.cpp deleted file mode 100644 index fae7970b416..00000000000 --- a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.cpp +++ /dev/null @@ -1,70 +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 FileOverrides &InputStates, - const CompilationDatabase &Database, - const std::vector<std::string> &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); - - setOverrides(InputStates); - - if (Tool.run(createActionFactory(Finder))) { - 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) LLVM_OVERRIDE { - return new ReplaceAutoPtrTransform(Opts); - } -}; - -// Register the factory using this statically initialized variable. -static TransformFactoryRegistry::Add<ReplaceAutoPtrFactory> -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; diff --git a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.h b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.h deleted file mode 100644 index c236c99b6c8..00000000000 --- a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtr.h +++ /dev/null @@ -1,55 +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 CPP11_MIGRATE_REPLACE_AUTO_PTR_H -#define CPP11_MIGRATE_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<int> i, j; -/// i = j; -/// \endcode -/// the code is transformed to: -/// \code -/// std::unique_ptr<int> i, j; -/// i = std::move(j); -/// \endcode -class ReplaceAutoPtrTransform : public Transform { -public: - ReplaceAutoPtrTransform(const TransformOptions &Options) - : Transform("ReplaceAutoPtr", Options) {} - - /// \see Transform::run(). - virtual int apply(const FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, - const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE; -}; - -#endif // CPP11_MIGRATE_REPLACE_AUTO_PTR_H diff --git a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrActions.cpp b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrActions.cpp deleted file mode 100644 index 2074e3764bb..00000000000 --- a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrActions.cpp +++ /dev/null @@ -1,108 +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 "ReplaceAutoPtrMatchers.h" -#include "Core/Transform.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<char, 8> 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<TypeLoc>(AutoPtrTokenId)) { - IdentifierLoc = locateFromTypeLoc(*TL, SM); - } else { - const UsingDecl *D = Result.Nodes.getNodeAs<UsingDecl>(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<TemplateSpecializationTypeLoc>(); - 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<Expr>(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; -} diff --git a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrActions.h b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrActions.h deleted file mode 100644 index fb805965b01..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 CPP11_MIGRATE_REPLACE_AUTO_PTR_ACTIONS_H -#define CPP11_MIGRATE_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. - virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) - LLVM_OVERRIDE; - -private: - /// \brief Locates the \c auto_ptr token when it is referred by a \c TypeLoc. - /// - /// \code - /// std::auto_ptr<int> 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<int> 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. - virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) - LLVM_OVERRIDE; - -private: - unsigned &AcceptedChanges; - Transform &Owner; -}; - -#endif // CPP11_MIGRATE_REPLACE_AUTO_PTR_ACTIONS_H diff --git a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrMatchers.cpp b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrMatchers.cpp deleted file mode 100644 index e03a2c342f5..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 = - operatorCallExpr(allOf( - hasOverloadedOperatorName("="), - callee(methodDecl(ofClass(AutoPtrDecl))), - hasArgument(1, MovableArgumentMatcher))); - - StatementMatcher copyCtor = - constructExpr(allOf(hasType(AutoPtrType), - argumentCountIs(1), - hasArgument(0, MovableArgumentMatcher))); - - return anyOf(assignOperator, copyCtor); -} diff --git a/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrMatchers.h b/clang-tools-extra/cpp11-migrate/ReplaceAutoPtr/ReplaceAutoPtrMatchers.h deleted file mode 100644 index 2a87d5b40ed..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 CPP11_MIGRATE_REPLACE_AUTO_PTR_MATCHERS_H -#define CPP11_MIGRATE_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<int> a; -/// ^~~~~~~~~~~~~ -/// -/// typedef std::auto_ptr<int> int_ptr_t; -/// ^~~~~~~~~~~~~ -/// -/// std::auto_ptr<int> fn(std::auto_ptr<int>); -/// ^~~~~~~~~~~~~ ^~~~~~~~~~~~~ -/// -/// <etc...> -/// \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<int> i, j; -/// i = j; -/// ~~~~^ -/// \endcode -clang::ast_matchers::StatementMatcher makeTransferOwnershipExprMatcher(); - -#endif // CPP11_MIGRATE_REPLACE_AUTO_PTR_MATCHERS_H diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp b/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp deleted file mode 100644 index 72f5ae077f2..00000000000 --- a/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp +++ /dev/null @@ -1,71 +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 FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, - const std::vector<std::string> &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); - - setOverrides(InputStates); - - if (int Result = UseAutoTool.run(createActionFactory(Finder))) { - llvm::errs() << "Error encountered during translation.\n"; - return Result; - } - - setAcceptedChanges(AcceptedChanges); - - return 0; -} - -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) LLVM_OVERRIDE { - return new UseAutoTransform(Opts); - } -}; - -// Register the factory using this statically initialized variable. -static TransformFactoryRegistry::Add<UseAutoFactory> -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; diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.h b/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.h deleted file mode 100644 index 26b5e4496f6..00000000000 --- a/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.h +++ /dev/null @@ -1,42 +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 CPP11_MIGRATE_USE_AUTO_H -#define CPP11_MIGRATE_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(). - virtual int apply(const FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, - const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE; -}; - -#endif // CPP11_MIGRATE_USE_AUTO_H diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoActions.cpp b/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoActions.cpp deleted file mode 100644 index 2a8d5c5935d..00000000000 --- a/clang-tools-extra/cpp11-migrate/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<DeclStmt>(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<VarDecl>(*DI); - - const Expr *ExprInit = V->getInit(); - - // Skip expressions with cleanups from the initializer expression. - if (const ExprWithCleanups *E = dyn_cast<ExprWithCleanups>(ExprInit)) - ExprInit = E->getSubExpr(); - - const CXXConstructExpr *Construct = cast<CXXConstructExpr>(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<CXXConstructExpr>(E)) - // If we ran into an implicit conversion constructor, can't convert. - // - // FIXME: The following only checks if the constructor can be used - // implicitly, not if it actually was. Cases where the converting - // constructor was used explicitly won't get converted. - if (NestedConstruct->getConstructor()->isConvertingConstructor(false)) - return; - if (!Result.Context->hasSameType(V->getType(), E->getType())) - return; - } - // Get the type location using the first declartion. - const VarDecl *V = cast<VarDecl>(*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<DeclStmt>(DeclWithNewId); - assert(D && "Bad Callback. No node provided"); - - SourceManager &SM = *Result.SourceManager; - if (!Owner.isFileModifiable(SM, D->getLocStart())) - return; - - const VarDecl *FirstDecl = cast<VarDecl>(*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<SourceLocation> StarLocations; - for (clang::DeclStmt::const_decl_iterator DI = D->decl_begin(), - DE = D->decl_end(); - DI != DE; ++DI) { - - const VarDecl *V = cast<VarDecl>(*DI); - // Ensure that every DeclStmt child is a VarDecl. - assert(V && "No VarDecl provided"); - - const CXXNewExpr *NewExpr = - cast<CXXNewExpr>(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<PointerTypeLoc>(); - while (!Q.isNull()) { - StarLocations.push_back(Q.getStarLoc()); - Q = Q.getNextTypeLoc().getAs<PointerTypeLoc>(); - } - } - - // Remove '*' from declarations using the saved star locations. - for (std::vector<SourceLocation>::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; -} diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoActions.h b/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoActions.h deleted file mode 100644 index 0ddb0e0c5af..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 CPP11_MIGRATE_USE_AUTO_ACTIONS_H -#define CPP11_MIGRATE_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. - virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) - LLVM_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. - virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) - LLVM_OVERRIDE; - -private: - unsigned &AcceptedChanges; - Transform &Owner; -}; - -#endif // CPP11_MIGRATE_USE_AUTO_ACTIONS_H diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp b/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.cpp deleted file mode 100644 index 4f314adb2e3..00000000000 --- a/clang-tools-extra/cpp11-migrate/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<CXXConstructExpr>(Init)) { - if (Construct->isListInitialization()) - return false; - ImplicitInit = Construct->getNumArgs() == 0 || - Construct->getArg(0)->isDefaultArgument(); - } else - if (Node.getInitStyle() == VarDecl::ListInit) - return false; - - return !ImplicitInit; -} - -/// \brief Matches QualTypes that are type sugar for QualTypes that match \c -/// SugarMatcher. -/// -/// Given -/// \code -/// class C {}; -/// typedef C my_type -/// typedef my_type my_other_type; -/// \endcode -/// -/// \c qualType(isSugarFor(recordType(hasDeclaration(namedDecl(hasName("C")))))) -/// matches \c my_type and \c my_other_type. -AST_MATCHER_P(QualType, isSugarFor, internal::Matcher<QualType>, SugarMatcher) { - QualType QT = Node; - for (;;) { - if (SugarMatcher.matches(QT, Finder, Builder)) - return true; - - QualType NewQT = QT.getSingleStepDesugaredType(Finder->getASTContext()); - if (NewQT == QT) - break; - QT = NewQT; - } - return false; -} - -/// \brief Matches named declarations that have one of the standard iterator -/// names: iterator, reverse_iterator, const_iterator, const_reverse_iterator. -/// -/// Given -/// \code -/// iterator I; -/// const_iterator CI; -/// \endcode -/// -/// \c namedDecl(hasStdIteratorName()) matches \c I and \c CI. -AST_MATCHER(NamedDecl, hasStdIteratorName) { - static const char *IteratorNames[] = { - "iterator", - "reverse_iterator", - "const_iterator", - "const_reverse_iterator" - }; - - for (unsigned int i = 0; - i < llvm::array_lengthof(IteratorNames); - ++i) { - if (hasName(IteratorNames[i]).matches(Node, Finder, Builder)) - return true; - } - return false; -} - -/// \brief Matches named declarations that have one of the standard container -/// names. -/// -/// Given -/// \code -/// class vector {}; -/// class forward_list {}; -/// class my_vec {}; -/// \endcode -/// -/// \c recordDecl(hasStdContainerName()) matches \c vector and \c forward_list -/// but not \c my_vec. -AST_MATCHER(NamedDecl, hasStdContainerName) { - static const char *ContainerNames[] = { - "array", - "deque", - "forward_list", - "list", - "vector", - - "map", - "multimap", - "set", - "multiset", - - "unordered_map", - "unordered_multimap", - "unordered_set", - "unordered_multiset", - - "queue", - "priority_queue", - "stack" - }; - - for (unsigned int i = 0; i < llvm::array_lengthof(ContainerNames); ++i) { - if (hasName(ContainerNames[i]).matches(Node, Finder, Builder)) - return true; - } - return false; -} - -} // namespace ast_matchers -} // namespace clang - -namespace { -// \brief Returns a TypeMatcher that matches typedefs for standard iterators -// inside records with a standard container name. -TypeMatcher typedefIterator() { - return typedefType( - hasDeclaration( - allOf( - namedDecl(hasStdIteratorName()), - hasDeclContext( - recordDecl(hasStdContainerName(), isFromStdNamespace()) - ) - ) - ) - ); -} - -// \brief Returns a TypeMatcher that matches records named for standard -// iterators nested inside records named for standard containers. -TypeMatcher nestedIterator() { - return recordType( - hasDeclaration( - allOf( - namedDecl(hasStdIteratorName()), - hasDeclContext( - recordDecl(hasStdContainerName(), isFromStdNamespace()) - ) - ) - ) - ); -} - -// \brief Returns a TypeMatcher that matches types declared with using -// declarations and which name standard iterators for standard containers. -TypeMatcher iteratorFromUsingDeclaration() { - // Types resulting from using declarations are - // represented by ElaboratedType. - return elaboratedType( - allOf( - // Unwrap the nested name specifier to test for - // one of the standard containers. - hasQualifier( - specifiesType( - templateSpecializationType( - hasDeclaration( - namedDecl(hasStdContainerName(), isFromStdNamespace()) - ) - ) - ) - ), - // The named type is what comes after the final - // '::' in the type. It should name one of the - // standard iterator names. - namesType(anyOf( - typedefType( - hasDeclaration( - namedDecl(hasStdIteratorName()) - ) - ), - recordType( - hasDeclaration( - namedDecl(hasStdIteratorName()) - ) - ) - )) - ) - ); -} -} // namespace - -// \brief This matcher returns delaration statements that contain variable -// declarations with written non-list initializer for standard iterators. -StatementMatcher makeIteratorDeclMatcher() { - return declStmt( - // At least one varDecl should be a child of the declStmt to ensure it's a - // declaration list and avoid matching other declarations - // e.g. using directives. - has(varDecl()), - unless(has(varDecl( - anyOf( - unless(hasWrittenNonListInitializer()), - hasType(autoType()), - unless(hasType( - isSugarFor( - anyOf( - typedefIterator(), - nestedIterator(), - iteratorFromUsingDeclaration() - ) - ) - )) - ) - ))) - ).bind(IteratorDeclStmtId); -} - -StatementMatcher makeDeclWithNewMatcher() { - return declStmt( - has(varDecl()), - unless(has(varDecl( - anyOf( - unless(hasInitializer( - ignoringParenImpCasts(newExpr()) - )), - // FIXME: TypeLoc information is not reliable where CV qualifiers are - // concerned so these types can't be handled for now. - hasType(pointerType(pointee(hasCanonicalType(hasLocalQualifiers())))), - - // FIXME: Handle function pointers. For now we ignore them because - // the replacement replaces the entire type specifier source range - // which includes the identifier. - hasType( - pointsTo( - pointsTo( - parenType(innerType(functionType())) - ) - ) - ) - ) - ))) - ).bind(DeclWithNewId); -} diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.h b/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoMatchers.h deleted file mode 100644 index 37baceee047..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 CPP11_MIGRATE_USE_AUTO_MATCHERS_H -#define CPP11_MIGRATE_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 // CPP11_MIGRATE_USE_AUTO_MATCHERS_H diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp deleted file mode 100644 index 23a8fd3a476..00000000000 --- a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp +++ /dev/null @@ -1,450 +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"; - -static cl::opt<std::string> -UserNullMacroNames("user-null-macros", - cl::desc("Comma-separated list of user-defined " - "macro names that behave like NULL"), - cl::cat(TransformsOptionsCategory), cl::init("")); - -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<MacroArgUsageVisitor> { -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<MacroArgUsageVisitor>::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<ImplicitCastExpr>(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<CastSequenceVisitor> { -public: - CastSequenceVisitor(ASTContext &Context, const UserMacroNames &UserNullMacros, - unsigned &AcceptedChanges, Transform &Owner) - : SM(Context.getSourceManager()), Context(Context), - UserNullMacros(UserNullMacros), AcceptedChanges(AcceptedChanges), - Owner(Owner), FirstSubExpr(0), PruneSubtree(false) {} - - bool TraverseStmt(Stmt *S) { - // Stop traversing down the tree if requested. - if (PruneSubtree) { - PruneSubtree = false; - return true; - } - return RecursiveASTVisitor<CastSequenceVisitor>::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<CastExpr>(S); - if (!C) { - FirstSubExpr = 0; - 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<Stmt>(*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<Decl>()) - ArgUsageVisitor.TraverseDecl(const_cast<Decl *>(D)); - else if (const Stmt *S = ContainingAncestor.get<Stmt>()) - ArgUsageVisitor.TraverseStmt(const_cast<Stmt *>(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<FileID, unsigned> 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<FileID, unsigned> 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 { - ASTContext::ParentVector Parents = Context.getParents(Start); - if (Parents.empty()) - return false; - assert(Parents.size() == 1 && - "Found an ancestor with more than one parent!"); - - ASTContext::ParentVector::const_iterator I = Parents.begin(); - - SourceLocation Loc; - if (const Decl *D = I->get<Decl>()) - Loc = D->getLocStart(); - else if (const Stmt *S = I->get<Stmt>()) - Loc = S->getLocStart(); - else - llvm_unreachable("Expected to find Decl or Stmt containing ancestor"); - - if (!expandsFrom(Loc, MacroLoc)) { - Result = *I; - return true; - } - Start = *I; - } 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, RiskLevel, - Transform &Owner) - : AcceptedChanges(AcceptedChanges), Owner(Owner) { - if (!UserNullMacroNames.empty()) { - llvm::StringRef S = UserNullMacroNames; - S.split(UserNullMacros, ","); - } - UserNullMacros.insert(UserNullMacros.begin(), llvm::StringRef(NullMacroName)); -} - -void NullptrFixer::run(const ast_matchers::MatchFinder::MatchResult &Result) { - const CastExpr *NullCast = Result.Nodes.getNodeAs<CastExpr>(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<CastExpr *>(NullCast)); -} diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.h b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.h deleted file mode 100644 index 02da6b76db0..00000000000 --- a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.h +++ /dev/null @@ -1,41 +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 CPP11_MIGRATE_NULLPTR_ACTIONS_H -#define CPP11_MIGRATE_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<llvm::StringRef, 1> UserMacroNames; - -/// \brief The callback to be used for nullptr migration matchers. -/// -class NullptrFixer : public clang::ast_matchers::MatchFinder::MatchCallback { -public: - NullptrFixer(unsigned &AcceptedChanges, RiskLevel, Transform &Owner); - - /// \brief Entry point to the callback called when matches are made. - virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result); - -private: - unsigned &AcceptedChanges; - UserMacroNames UserNullMacros; - Transform &Owner; -}; - -#endif // CPP11_MIGRATE_NULLPTR_ACTIONS_H diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrMatchers.cpp b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrMatchers.cpp deleted file mode 100644 index 0995c168b50..00000000000 --- a/clang-tools-extra/cpp11-migrate/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<BuiltinType>(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); -} diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrMatchers.h b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrMatchers.h deleted file mode 100644 index b6b686859a6..00000000000 --- a/clang-tools-extra/cpp11-migrate/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 CPP11_MIGRATE_USE_NULLPTR_MATCHERS_H -#define CPP11_MIGRATE_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 // CPP11_MIGRATE_USE_NULLPTR_MATCHERS_H diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.cpp b/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.cpp deleted file mode 100644 index e07ee6682ee..00000000000 --- a/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.cpp +++ /dev/null @@ -1,70 +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; - -int UseNullptrTransform::apply(const FileOverrides &InputStates, - const CompilationDatabase &Database, - const std::vector<std::string> &SourcePaths) { - ClangTool UseNullptrTool(Database, SourcePaths); - - unsigned AcceptedChanges = 0; - - MatchFinder Finder; - NullptrFixer Fixer(AcceptedChanges, Options().MaxRiskLevel, /*Owner=*/ *this); - - Finder.addMatcher(makeCastSequenceMatcher(), &Fixer); - - setOverrides(InputStates); - - if (int result = UseNullptrTool.run(createActionFactory(Finder))) { - llvm::errs() << "Error encountered during translation.\n"; - return result; - } - - setAcceptedChanges(AcceptedChanges); - - return 0; -} - -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) LLVM_OVERRIDE { - return new UseNullptrTransform(Opts); - } -}; - -// Register the factory using this statically initialized variable. -static TransformFactoryRegistry::Add<UseNullptrFactory> -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; diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.h b/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.h deleted file mode 100644 index ed90f9a5bbc..00000000000 --- a/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.h +++ /dev/null @@ -1,36 +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 CPP11_MIGRATE_USE_NULLPTR_H -#define CPP11_MIGRATE_USE_NULLPTR_H - -#include "Core/Transform.h" -#include "llvm/Support/Compiler.h" // For LLVM_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(). - virtual int apply(const FileOverrides &InputStates, - const clang::tooling::CompilationDatabase &Database, - const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE; -}; - -#endif // CPP11_MIGRATE_USE_NULLPTR_H diff --git a/clang-tools-extra/cpp11-migrate/tool/CMakeLists.txt b/clang-tools-extra/cpp11-migrate/tool/CMakeLists.txt deleted file mode 100644 index 06e61c37e6d..00000000000 --- a/clang-tools-extra/cpp11-migrate/tool/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ -set(LLVM_LINK_COMPONENTS support) - -set (Cpp11MigrateSources - Cpp11Migrate.cpp - ) - -# FIXME: Lib-ify the transforms to simplify the build rules. - -# For each transform subdirectory. -file(GLOB_RECURSE LoopConvertSources "../LoopConvert/*.cpp") -list(APPEND Cpp11MigrateSources ${LoopConvertSources}) - -file(GLOB_RECURSE UseNullptrSources "../UseNullptr/*.cpp") -list(APPEND Cpp11MigrateSources ${UseNullptrSources}) - -file(GLOB_RECURSE UseAutoSources "../UseAuto/*.cpp") -list(APPEND Cpp11MigrateSources ${UseAutoSources}) - -file(GLOB_RECURSE AddOverrideSources "../AddOverride/*.cpp") -list(APPEND Cpp11MigrateSources ${AddOverrideSources}) - -file(GLOB_RECURSE PassByValueSources "../PassByValue/*.cpp") -list(APPEND Cpp11MigrateSources ${PassByValueSources}) - -file(GLOB_RECURSE ReplaceAutoPtrSources "../ReplaceAutoPtr/*.cpp") -list(APPEND Cpp11MigrateSources ${ReplaceAutoPtrSources}) - -add_clang_executable(cpp11-migrate - ${Cpp11MigrateSources} - ) - -add_dependencies(cpp11-migrate - clang-headers - ) - -target_link_libraries(cpp11-migrate - clangApplyReplacements - migrateCore - ) - -install(TARGETS cpp11-migrate - RUNTIME DESTINATION bin) diff --git a/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp b/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp deleted file mode 100644 index 14d55609b22..00000000000 --- a/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp +++ /dev/null @@ -1,494 +0,0 @@ -//===-- cpp11-migrate/Cpp11Migrate.cpp - Main file C++11 migration 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/FileOverrides.h" -#include "Core/PerfSupport.h" -#include "Core/SyntaxCheck.h" -#include "Core/Transform.h" -#include "Core/Transforms.h" -#include "Core/Reformatting.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Rewrite/Core/Rewriter.h" -#include "clang/Tooling/CommonOptionsParser.h" -#include "clang/Tooling/Tooling.h" -#include "clang-apply-replacements/Tooling/ApplyReplacements.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Signals.h" - -namespace cl = llvm::cl; -using namespace clang; -using namespace clang::tooling; - -TransformOptions GlobalOptions; - -static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); -static cl::opt<std::string> BuildPath( - "p", cl::desc("Build Path"), cl::Optional); -static cl::list<std::string> SourcePaths( - cl::Positional, cl::desc("<source0> [... <sourceN>]"), cl::OneOrMore); -static cl::extrahelp MoreHelp( - "EXAMPLES:\n\n" - "Apply all transforms on a given file, no compilation database:\n\n" - " cpp11-migrate path/to/file.cpp -- -Ipath/to/include/\n" - "\n" - "Convert for loops to the new ranged-based for loops on all files in a " - "subtree\nand reformat the code automatically using the LLVM style:\n\n" - " find path/in/subtree -name '*.cpp' -exec \\\n" - " cpp11-migrate -p build/path -format-style=LLVM -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{} cpp11-migrate -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:\n\n" - " cpp11-migrate -for-compilers=clang-3.0,gcc-4.7 foo.cpp -- -Ibar\n"); - -static cl::opt<RiskLevel, /*ExternalStorage=*/true> 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)); - -static cl::opt<bool> FinalSyntaxCheck( - "final-syntax-check", - cl::desc("Check for correct syntax after applying transformations"), - cl::init(false)); - -static cl::opt<std::string> FormatStyleOpt( - "format-style", - cl::desc("Coding style to use on the replacements, either a builtin style\n" - "or a YAML config file (see: clang-format -dump-config).\n" - "Currently supports 4 builtins style:\n" - " LLVM, Google, Chromium, Mozilla.\n"), - cl::value_desc("string")); - -static cl::opt<bool> -SummaryMode("summary", cl::desc("Print transform summary"), - cl::init(false)); - -const char NoTiming[] = "no_timing"; -static cl::opt<std::string> TimingDirectoryName( - "perf", cl::desc("Capture performance data and output to specified " - "directory. Default: ./migrate_perf"), - cl::init(NoTiming), cl::ValueOptional, cl::value_desc("directory name")); - -// TODO: Remove cl::Hidden when functionality for acknowledging include/exclude -// options are implemented in the tool. -static cl::opt<std::string> -IncludePaths("include", cl::Hidden, - cl::desc("Comma seperated list of paths to consider to be " - "transformed")); -static cl::opt<std::string> -ExcludePaths("exclude", cl::Hidden, - cl::desc("Comma seperated list of paths that can not " - "be transformed")); -static cl::opt<std::string> -IncludeFromFile("include-from", cl::Hidden, cl::value_desc("filename"), - cl::desc("File containing a list of paths to consider to " - "be transformed")); -static cl::opt<std::string> -ExcludeFromFile("exclude-from", cl::Hidden, cl::value_desc("filename"), - cl::desc("File containing a list of paths that can not be " - "transforms")); - -// Header modifications will probably be always on eventually. For now, they -// need to be explicitly enabled. -static cl::opt<bool, /*ExternalStorage=*/true> EnableHeaderModifications( - "headers", - cl::Hidden, // Experimental feature for now. - cl::desc("Enable modifications to headers"), - cl::location(GlobalOptions.EnableHeaderModifications), - cl::init(false)); - -static cl::opt<bool> -SerializeReplacements("serialize-replacements", - cl::Hidden, // Associated with -headers - cl::desc("Serialize translation unit replacements to " - "disk instead of changing files."), - cl::init(false)); - -cl::opt<std::string> 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-seperated list of <compiler>-<version>.\n" - "\t<compiler> can be any of: clang, gcc, icc, msvc\n" - "\t<version> is <major>[.<minor>]\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<llvm::StringRef, 4> Compilers; - - llvm::StringRef(SupportedCompilers).split(Compilers, ","); - - for (llvm::SmallVectorImpl<llvm::StringRef>::iterator I = Compilers.begin(), - E = Compilers.end(); - I != E; ++I) { - llvm::StringRef Compiler, VersionStr; - llvm::tie(Compiler, VersionStr) = I->split('-'); - Version *V = llvm::StringSwitch<Version *>(Compiler) - .Case("clang", &RequiredVersions.Clang) - .Case("gcc", &RequiredVersions.Gcc).Case("icc", &RequiredVersions.Icc) - .Case("msvc", &RequiredVersions.Msvc).Default(NULL); - - if (V == NULL) { - 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 \"<major>[.<minor>]\" instead of \"" - << VersionStr << "\"\n"; - Error = true; - continue; - } - // support the lowest version given - if (V->isNull() || Version < *V) - *V = Version; - } - return RequiredVersions; -} - -/// \brief Creates the Reformatter if the format style option is provided, -/// return a null pointer otherwise. -/// -/// \param ProgName The name of the program, \c argv[0], used to print errors. -/// \param Error If the \c -format-style is provided but with wrong parameters -/// this is parameter is set to \c true, left untouched otherwise. An error -/// message is printed with an explanation. -static Reformatter *handleFormatStyle(const char *ProgName, bool &Error) { - if (FormatStyleOpt.getNumOccurrences() > 0) { - format::FormatStyle Style; - if (!format::getPredefinedStyle(FormatStyleOpt, &Style)) { - llvm::StringRef ConfigFilePath = FormatStyleOpt; - llvm::OwningPtr<llvm::MemoryBuffer> Text; - llvm::error_code ec; - - ec = llvm::MemoryBuffer::getFile(ConfigFilePath, Text); - if (!ec) - ec = parseConfiguration(Text->getBuffer(), &Style); - - if (ec) { - llvm::errs() << ProgName << ": invalid format style " << FormatStyleOpt - << ": " << ec.message() << "\n"; - Error = true; - return 0; - } - } - - // force mode to C++11 - Style.Standard = clang::format::FormatStyle::LS_Cpp11; - return new Reformatter(Style); - } - return 0; -} - -/// \brief Use \c ChangesReformatter to reformat all changed regions of all -/// files stored in \c Overrides and write the result to disk. -/// -/// \returns \li true if reformatting replacements were successfully applied -/// without conflicts and all files were successfully written to -/// disk. -/// \li false if reformatting could not be successfully applied or -/// if at least one file failed to write to disk. -bool reformat(Reformatter &ChangesReformatter, const FileOverrides &Overrides, - DiagnosticsEngine &Diagnostics) { - FileManager Files((FileSystemOptions())); - SourceManager SM(Diagnostics, Files); - - replace::TUReplacements AllReplacements(1); - ChangesReformatter.reformatChanges(Overrides, SM, - AllReplacements.front().Replacements); - - replace::FileToReplacementsMap GroupedReplacements; - if (!replace::mergeAndDeduplicate(AllReplacements, GroupedReplacements, SM)) { - llvm::errs() << "Warning: Reformatting produced conflicts.\n"; - return false; - } - - Rewriter DestRewriter(SM, LangOptions()); - if (!replace::applyReplacements(GroupedReplacements, DestRewriter)) { - llvm::errs() << "Warning: Failed to apply reformatting conflicts!\n"; - return false; - } - - return replace::writeFiles(DestRewriter); -} - -bool serializeReplacements(const replace::TUReplacements &Replacements) { - bool Errors = false; - for (replace::TUReplacements::const_iterator I = Replacements.begin(), - E = Replacements.end(); - I != E; ++I) { - llvm::SmallString<128> ReplacementsFileName; - llvm::SmallString<64> Error; - bool Result = generateReplacementsFileName(I->MainSourceFile, - ReplacementsFileName, Error); - if (!Result) { - llvm::errs() << "Failed to generate replacements filename:" << Error - << "\n"; - Errors = true; - continue; - } - - std::string ErrorInfo; - llvm::raw_fd_ostream ReplacementsFile(ReplacementsFileName.c_str(), - ErrorInfo, llvm::sys::fs::F_Binary); - if (!ErrorInfo.empty()) { - llvm::errs() << "Error opening file: " << ErrorInfo << "\n"; - Errors = true; - continue; - } - llvm::yaml::Output YAML(ReplacementsFile); - YAML << const_cast<TranslationUnitReplacements &>(*I); - } - return !Errors; -} - -int main(int argc, const char **argv) { - llvm::sys::PrintStackTraceOnErrorSignal(); - Transforms TransformManager; - - TransformManager.registerTransforms(); - - // Parse options and generate compilations. - OwningPtr<CompilationDatabase> Compilations( - FixedCompilationDatabase::loadFromCommandLine(argc, argv)); - cl::ParseCommandLineOptions(argc, argv); - - if (!Compilations) { - std::string ErrorMessage; - if (BuildPath.getNumOccurrences() > 0) { - Compilations.reset(CompilationDatabase::autoDetectFromDirectory( - BuildPath, ErrorMessage)); - } else { - Compilations.reset(CompilationDatabase::autoDetectFromSource( - SourcePaths[0], ErrorMessage)); - // If no compilation database can be detected from source then we create - // a new FixedCompilationDatabase with c++11 support. - if (!Compilations) { - std::string CommandLine[] = {"-std=c++11"}; - Compilations.reset(new FixedCompilationDatabase(".", CommandLine)); - } - } - if (!Compilations) - llvm::report_fatal_error(ErrorMessage); - } - - // Since ExecutionTimeDirectoryName could be an empty string we compare - // against the default value when the command line option is not specified. - GlobalOptions.EnableTiming = (TimingDirectoryName != NoTiming); - - // Check the reformatting style option - bool CmdSwitchError = false; - llvm::OwningPtr<Reformatter> ChangesReformatter( - handleFormatStyle(argv[0], CmdSwitchError)); - - CompilerVersions RequiredVersions = - handleSupportedCompilers(argv[0], CmdSwitchError); - if (CmdSwitchError) - return 1; - - // Populate the ModifiableHeaders structure if header modifications are - // enabled. - if (GlobalOptions.EnableHeaderModifications) { - GlobalOptions.ModifiableHeaders - .readListFromString(IncludePaths, ExcludePaths); - GlobalOptions.ModifiableHeaders - .readListFromFile(IncludeFromFile, ExcludeFromFile); - } - - TransformManager.createSelectedTransforms(GlobalOptions, RequiredVersions); - - llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts( - new DiagnosticOptions()); - DiagnosticsEngine Diagnostics( - llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), - DiagOpts.getPtr()); - - // FIXME: Make this DiagnosticsEngine available to all Transforms probably via - // GlobalOptions. - - if (TransformManager.begin() == TransformManager.end()) { - if (SupportedCompilers.empty()) - llvm::errs() << argv[0] << ": no selected transforms\n"; - else - llvm::errs() << argv[0] - << ": no transforms available for specified compilers\n"; - return 1; - } - - // If SerializeReplacements is requested, then change reformatting must be - // turned off and only one transform should be requested. Reformatting is - // basically another transform so even if there's only one other transform, - // the reformatting pass would make two. - if (SerializeReplacements && - (std::distance(TransformManager.begin(), TransformManager.end()) > 1 || - ChangesReformatter)) { - llvm::errs() << "Serialization of replacements requested for multiple " - "transforms.\nChanges from only one transform can be " - "serialized.\n"; - return 1; - } - - SourcePerfData PerfData; - FileOverrides FileStates; - - for (Transforms::const_iterator I = TransformManager.begin(), - E = TransformManager.end(); - I != E; ++I) { - Transform *T = *I; - - if (T->apply(FileStates, *Compilations, SourcePaths) != 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"; - } - - // Collect all TranslationUnitReplacements generated from the translation - // units the transform worked on and store them in AllReplacements. - replace::TUReplacements AllReplacements; - const TUReplacementsMap &ReplacementsMap = T->getAllReplacements(); - const TranslationUnitReplacements &( - TUReplacementsMap::value_type::*getValue)() const = - &TUReplacementsMap::value_type::getValue; - std::transform(ReplacementsMap.begin(), ReplacementsMap.end(), - std::back_inserter(AllReplacements), - std::mem_fun_ref(getValue)); - - if (SerializeReplacements) - serializeReplacements(AllReplacements); - - FileManager Files((FileSystemOptions())); - SourceManager SM(Diagnostics, Files); - - // Make sure SourceManager is updated to have the same initial state as the - // transforms. - FileStates.applyOverrides(SM); - - replace::FileToReplacementsMap GroupedReplacements; - if (!replace::mergeAndDeduplicate(AllReplacements, GroupedReplacements, - SM)) { - llvm::outs() << "Transform " << T->getName() - << " resulted in conflicts. Discarding all " - << "replacements.\n"; - continue; - } - - // Apply replacements and update FileStates with new state. - Rewriter DestRewriter(SM, LangOptions()); - if (!replace::applyReplacements(GroupedReplacements, DestRewriter)) { - llvm::outs() << "Some replacements failed to apply. Discarding " - "all replacements.\n"; - continue; - } - - // Update contents of files in memory to serve as initial state for next - // transform. - FileStates.updateState(DestRewriter); - - // Update changed ranges for reformatting - if (ChangesReformatter) - FileStates.adjustChangedRanges(GroupedReplacements); - } - - // Skip writing final file states to disk if we were asked to serialize - // replacements. Otherwise reformat changes if reformatting is enabled. If - // not enabled or if reformatting fails write un-formated changes to disk - // instead. reformat() takes care of writing successfully formatted changes. - if (!SerializeReplacements && - (!ChangesReformatter || - !reformat(*ChangesReformatter, FileStates, Diagnostics))) - FileStates.writeToDisk(Diagnostics); - - if (FinalSyntaxCheck) - if (!doSyntaxCheck(*Compilations, SourcePaths, FileStates)) - 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 -}; diff --git a/clang-tools-extra/cpp11-migrate/tool/Makefile b/clang-tools-extra/cpp11-migrate/tool/Makefile deleted file mode 100644 index 8c4d0105386..00000000000 --- a/clang-tools-extra/cpp11-migrate/tool/Makefile +++ /dev/null @@ -1,57 +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 = cpp11-migrate - -# No plugins, optimize startup time. -TOOL_NO_EXPORTS = 1 - -SOURCES = Cpp11Migrate.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 = migrateCore.a clangFormat.a clangApplyReplacements.a clangTooling.a clangFrontend.a \ - clangSerialization.a clangDriver.a clangRewriteFrontend.a \ - clangRewriteCore.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)/.. -I$(PROJ_SRC_DIR)/../../clang-apply-replacements/include - -# 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 /<name>/ 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) > $@ - |