//===-- clang-format/ClangFormat.cpp - Clang format 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 a clang-format tool that automatically formats /// (fragments of) C++ code. /// //===----------------------------------------------------------------------===// #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" #include "clang/Lex/Lexer.h" #include "clang/Rewrite/Core/Rewriter.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Signals.h" using namespace llvm; static cl::opt Help("h", cl::desc("Alias for -help"), cl::Hidden); static cl::list Offsets( "offset", cl::desc("Format a range starting at this file offset.")); static cl::list Lengths( "length", cl::desc("Format a range of this length, -1 for end of file.")); static cl::opt Style( "style", cl::desc("Coding style, currently supports: LLVM, Google, Chromium."), cl::init("LLVM")); static cl::opt Inplace("i", cl::desc("Inplace edit , if specified.")); static cl::opt OutputXML( "output-replacements-xml", cl::desc("Output replacements as XML.")); static cl::opt FileName(cl::Positional, cl::desc("[]"), cl::init("-")); namespace clang { namespace format { static FileID createInMemoryFile(StringRef FileName, const MemoryBuffer *Source, SourceManager &Sources, FileManager &Files) { const FileEntry *Entry = Files.getVirtualFile(FileName == "-" ? "" : FileName, Source->getBufferSize(), 0); Sources.overrideFileContents(Entry, Source, true); return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User); } static FormatStyle getStyle() { FormatStyle TheStyle = getGoogleStyle(); if (Style == "LLVM") TheStyle = getLLVMStyle(); if (Style == "Chromium") TheStyle = getChromiumStyle(); return TheStyle; } static void format() { FileManager Files((FileSystemOptions())); DiagnosticsEngine Diagnostics( IntrusiveRefCntPtr(new DiagnosticIDs), new DiagnosticOptions); SourceManager Sources(Diagnostics, Files); OwningPtr Code; if (error_code ec = MemoryBuffer::getFileOrSTDIN(FileName, Code)) { llvm::errs() << ec.message() << "\n"; return; } FileID ID = createInMemoryFile(FileName, Code.get(), Sources, Files); Lexer Lex(ID, Sources.getBuffer(ID), Sources, getFormattingLangOpts()); if (Offsets.empty()) Offsets.push_back(0); if (Offsets.size() != Lengths.size() && !(Offsets.size() == 1 && Lengths.empty())) { llvm::errs() << "Number of -offset and -length arguments must match.\n"; return; } std::vector Ranges; for (cl::list::size_type i = 0, e = Offsets.size(); i != e; ++i) { SourceLocation Start = Sources.getLocForStartOfFile(ID).getLocWithOffset(Offsets[i]); SourceLocation End; if (i < Lengths.size()) { End = Start.getLocWithOffset(Lengths[i]); } else { End = Sources.getLocForEndOfFile(ID); } Ranges.push_back(CharSourceRange::getCharRange(Start, End)); } tooling::Replacements Replaces = reformat(getStyle(), Lex, Sources, Ranges); if (OutputXML) { llvm::outs() << "\n\n"; for (tooling::Replacements::const_iterator I = Replaces.begin(), E = Replaces.end(); I != E; ++I) { llvm::outs() << "" << I->getReplacementText() << "\n"; } llvm::outs() << "\n"; } else { Rewriter Rewrite(Sources, LangOptions()); tooling::applyAllReplacements(Replaces, Rewrite); if (Inplace) { if (Replaces.size() == 0) return; // Nothing changed, don't touch the file. std::string ErrorInfo; llvm::raw_fd_ostream FileStream(FileName.c_str(), ErrorInfo, llvm::raw_fd_ostream::F_Binary); if (!ErrorInfo.empty()) { llvm::errs() << "Error while writing file: " << ErrorInfo << "\n"; return; } Rewrite.getEditBuffer(ID).write(FileStream); FileStream.flush(); } else { Rewrite.getEditBuffer(ID).write(outs()); } } } } // namespace format } // namespace clang int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); cl::ParseCommandLineOptions( argc, argv, "A tool to format C/C++/Obj-C code.\n\n" "Currently supports LLVM and Google style guides.\n" "If no arguments are specified, it formats the code from standard input\n" "and writes the result to the standard output.\n" "If is given, it reformats the file. If -i is specified together\n" "with , the file is edited in-place. Otherwise, the result is\n" "written to the standard output.\n"); if (Help) cl::PrintHelpMessage(); clang::format::format(); return 0; }