forked from OSchip/llvm-project
153 lines
5.5 KiB
C++
153 lines
5.5 KiB
C++
//===-- 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<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
|
|
|
|
static cl::list<int> Offsets(
|
|
"offset", cl::desc("Format a range starting at this file offset."));
|
|
static cl::list<int> Lengths(
|
|
"length", cl::desc("Format a range of this length, -1 for end of file."));
|
|
static cl::opt<std::string> Style(
|
|
"style",
|
|
cl::desc("Coding style, currently supports: LLVM, Google, Chromium."),
|
|
cl::init("LLVM"));
|
|
static cl::opt<bool> Inplace("i",
|
|
cl::desc("Inplace edit <file>, if specified."));
|
|
|
|
static cl::opt<bool> OutputXML(
|
|
"output-replacements-xml", cl::desc("Output replacements as XML."));
|
|
|
|
static cl::opt<std::string> FileName(cl::Positional, cl::desc("[<file>]"),
|
|
cl::init("-"));
|
|
|
|
namespace clang {
|
|
namespace format {
|
|
|
|
static FileID createInMemoryFile(StringRef FileName, const MemoryBuffer *Source,
|
|
SourceManager &Sources, FileManager &Files) {
|
|
const FileEntry *Entry = Files.getVirtualFile(FileName == "-" ? "<stdin>" :
|
|
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<DiagnosticIDs>(new DiagnosticIDs),
|
|
new DiagnosticOptions);
|
|
SourceManager Sources(Diagnostics, Files);
|
|
OwningPtr<MemoryBuffer> 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<CharSourceRange> Ranges;
|
|
for (cl::list<int>::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() << "<?xml version='1.0'?>\n<replacements xml:space='preserve'>\n";
|
|
for (tooling::Replacements::const_iterator I = Replaces.begin(),
|
|
E = Replaces.end();
|
|
I != E; ++I) {
|
|
llvm::outs() << "<replacement "
|
|
<< "offset='" << I->getOffset() << "' "
|
|
<< "length='" << I->getLength() << "'>"
|
|
<< I->getReplacementText() << "</replacement>\n";
|
|
}
|
|
llvm::outs() << "</replacements>\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 <file> is given, it reformats the file. If -i is specified together\n"
|
|
"with <file>, 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;
|
|
}
|