r181997 - Add a more convenient interface to use clang-format.
Daniel Jasper
djasper at google.com
Thu May 16 03:40:07 PDT 2013
Author: djasper
Date: Thu May 16 05:40:07 2013
New Revision: 181997
URL: http://llvm.org/viewvc/llvm-project?rev=181997&view=rev
Log:
Add a more convenient interface to use clang-format.
It turns out that several implementations go through the trouble of
setting up a SourceManager and Lexer and abstracting this into a
function makes usage easier.
Also abstracts SourceManager-independent ranges out of
tooling::Refactoring and provides a convenience function to create them
from line ranges.
Modified:
cfe/trunk/include/clang/Format/Format.h
cfe/trunk/include/clang/Tooling/Refactoring.h
cfe/trunk/lib/Format/Format.cpp
cfe/trunk/lib/Tooling/Refactoring.cpp
cfe/trunk/unittests/Format/FormatTest.cpp
Modified: cfe/trunk/include/clang/Format/Format.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Format/Format.h?rev=181997&r1=181996&r2=181997&view=diff
==============================================================================
--- cfe/trunk/include/clang/Format/Format.h (original)
+++ cfe/trunk/include/clang/Format/Format.h Thu May 16 05:40:07 2013
@@ -183,6 +183,13 @@ tooling::Replacements reformat(const For
SourceManager &SourceMgr,
std::vector<CharSourceRange> Ranges);
+/// \brief Reformats the given \p Ranges in \p Code.
+///
+/// Otherwise identical to the reformat() function consuming a \c Lexer.
+tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
+ std::vector<tooling::Range> Ranges,
+ StringRef FileName = "<stdin>");
+
/// \brief Returns the \c LangOpts that the formatter expects you to set.
LangOptions getFormattingLangOpts();
Modified: cfe/trunk/include/clang/Tooling/Refactoring.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring.h?rev=181997&r1=181996&r2=181997&view=diff
==============================================================================
--- cfe/trunk/include/clang/Tooling/Refactoring.h (original)
+++ cfe/trunk/include/clang/Tooling/Refactoring.h Thu May 16 05:40:07 2013
@@ -32,6 +32,20 @@ class SourceLocation;
namespace tooling {
+/// \brief A source range independent of the \c SourceManager.
+class Range {
+public:
+ Range() : Offset(0), Length(0) {}
+ Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {}
+
+ unsigned getOffset() const { return Offset; }
+ unsigned getLength() const { return Length; }
+
+private:
+ unsigned Offset;
+ unsigned Length;
+};
+
/// \brief A text replacement.
///
/// Represents a SourceManager independent replacement of a range of text in a
@@ -72,8 +86,8 @@ public:
/// \brief Accessors.
/// @{
StringRef getFilePath() const { return FilePath; }
- unsigned getOffset() const { return Offset; }
- unsigned getLength() const { return Length; }
+ unsigned getOffset() const { return ReplacementRange.getOffset(); }
+ unsigned getLength() const { return ReplacementRange.getLength(); }
StringRef getReplacementText() const { return ReplacementText; }
/// @}
@@ -96,8 +110,7 @@ public:
StringRef ReplacementText);
std::string FilePath;
- unsigned Offset;
- unsigned Length;
+ Range ReplacementRange;
std::string ReplacementText;
};
@@ -113,6 +126,12 @@ typedef std::set<Replacement, Replacemen
/// \returns true if all replacements apply. false otherwise.
bool applyAllReplacements(Replacements &Replaces, Rewriter &Rewrite);
+/// \brief Applies all replacements in \p Replaces to \p Code.
+///
+/// This completely ignores the path stored in each replacement. If one or more
+/// replacements cannot be applied, this returns an empty \c string.
+std::string applyAllReplacements(StringRef Code, Replacements &Replaces);
+
/// \brief A tool to run refactorings.
///
/// This is a refactoring specific version of \see ClangTool. FrontendActions
Modified: cfe/trunk/lib/Format/Format.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=181997&r1=181996&r2=181997&view=diff
==============================================================================
--- cfe/trunk/lib/Format/Format.cpp (original)
+++ cfe/trunk/lib/Format/Format.cpp Thu May 16 05:40:07 2013
@@ -19,6 +19,7 @@
#include "TokenAnnotator.h"
#include "UnwrappedLineParser.h"
#include "WhitespaceManager.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
@@ -1553,6 +1554,31 @@ tooling::Replacements reformat(const For
return formatter.format();
}
+tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
+ std::vector<tooling::Range> Ranges,
+ StringRef FileName) {
+ FileManager Files((FileSystemOptions()));
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ new DiagnosticOptions);
+ SourceManager SourceMgr(Diagnostics, Files);
+ llvm::MemoryBuffer *Buf = llvm::MemoryBuffer::getMemBuffer(Code, FileName);
+ const clang::FileEntry *Entry =
+ Files.getVirtualFile(FileName, Buf->getBufferSize(), 0);
+ SourceMgr.overrideFileContents(Entry, Buf);
+ FileID ID =
+ SourceMgr.createFileID(Entry, SourceLocation(), clang::SrcMgr::C_User);
+ Lexer Lex(ID, SourceMgr.getBuffer(ID), SourceMgr, getFormattingLangOpts());
+ SourceLocation StartOfFile = SourceMgr.getLocForStartOfFile(ID);
+ std::vector<CharSourceRange> CharRanges;
+ for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
+ SourceLocation Start = StartOfFile.getLocWithOffset(Ranges[i].getOffset());
+ SourceLocation End = Start.getLocWithOffset(Ranges[i].getLength());
+ CharRanges.push_back(CharSourceRange::getCharRange(Start, End));
+ }
+ return reformat(Style, Lex, SourceMgr, CharRanges);
+}
+
LangOptions getFormattingLangOpts() {
LangOptions LangOpts;
LangOpts.CPlusPlus = 1;
Modified: cfe/trunk/lib/Tooling/Refactoring.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring.cpp?rev=181997&r1=181996&r2=181997&view=diff
==============================================================================
--- cfe/trunk/lib/Tooling/Refactoring.cpp (original)
+++ cfe/trunk/lib/Tooling/Refactoring.cpp Thu May 16 05:40:07 2013
@@ -26,12 +26,12 @@ namespace tooling {
static const char * const InvalidLocation = "";
Replacement::Replacement()
- : FilePath(InvalidLocation), Offset(0), Length(0) {}
+ : FilePath(InvalidLocation) {}
-Replacement::Replacement(StringRef FilePath, unsigned Offset,
- unsigned Length, StringRef ReplacementText)
- : FilePath(FilePath), Offset(Offset),
- Length(Length), ReplacementText(ReplacementText) {}
+Replacement::Replacement(StringRef FilePath, unsigned Offset, unsigned Length,
+ StringRef ReplacementText)
+ : FilePath(FilePath), ReplacementRange(Offset, Length),
+ ReplacementText(ReplacementText) {}
Replacement::Replacement(SourceManager &Sources, SourceLocation Start,
unsigned Length, StringRef ReplacementText) {
@@ -62,11 +62,12 @@ bool Replacement::apply(Rewriter &Rewrit
// the remapping API is not public in the RewriteBuffer.
const SourceLocation Start =
SM.getLocForStartOfFile(ID).
- getLocWithOffset(Offset);
+ getLocWithOffset(ReplacementRange.getOffset());
// ReplaceText returns false on success.
// ReplaceText only fails if the source location is not a file location, in
// which case we already returned false earlier.
- bool RewriteSucceeded = !Rewrite.ReplaceText(Start, Length, ReplacementText);
+ bool RewriteSucceeded = !Rewrite.ReplaceText(
+ Start, ReplacementRange.getLength(), ReplacementText);
assert(RewriteSucceeded);
return RewriteSucceeded;
}
@@ -74,16 +75,18 @@ bool Replacement::apply(Rewriter &Rewrit
std::string Replacement::toString() const {
std::string result;
llvm::raw_string_ostream stream(result);
- stream << FilePath << ": " << Offset << ":+" << Length
- << ":\"" << ReplacementText << "\"";
+ stream << FilePath << ": " << ReplacementRange.getOffset() << ":+"
+ << ReplacementRange.getLength() << ":\"" << ReplacementText << "\"";
return result;
}
bool Replacement::Less::operator()(const Replacement &R1,
const Replacement &R2) const {
if (R1.FilePath != R2.FilePath) return R1.FilePath < R2.FilePath;
- if (R1.Offset != R2.Offset) return R1.Offset < R2.Offset;
- if (R1.Length != R2.Length) return R1.Length < R2.Length;
+ if (R1.ReplacementRange.getOffset() != R2.ReplacementRange.getOffset())
+ return R1.ReplacementRange.getOffset() < R2.ReplacementRange.getOffset();
+ if (R1.ReplacementRange.getLength() != R2.ReplacementRange.getLength())
+ return R1.ReplacementRange.getLength() < R2.ReplacementRange.getLength();
return R1.ReplacementText < R2.ReplacementText;
}
@@ -94,8 +97,7 @@ void Replacement::setFromSourceLocation(
Sources.getDecomposedLoc(Start);
const FileEntry *Entry = Sources.getFileEntryForID(DecomposedLocation.first);
this->FilePath = Entry != NULL ? Entry->getName() : InvalidLocation;
- this->Offset = DecomposedLocation.second;
- this->Length = Length;
+ this->ReplacementRange = Range(DecomposedLocation.second, Length);
this->ReplacementText = ReplacementText;
}
@@ -135,6 +137,35 @@ bool applyAllReplacements(Replacements &
return Result;
}
+std::string applyAllReplacements(StringRef Code, Replacements &Replaces) {
+ FileManager Files((FileSystemOptions()));
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ new DiagnosticOptions);
+ Diagnostics.setClient(new TextDiagnosticPrinter(
+ llvm::outs(), &Diagnostics.getDiagnosticOptions()));
+ SourceManager SourceMgr(Diagnostics, Files);
+ Rewriter Rewrite(SourceMgr, LangOptions());
+ llvm::MemoryBuffer *Buf = llvm::MemoryBuffer::getMemBuffer(Code, "<stdin>");
+ const clang::FileEntry *Entry =
+ Files.getVirtualFile("<stdin>", Buf->getBufferSize(), 0);
+ SourceMgr.overrideFileContents(Entry, Buf);
+ FileID ID =
+ SourceMgr.createFileID(Entry, SourceLocation(), clang::SrcMgr::C_User);
+ for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E;
+ ++I) {
+ Replacement Replace("<stdin>", I->getOffset(), I->getLength(),
+ I->getReplacementText());
+ if (!Replace.apply(Rewrite))
+ return "";
+ }
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ Rewrite.getEditBuffer(ID).write(OS);
+ OS.flush();
+ return Result;
+}
+
RefactoringTool::RefactoringTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths)
: ClangTool(Compilations, SourcePaths) {}
Modified: cfe/trunk/unittests/Format/FormatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=181997&r1=181996&r2=181997&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTest.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTest.cpp Thu May 16 05:40:07 2013
@@ -10,7 +10,6 @@
#define DEBUG_TYPE "format-test"
#include "clang/Format/Format.h"
-#include "../Tooling/RewriterTestContext.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/Debug.h"
#include "gtest/gtest.h"
@@ -23,21 +22,13 @@ protected:
std::string format(llvm::StringRef Code, unsigned Offset, unsigned Length,
const FormatStyle &Style) {
DEBUG(llvm::errs() << "---\n");
- RewriterTestContext Context;
- FileID ID = Context.createInMemoryFile("input.cc", Code);
- SourceLocation Start =
- Context.Sources.getLocForStartOfFile(ID).getLocWithOffset(Offset);
- std::vector<CharSourceRange> Ranges(
- 1,
- CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length)));
- Lexer Lex(ID, Context.Sources.getBuffer(ID), Context.Sources,
- getFormattingLangOpts());
- tooling::Replacements Replace =
- reformat(Style, Lex, Context.Sources, Ranges);
- ReplacementCount = Replace.size();
- EXPECT_TRUE(applyAllReplacements(Replace, Context.Rewrite));
- DEBUG(llvm::errs() << "\n" << Context.getRewrittenText(ID) << "\n\n");
- return Context.getRewrittenText(ID);
+ std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
+ tooling::Replacements Replaces = reformat(Style, Code, Ranges);
+ ReplacementCount = Replaces.size();
+ std::string Result = applyAllReplacements(Code, Replaces);
+ EXPECT_NE("", Result);
+ DEBUG(llvm::errs() << "\n" << Result << "\n\n");
+ return Result;
}
std::string
More information about the cfe-commits
mailing list