Index: include/clang/Tooling/Core/Environment.h =================================================================== --- /dev/null +++ include/clang/Tooling/Core/Environment.h @@ -0,0 +1,55 @@ +//===--- Environment.h - Sourece tooling environment --*- C++ -*-----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_CORE_ENVIRONMENT_H +#define LLVM_CLANG_TOOLING_CORE_ENVIRONMENT_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" + +namespace clang { +namespace tooling { + +/// An environment for handling file contents with SourceManager. +class Environment { +public: + Environment(SourceManager &SM, FileID ID) : ID(ID), SM(SM) {} + + Environment(FileID ID, std::unique_ptr FileMgr, + std::unique_ptr VirtualSM, + std::unique_ptr Diagnostics) + : ID(ID), SM(*VirtualSM), FileMgr(std::move(FileMgr)), + VirtualSM(std::move(VirtualSM)), Diagnostics(std::move(Diagnostics)) {} + + // This sets up an virtual file system with file \p FileName containing the + // fragment \p Content. + static std::unique_ptr + createVirtualEnvironment(StringRef Content, StringRef FileName); + + FileID getFileID() const { return ID; } + + const SourceManager &getSourceManager() const { return SM; } + +private: + FileID ID; + SourceManager &SM; + + // The order of these fields are important - they should be in the same order + // as they are created in `createVirtualEnvironment` so that they can be + // deleted in the reverse order as they are created. + std::unique_ptr FileMgr; + std::unique_ptr VirtualSM; + std::unique_ptr Diagnostics; +}; + +} // namespace tooling +} // namespace clang + +#endif // LLVM_CLANG_TOOLING_CORE_ENVIRONMENT_H Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -1882,10 +1882,9 @@ StringRef FileName, StringRef Code, const FormatStyle &Style, llvm::function_ref GetOffsetAfterSequence) { - std::unique_ptr Env = - Environment::CreateVirtualEnvironment(Code, FileName, /*Ranges=*/{}); - const SourceManager &SourceMgr = Env->getSourceManager(); - Lexer Lex(Env->getFileID(), SourceMgr.getBuffer(Env->getFileID()), SourceMgr, + Environment Env(Code, FileName, /*Ranges=*/{}); + const SourceManager &SourceMgr = Env.getSourceManager(); + Lexer Lex(Env.getFileID(), SourceMgr.getBuffer(Env.getFileID()), SourceMgr, getFormattingLangOpts(Style)); Token Tok; // Get the first token. @@ -2192,14 +2191,13 @@ return Formatter(Env, Expanded, Status).process(); }); - std::unique_ptr Env = Environment::CreateVirtualEnvironment( - Code, FileName, Ranges, FirstStartColumn, NextStartColumn, - LastStartColumn); + Environment Env(Code, FileName, Ranges, FirstStartColumn, NextStartColumn, + LastStartColumn); llvm::Optional CurrentCode = None; tooling::Replacements Fixes; unsigned Penalty = 0; for (size_t I = 0, E = Passes.size(); I < E; ++I) { - std::pair PassFixes = Passes[I](*Env); + std::pair PassFixes = Passes[I](Env); auto NewCode = applyAllReplacements( CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first); if (NewCode) { @@ -2207,7 +2205,7 @@ Penalty += PassFixes.second; if (I + 1 < E) { CurrentCode = std::move(*NewCode); - Env = Environment::CreateVirtualEnvironment( + Env = Environment( *CurrentCode, FileName, tooling::calculateRangesAfterReplacements(Fixes, Ranges), FirstStartColumn, NextStartColumn, LastStartColumn); @@ -2236,10 +2234,7 @@ // cleanups only apply to C++ (they mostly concern ctor commas etc.) if (Style.Language != FormatStyle::LK_Cpp) return tooling::Replacements(); - std::unique_ptr Env = - Environment::CreateVirtualEnvironment(Code, FileName, Ranges); - Cleaner Clean(*Env, Style); - return Clean.process().first; + return Cleaner(Environment(Code, FileName, Ranges), Style).process().first; } tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, @@ -2256,20 +2251,18 @@ StringRef Code, ArrayRef Ranges, StringRef FileName) { - std::unique_ptr Env = - Environment::CreateVirtualEnvironment(Code, FileName, Ranges); - NamespaceEndCommentsFixer Fix(*Env, Style); - return Fix.process().first; + return NamespaceEndCommentsFixer(Environment(Code, FileName, Ranges), Style) + .process() + .first; } tooling::Replacements sortUsingDeclarations(const FormatStyle &Style, StringRef Code, ArrayRef Ranges, StringRef FileName) { - std::unique_ptr Env = - Environment::CreateVirtualEnvironment(Code, FileName, Ranges); - UsingDeclarationsSorter Sorter(*Env, Style); - return Sorter.process().first; + return UsingDeclarationsSorter(Environment(Code, FileName, Ranges), Style) + .process() + .first; } LangOptions getFormattingLangOpts(const FormatStyle &Style) { @@ -2329,9 +2322,8 @@ // of the code to see if it contains Objective-C. if (Extension.empty() || Extension == ".h") { auto NonEmptyFileName = FileName.empty() ? "guess.h" : FileName; - std::unique_ptr Env = - Environment::CreateVirtualEnvironment(Code, NonEmptyFileName, /*Ranges=*/{}); - ObjCHeaderStyleGuesser Guesser(*Env, getLLVMStyle()); + Environment Env(Code, NonEmptyFileName, /*Ranges=*/{}); + ObjCHeaderStyleGuesser Guesser(Env, getLLVMStyle()); Guesser.process(); if (Guesser.isObjC()) return FormatStyle::LK_ObjC; Index: lib/Format/SortJavaScriptImports.cpp =================================================================== --- lib/Format/SortJavaScriptImports.cpp +++ lib/Format/SortJavaScriptImports.cpp @@ -445,10 +445,9 @@ ArrayRef Ranges, StringRef FileName) { // FIXME: Cursor support. - std::unique_ptr Env = - Environment::CreateVirtualEnvironment(Code, FileName, Ranges); - JavaScriptImportSorter Sorter(*Env, Style); - return Sorter.process().first; + return JavaScriptImportSorter(Environment(Code, FileName, Ranges), Style) + .process() + .first; } } // end namespace format Index: lib/Format/TokenAnalyzer.h =================================================================== --- lib/Format/TokenAnalyzer.h +++ lib/Format/TokenAnalyzer.h @@ -28,6 +28,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" +#include "clang/Tooling/Core/Environment.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" @@ -37,43 +38,26 @@ class Environment { public: Environment(SourceManager &SM, FileID ID, ArrayRef Ranges) - : ID(ID), CharRanges(Ranges.begin(), Ranges.end()), SM(SM), - FirstStartColumn(0), - NextStartColumn(0), - LastStartColumn(0) {} - - Environment(FileID ID, std::unique_ptr FileMgr, - std::unique_ptr VirtualSM, - std::unique_ptr Diagnostics, - const std::vector &CharRanges, - unsigned FirstStartColumn, - unsigned NextStartColumn, - unsigned LastStartColumn) - : ID(ID), CharRanges(CharRanges.begin(), CharRanges.end()), - SM(*VirtualSM), - FirstStartColumn(FirstStartColumn), - NextStartColumn(NextStartColumn), - LastStartColumn(LastStartColumn), - FileMgr(std::move(FileMgr)), - VirtualSM(std::move(VirtualSM)), Diagnostics(std::move(Diagnostics)) {} + : ToolEnv(new tooling::Environment(SM, ID)), + CharRanges(Ranges.begin(), Ranges.end()), FirstStartColumn(0), + NextStartColumn(0), LastStartColumn(0) {} // This sets up an virtual file system with file \p FileName containing the // fragment \p Code. Assumes that \p Code starts at \p FirstStartColumn, // that the next lines of \p Code should start at \p NextStartColumn, and // that \p Code should end at \p LastStartColumn if it ends in newline. // See also the documentation of clang::format::internal::reformat. - static std::unique_ptr - CreateVirtualEnvironment(StringRef Code, StringRef FileName, - ArrayRef Ranges, - unsigned FirstStartColumn = 0, - unsigned NextStartColumn = 0, - unsigned LastStartColumn = 0); + Environment(StringRef Code, StringRef FileName, + ArrayRef Ranges, unsigned FirstStartColumn = 0, + unsigned NextStartColumn = 0, unsigned LastStartColumn = 0); - FileID getFileID() const { return ID; } + FileID getFileID() const { return ToolEnv->getFileID(); } - ArrayRef getCharRanges() const { return CharRanges; } + const SourceManager &getSourceManager() const { + return ToolEnv->getSourceManager(); + } - const SourceManager &getSourceManager() const { return SM; } + ArrayRef getCharRanges() const { return CharRanges; } // Returns the column at which the fragment of code managed by this // environment starts. @@ -88,19 +72,11 @@ unsigned getLastStartColumn() const { return LastStartColumn; } private: - FileID ID; + std::unique_ptr ToolEnv; SmallVector CharRanges; - SourceManager &SM; unsigned FirstStartColumn; unsigned NextStartColumn; unsigned LastStartColumn; - - // The order of these fields are important - they should be in the same order - // as they are created in `CreateVirtualEnvironment` so that they can be - // deleted in the reverse order as they are created. - std::unique_ptr FileMgr; - std::unique_ptr VirtualSM; - std::unique_ptr Diagnostics; }; class TokenAnalyzer : public UnwrappedLineConsumer { Index: lib/Format/TokenAnalyzer.cpp =================================================================== --- lib/Format/TokenAnalyzer.cpp +++ lib/Format/TokenAnalyzer.cpp @@ -34,48 +34,20 @@ namespace clang { namespace format { -// This sets up an virtual file system with file \p FileName containing \p -// Code. -std::unique_ptr -Environment::CreateVirtualEnvironment(StringRef Code, StringRef FileName, - ArrayRef Ranges, - unsigned FirstStartColumn, - unsigned NextStartColumn, - unsigned LastStartColumn) { - // This is referenced by `FileMgr` and will be released by `FileMgr` when it - // is deleted. - IntrusiveRefCntPtr InMemoryFileSystem( - new vfs::InMemoryFileSystem); - // This is passed to `SM` as reference, so the pointer has to be referenced - // in `Environment` so that `FileMgr` can out-live this function scope. - std::unique_ptr FileMgr( - new FileManager(FileSystemOptions(), InMemoryFileSystem)); - // This is passed to `SM` as reference, so the pointer has to be referenced - // by `Environment` due to the same reason above. - std::unique_ptr Diagnostics(new DiagnosticsEngine( - IntrusiveRefCntPtr(new DiagnosticIDs), - new DiagnosticOptions)); - // This will be stored as reference, so the pointer has to be stored in - // due to the same reason above. - std::unique_ptr VirtualSM( - new SourceManager(*Diagnostics, *FileMgr)); - InMemoryFileSystem->addFile( - FileName, 0, - llvm::MemoryBuffer::getMemBuffer(Code, FileName, - /*RequiresNullTerminator=*/false)); - FileID ID = VirtualSM->createFileID(FileMgr->getFile(FileName), - SourceLocation(), clang::SrcMgr::C_User); - assert(ID.isValid()); - SourceLocation StartOfFile = VirtualSM->getLocForStartOfFile(ID); - std::vector CharRanges; +Environment::Environment(StringRef Code, StringRef FileName, + ArrayRef Ranges, + unsigned FirstStartColumn, unsigned NextStartColumn, + unsigned LastStartColumn) + : ToolEnv(tooling::Environment::createVirtualEnvironment(Code, FileName)), + FirstStartColumn(FirstStartColumn), NextStartColumn(NextStartColumn), + LastStartColumn(LastStartColumn) { + SourceLocation StartOfFile = + ToolEnv->getSourceManager().getLocForStartOfFile(ToolEnv->getFileID()); for (const tooling::Range &Range : Ranges) { SourceLocation Start = StartOfFile.getLocWithOffset(Range.getOffset()); SourceLocation End = Start.getLocWithOffset(Range.getLength()); CharRanges.push_back(CharSourceRange::getCharRange(Start, End)); } - return llvm::make_unique( - ID, std::move(FileMgr), std::move(VirtualSM), std::move(Diagnostics), - CharRanges, FirstStartColumn, NextStartColumn, LastStartColumn); } TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle &Style) Index: lib/Tooling/Core/CMakeLists.txt =================================================================== --- lib/Tooling/Core/CMakeLists.txt +++ lib/Tooling/Core/CMakeLists.txt @@ -1,9 +1,10 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangToolingCore + Diagnostic.cpp + Environment.cpp Lookup.cpp Replacement.cpp - Diagnostic.cpp LINK_LIBS clangAST Index: lib/Tooling/Core/Environment.cpp =================================================================== --- /dev/null +++ lib/Tooling/Core/Environment.cpp @@ -0,0 +1,47 @@ +//===--- Environment.cpp - Sourece tooling environment --*- C++ -*---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Core/Environment.h" + +namespace clang { +namespace tooling { + +std::unique_ptr +Environment::createVirtualEnvironment(StringRef Content, StringRef FileName) { + // This is referenced by `FileMgr` and will be released by `FileMgr` when it + // is deleted. + IntrusiveRefCntPtr InMemoryFileSystem( + new vfs::InMemoryFileSystem); + // This is passed to `SM` as reference, so the pointer has to be referenced + // in `Environment` so that `FileMgr` can out-live this function scope. + std::unique_ptr FileMgr( + new FileManager(FileSystemOptions(), InMemoryFileSystem)); + // This is passed to `SM` as reference, so the pointer has to be referenced + // by `Environment` due to the same reason above. + std::unique_ptr Diagnostics(new DiagnosticsEngine( + IntrusiveRefCntPtr(new DiagnosticIDs), + new DiagnosticOptions)); + // This will be stored as reference, so the pointer has to be stored in + // due to the same reason above. + std::unique_ptr VirtualSM( + new SourceManager(*Diagnostics, *FileMgr)); + InMemoryFileSystem->addFile( + FileName, 0, + llvm::MemoryBuffer::getMemBuffer(Content, FileName, + /*RequiresNullTerminator=*/false)); + FileID ID = VirtualSM->createFileID(FileMgr->getFile(FileName), + SourceLocation(), clang::SrcMgr::C_User); + assert(ID.isValid()); + + return llvm::make_unique( + ID, std::move(FileMgr), std::move(VirtualSM), std::move(Diagnostics)); +} + +} // namespace tooling +} // namespace clang