Index: test/Index/overriding-method-comments.mm
===================================================================
--- test/Index/overriding-method-comments.mm (revision 170208)
+++ test/Index/overriding-method-comments.mm (working copy)
@@ -19,7 +19,7 @@
- (void)METH:(id)AAA;
@end
-// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void) METH:(id)AAAAAA0in ZZZ ]
+// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void)METH:(id)AAAAAA0in ZZZ ]
@interface Sub : Root
@end
@@ -28,13 +28,13 @@
- (void)METH:(id)BBB;
@end
-// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void) METH:(id)BBBBBB0in ZZZ ]
+// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void)METH:(id)BBBBBB0in ZZZ ]
@implementation Sub(CAT)
- (void)METH:(id)III {}
@end
-// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void) METH:(id)IIIIII0in ZZZ ]
+// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void)METH:(id)IIIIII0in ZZZ ]
@interface Redec : Root
@end
@@ -48,13 +48,13 @@
- (void)EXT_METH:(id)AAA : (double)BBB : (int)CCC;
@end
-// CHECK: FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::- (void) EXT_METH:(id)AAA :(double)BBB :(int)CCCAAA0in input value BBB1in 2nd input value is double CCC2out output value is int ]
+// CHECK: FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::- (void)EXT_METH:(id)AAA:(double)BBB:(int)CCCAAA0in input value BBB1in 2nd input value is double CCC2out output value is int ]
@implementation Redec
- (void)EXT_METH:(id)PPP : (double)QQQ : (int)RRR {}
@end
-// CHECK: FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::- (void) EXT_METH:(id)PPP :(double)QQQ :(int)RRRPPP0in input value QQQ1in 2nd input value is double RRR2out output value is int ]
+// CHECK: FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::- (void)EXT_METH:(id)PPP:(double)QQQ:(int)RRRPPP0in input value QQQ1in 2nd input value is double RRR2out output value is int ]
struct Base {
/// \brief Does something.
Index: test/Index/comment-objc-decls.m
===================================================================
--- test/Index/comment-objc-decls.m (revision 170208)
+++ test/Index/comment-objc-decls.m (working copy)
@@ -20,7 +20,7 @@
* \param[in] range output value is unsigned int
* \result return index
*/
-- (unsigned int)MethodMyProto:(id)anObject inRange:(unsigned int)range;
+- (unsigned int)MethodMyProto:(id) anObject inRange : (unsigned int)range;
/**
* \brief PropertyMyProto - This is protocol's property.
*/
@@ -30,10 +30,10 @@
*/
+ ClassMethodMyProto;
@end
-// CHECK: @protocol MyProto\n@end
-// CHECK: - (unsigned int) MethodMyProto:(id)anObject inRange:(unsigned int)range
-// CHECK: @optional\n@property ( readwrite,copy,atomic ) id PropertyMyProto
-// CHECK: + (id) ClassMethodMyProto
+// CHECK: @protocol MyProto @end
+// CHECK: - (unsigned int)MethodMyProto:(id)anObject inRange:(unsigned int)range
+// CHECK: @optional\n @property(readwrite, copy, atomic) id PropertyMyProto
+// CHECK: + (id)ClassMethodMyProto
/**
* \brief NSObject is the root class.
@@ -45,7 +45,7 @@
id IvarNSObject;
}
@end
-// CHECK: Declaration>@interface NSObject{\n id IvarNSObject;\n}\n@end
+// CHECK: Declaration>@interface NSObject {\n id IvarNSObject\n}\n@end
// CHECK: id IvarNSObject
/**
@@ -73,11 +73,11 @@
*/
@property (copy) id PropertyMyClass;
@end
-// CHECK: @interface MyClass : NSObject<MyProto> {\n id IvarMyClass;\n}\n@end
+// CHECK: @interface MyClass : NSObject<MyProto> {\n id IvarMyClass\n}\n@end
// CHECK: id IvarMyClass
-// CHECK: - (id) MethodMyClass
-// CHECK: + (id) ClassMethodMyClass
-// CHECK: @property ( readwrite,copy,atomic ) id PropertyMyClass- (id)MethodMyClass
+// CHECK: + (id)ClassMethodMyClass
+// CHECK: @property(readwrite, copy, atomic) id PropertyMyClass@interface MyClass()\n{\n id IvarMyClassExtension;\n}\n@end
+// CHECK: @interface MyClass() {\n id IvarMyClassExtension\n}\n@end
// CHECK: id IvarMyClassExtension
@@ -108,11 +108,11 @@
*/
@property (copy) id PropertyMyClassCategory;
@end
-// CHECK: @interface MyClass(Category)\n@end
-// CHECK: - (void) MethodMyClassCategory
-// CHECK: @property ( readwrite,copy,atomic ) id PropertyMyClassCategory
-// CHECK: - (id) PropertyMyClassCategory
-// CHECK: - (void) setPropertyMyClassCategory:(id)arg
+// CHECK: @interface MyClass(Category) @end
+// CHECK: - (void)MethodMyClassCategory
+// CHECK: @property(readwrite, copy, atomic) id PropertyMyClassCategory
+// CHECK: - (id)PropertyMyClassCategory
+// CHECK: - (void)setPropertyMyClassCategory:(id)arg
/// @implementation's
@@ -139,10 +139,10 @@
return 0;
}
@end
-// CHECK: @implementation MyClass{\n id IvarPrivateToMyClassImpl;\n id _PropertyMyClass;\n}\n@end
+// CHECK: @implementation MyClass {\n id IvarPrivateToMyClassImpl\n id _PropertyMyClass\n}\n@end
// CHECK: id IvarPrivateToMyClassImpl
-// CHECK: - (id) MethodMyClass
-// CHECK: + (id) ClassMethodMyClass
+// CHECK: - (id)MethodMyClass
+// CHECK: + (id)ClassMethodMyClass
/**
* \brief MyClass (Category) is implementation of private to MyClass.
@@ -162,14 +162,14 @@
*/
- (void) setPropertyMyClassCategory : (id) arg {}
@end
-// CHECK: @implementation MyClass(Category)\n@end
-// CHECK: - (void) MethodMyClassCategory
-// CHECK: - (id) PropertyMyClassCategory
-// CHECK: - (void) setPropertyMyClassCategory:(id)arg
+// CHECK: @implementation MyClass(Category) @end
+// CHECK: - (void)MethodMyClassCategory
+// CHECK: - (id)PropertyMyClassCategory
+// CHECK: - (void)setPropertyMyClassCategory:(id)arg
/**
* \brief NSObject implementation
*/
@implementation NSObject
@end
-// CHECK: @implementation NSObject@end
+// CHECK: @implementation NSObject @end
Index: include/clang/Format/RewriterFormatContext.h
===================================================================
--- include/clang/Format/RewriterFormatContext.h (revision 0)
+++ include/clang/Format/RewriterFormatContext.h (revision 0)
@@ -0,0 +1,125 @@
+//===--- RewriterFormatContext.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a utility class for Rewriter related tests.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_REWRITER_FORMAT_CONTEXT_H
+#define LLVM_CLANG_REWRITER_FORMAT_CONTEXT_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+
+/// \brief A class that sets up a ready to use Rewriter.
+///
+/// Useful in unit tests that need a Rewriter. Creates all dependencies
+/// of a Rewriter with default values for testing and provides convenience
+/// methods, which help with writing tests that change files.
+class RewriterTestContext {
+ public:
+ RewriterTestContext()
+ : DiagOpts(new DiagnosticOptions()),
+ Diagnostics(llvm::IntrusiveRefCntPtr(new DiagnosticIDs),
+ &*DiagOpts),
+ Files((FileSystemOptions())),
+ Sources(Diagnostics, Files),
+ Rewrite(Sources, Options) {
+ Diagnostics.setClient(new IgnoringDiagConsumer, true);
+ }
+
+ ~RewriterTestContext() {
+ if (!TemporaryDirectory.empty()) {
+ uint32_t RemovedCount = 0;
+ llvm::sys::fs::remove_all(TemporaryDirectory.str(), RemovedCount);
+ }
+ }
+
+ FileID createInMemoryFile(StringRef Name, StringRef Content) {
+ const llvm::MemoryBuffer *Source =
+ llvm::MemoryBuffer::getMemBuffer(Content);
+ const FileEntry *Entry =
+ Files.getVirtualFile(Name, Source->getBufferSize(), 0);
+ Sources.overrideFileContents(Entry, Source, true);
+ assert(Entry != NULL);
+ return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
+ }
+
+ FileID createOnDiskFile(StringRef Name, StringRef Content) {
+ if (TemporaryDirectory.empty()) {
+ int FD;
+ bool error =
+ llvm::sys::fs::unique_file("rewriter-test-%%-%%-%%-%%/anchor", FD,
+ TemporaryDirectory);
+ assert(!error); (void)error;
+ llvm::raw_fd_ostream Closer(FD, /*shouldClose=*/true);
+ TemporaryDirectory = llvm::sys::path::parent_path(TemporaryDirectory);
+ }
+ llvm::SmallString<1024> Path(TemporaryDirectory);
+ llvm::sys::path::append(Path, Name);
+ std::string ErrorInfo;
+ llvm::raw_fd_ostream OutStream(Path.c_str(),
+ ErrorInfo, llvm::raw_fd_ostream::F_Binary);
+ assert(ErrorInfo.empty());
+ OutStream << Content;
+ OutStream.close();
+ const FileEntry *File = Files.getFile(Path);
+ assert(File != NULL);
+ return Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
+ }
+
+ SourceLocation getLocation(FileID ID, unsigned Line, unsigned Column) {
+ SourceLocation Result = Sources.translateFileLineCol(
+ Sources.getFileEntryForID(ID), Line, Column);
+ assert(Result.isValid());
+ return Result;
+ }
+
+ std::string getRewrittenText(FileID ID) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ Rewrite.getEditBuffer(ID).write(OS);
+ OS.flush();
+ return Result;
+ }
+
+ std::string getFileContentFromDisk(StringRef Name) {
+ llvm::SmallString<1024> Path(TemporaryDirectory.str());
+ llvm::sys::path::append(Path, Name);
+ // We need to read directly from the FileManager without relaying through
+ // a FileEntry, as otherwise we'd read through an already opened file
+ // descriptor, which might not see the changes made.
+ // FIXME: Figure out whether there is a way to get the SourceManger to
+ // reopen the file.
+ return Files.getBufferForFile(Path, NULL)->getBuffer();
+ }
+
+ llvm::IntrusiveRefCntPtr DiagOpts;
+ DiagnosticsEngine Diagnostics;
+ FileManager Files;
+ SourceManager Sources;
+ LangOptions Options;
+ Rewriter Rewrite;
+
+ // Will be set once on disk files are generated.
+ SmallString<128> TemporaryDirectory;
+};
+
+} // end namespace clang
+
+#endif
Index: tools/libclang/CXTranslationUnit.h
===================================================================
--- tools/libclang/CXTranslationUnit.h (revision 170208)
+++ tools/libclang/CXTranslationUnit.h (working copy)
@@ -21,6 +21,8 @@
void *StringPool;
void *Diagnostics;
void *OverridenCursorsPool;
+ void *FormatContext;
+ unsigned FormatInMemoryUniqueId;
};
}
Index: tools/libclang/CXCursor.h
===================================================================
--- tools/libclang/CXCursor.h (revision 170208)
+++ tools/libclang/CXCursor.h (working copy)
@@ -211,10 +211,18 @@
/// \brief Create an opaque pool used for fast generation of overriden
/// CXCursor arrays.
void *createOverridenCXCursorsPool();
+
+/// \brief Create an opaque object used for declaration comment
+/// formatting.
+void *createFormatContext();
/// \brief Dispose of the overriden CXCursors pool.
void disposeOverridenCXCursorsPool(void *pool);
+/// \brief Dispose of the formatting object.
+void disposeFormatContext(void *formatContext);
+
+
/// \brief Returns a index/location pair for a selector identifier if the cursor
/// points to one.
std::pair getSelectorIdentifierIndexAndLoc(CXCursor);
Index: tools/libclang/Makefile
===================================================================
--- tools/libclang/Makefile (revision 170208)
+++ tools/libclang/Makefile (working copy)
@@ -21,7 +21,8 @@
clangFrontend.a clangDriver.a \
clangSerialization.a \
clangParse.a clangSema.a clangEdit.a clangAnalysis.a \
- clangAST.a clangLex.a clangTooling.a clangBasic.a
+ clangAST.a clangLex.a clangTooling.a clangBasic.a \
+ clangFormat.a
include $(CLANG_LEVEL)/Makefile
Index: tools/libclang/CMakeLists.txt
===================================================================
--- tools/libclang/CMakeLists.txt (revision 170208)
+++ tools/libclang/CMakeLists.txt (working copy)
@@ -54,6 +54,7 @@
clangLex
clangTooling
clangBasic
+ clangFormat
)
set(GENERATED_HEADERS
Index: tools/libclang/CXComment.cpp
===================================================================
--- tools/libclang/CXComment.cpp (revision 170208)
+++ tools/libclang/CXComment.cpp (working copy)
@@ -19,9 +19,13 @@
#include "clang/AST/CommentVisitor.h"
#include "clang/AST/Decl.h"
#include "clang/AST/PrettyPrinter.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
+#include "clang/Format/Format.h"
+#include "clang/Format/RewriterFormatContext.h"
+#include "clang/Lex/Lexer.h"
#include
using namespace clang;
@@ -856,8 +860,11 @@
CommentASTToXMLConverter(const FullComment *FC,
SmallVectorImpl &Str,
const CommandTraits &Traits,
- const SourceManager &SM) :
- FC(FC), Result(Str), Traits(Traits), SM(SM) { }
+ const SourceManager &SM,
+ RewriterTestContext &RTC,
+ unsigned FUID) :
+ FC(FC), Result(Str), Traits(Traits), SM(SM), TContext(RTC),
+ FormatInMemoryUniqueId(FUID) { }
// Inline content.
void visitTextComment(const TextComment *C);
@@ -877,7 +884,7 @@
void visitFullComment(const FullComment *C);
// Helpers.
- void appendToResultWithXMLEscaping(StringRef S);
+ void appendToResultWithXMLEscaping(StringRef S, bool SkipSemi=false);
private:
const FullComment *FC;
@@ -887,6 +894,8 @@
const CommandTraits &Traits;
const SourceManager &SM;
+ RewriterTestContext &TContext;
+ unsigned FormatInMemoryUniqueId;
};
void getSourceTextOfDeclaration(const DeclInfo *ThisDecl,
@@ -1165,7 +1174,43 @@
Result << "";
SmallString<128> Declaration;
getSourceTextOfDeclaration(DI, Declaration);
- appendToResultWithXMLEscaping(Declaration);
+
+ // FIXME. For now focus on formatting objective-C declarations.
+ if (isa(DI->CurrentDecl) ||
+ isa(DI->CurrentDecl) ||
+ isa(DI->CurrentDecl) ||
+ isa(DI->CurrentDecl) ||
+ isa(DI->CurrentDecl)) {
+ // FIXME. formatting API expects null terminated input string.
+ // There might be more efficient way of doing this.
+ std::string StringDecl = Declaration.str();
+ StringDecl += ";";
+
+ // Formatter specific code.
+ // Form a unique in memory buffer name.
+ llvm::SmallString<128> filename;
+ filename += "xmldecl";
+ filename += llvm::utostr(FormatInMemoryUniqueId);
+ filename += ".xd";
+ FileID ID = TContext.createInMemoryFile(filename, StringDecl);
+ SourceLocation Start =
+ TContext.Sources.getLocForStartOfFile(ID).getLocWithOffset(0);
+ unsigned Length = Declaration.size();
+
+ std::vector Ranges(1,
+ CharSourceRange::getCharRange(Start,
+ Start.getLocWithOffset(Length)));
+ ASTContext &Context = DI->CurrentDecl->getASTContext();
+ const LangOptions &LangOpts = Context.getLangOpts();
+ Lexer Lex(ID, TContext.Sources.getBuffer(ID), TContext.Sources, LangOpts);
+ tooling::Replacements Replace =
+ reformat(format::getLLVMStyle(), Lex, TContext.Sources, Ranges);
+ applyAllReplacements(Replace, TContext.Rewrite);
+ appendToResultWithXMLEscaping(TContext.getRewrittenText(ID), true /*SkipSemi*/);
+ }
+ else
+ appendToResultWithXMLEscaping(Declaration);
+
Result << "";
}
@@ -1288,7 +1333,8 @@
Result.flush();
}
-void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
+void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S,
+ bool SkipSemi) {
for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
const char C = *I;
switch (C) {
@@ -1307,6 +1353,9 @@
case '\'':
Result << "'";
break;
+ case ';':
+ if (SkipSemi)
+ break;
default:
Result << C;
break;
@@ -1325,7 +1374,10 @@
SourceManager &SM = static_cast(TU->TUData)->getSourceManager();
SmallString<1024> XML;
- CommentASTToXMLConverter Converter(FC, XML, getCommandTraits(CXC), SM);
+ CommentASTToXMLConverter Converter(FC, XML, getCommandTraits(CXC), SM,
+ *static_cast(
+ TU->FormatContext),
+ TU->FormatInMemoryUniqueId++);
Converter.visit(FC);
return createCXString(XML.str(), /* DupString = */ true);
}
Index: tools/libclang/CXCursor.cpp
===================================================================
--- tools/libclang/CXCursor.cpp (revision 170208)
+++ tools/libclang/CXCursor.cpp (working copy)
@@ -26,6 +26,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Frontend/ASTUnit.h"
+#include "clang/Format/RewriterFormatContext.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -1066,11 +1067,19 @@
void *cxcursor::createOverridenCXCursorsPool() {
return new OverridenCursorsPool();
}
-
+
+void *cxcursor::createFormatContext() {
+ return new RewriterTestContext();
+}
+
void cxcursor::disposeOverridenCXCursorsPool(void *pool) {
delete static_cast(pool);
}
-
+
+void cxcursor::disposeFormatContext(void *formatContext) {
+ delete static_cast(formatContext);
+}
+
extern "C" {
void clang_getOverriddenCursors(CXCursor cursor,
CXCursor **overridden,
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp (revision 170208)
+++ tools/libclang/CIndex.cpp (working copy)
@@ -61,6 +61,8 @@
D->StringPool = createCXStringPool();
D->Diagnostics = 0;
D->OverridenCursorsPool = createOverridenCXCursorsPool();
+ D->FormatContext = createFormatContext();
+ D->FormatInMemoryUniqueId = 0;
return D;
}
@@ -2773,6 +2775,8 @@
disposeCXStringPool(CTUnit->StringPool);
delete static_cast(CTUnit->Diagnostics);
disposeOverridenCXCursorsPool(CTUnit->OverridenCursorsPool);
+ disposeFormatContext(CTUnit->FormatContext);
+ CTUnit->FormatInMemoryUniqueId = 0;
delete CTUnit;
}
}
Index: unittests/Format/FormatTest.cpp
===================================================================
--- unittests/Format/FormatTest.cpp (revision 170208)
+++ unittests/Format/FormatTest.cpp (working copy)
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Format/Format.h"
-#include "../Tooling/RewriterTestContext.h"
+#include "clang/Format/RewriterFormatContext.h"
#include "clang/Lex/Lexer.h"
#include "gtest/gtest.h"
@@ -28,6 +28,8 @@
CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length)));
LangOptions LangOpts;
LangOpts.CPlusPlus = 1;
+ // FIXME. Need this to test ObjC1 features.
+ LangOpts.ObjC1 = 1;
Lexer Lex(ID, Context.Sources.getBuffer(ID), Context.Sources, LangOpts);
tooling::Replacements Replace =
reformat(Style, Lex, Context.Sources, Ranges);
@@ -63,6 +65,31 @@
// Basic function tests.
//===----------------------------------------------------------------------===//
+TEST_F(FormatTest, FormatForObjectiveCDecls) {
+ EXPECT_EQ("@protocol MyProto @end;",
+ format("@protocol MyProto@end;"));
+}
+
+TEST_F(FormatTest, FormatForObjectiveCMethods) {
+ verifyFormat("- (void)sendAction:(SEL)aSelector to:(BOOL)anObject;");
+ EXPECT_EQ("- (NSUInteger)indexOfObject:(id)anObject;",
+ format("-(NSUInteger)indexOfObject:(id)anObject;"));
+
+ EXPECT_EQ("- (NSInteger)Mthod1;",
+ format("-(NSInteger)Mthod1;"));
+ EXPECT_EQ("+ (id)Mthod2;", format("+(id)Mthod2;"));
+ EXPECT_EQ("- (NSInteger)Method3:(id)anObject;",
+ format("-(NSInteger)Method3:(id)anObject;"));
+ EXPECT_EQ("- (NSInteger)Method4:(id)anObject;",
+ format("-(NSInteger)Method4:(id)anObject;"));
+ EXPECT_EQ("- (NSInteger)Method5:(id)anObject:(id)AnotherObject;",
+ format("-(NSInteger)Method5:(id)anObject:(id)AnotherObject;"));
+ EXPECT_EQ("- (id)Method6:(id)A:(id)B:(id)C:(id)D;",
+ format("- (id)Method6:(id)A:(id)B:(id)C:(id)D;"));
+ EXPECT_EQ("- (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;",
+ format("- (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;"));
+}
+
TEST_F(FormatTest, DoesNotChangeCorrectlyFormatedCode) {
EXPECT_EQ(";", format(";"));
}
Index: unittests/Tooling/RefactoringTest.cpp
===================================================================
--- unittests/Tooling/RefactoringTest.cpp (revision 170208)
+++ unittests/Tooling/RefactoringTest.cpp (working copy)
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "RewriterTestContext.h"
+#include "clang/Format/RewriterFormatContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
Index: unittests/Tooling/RewriterTest.cpp
===================================================================
--- unittests/Tooling/RewriterTest.cpp (revision 170208)
+++ unittests/Tooling/RewriterTest.cpp (working copy)
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "RewriterTestContext.h"
+#include "clang/Format/RewriterFormatContext.h"
#include "gtest/gtest.h"
namespace clang {
Index: unittests/Tooling/RefactoringCallbacksTest.cpp
===================================================================
--- unittests/Tooling/RefactoringCallbacksTest.cpp (revision 170208)
+++ unittests/Tooling/RefactoringCallbacksTest.cpp (working copy)
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Tooling/RefactoringCallbacks.h"
-#include "RewriterTestContext.h"
+#include "clang/Format/RewriterFormatContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "gtest/gtest.h"
Index: unittests/Tooling/RewriterTestContext.h
===================================================================
--- unittests/Tooling/RewriterTestContext.h (revision 170208)
+++ unittests/Tooling/RewriterTestContext.h (working copy)
@@ -1,128 +0,0 @@
-//===--- RewriterTestContext.h ----------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a utility class for Rewriter related tests.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_REWRITER_TEST_CONTEXT_H
-#define LLVM_CLANG_REWRITER_TEST_CONTEXT_H
-
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Rewrite/Core/Rewriter.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace clang {
-
-/// \brief A class that sets up a ready to use Rewriter.
-///
-/// Useful in unit tests that need a Rewriter. Creates all dependencies
-/// of a Rewriter with default values for testing and provides convenience
-/// methods, which help with writing tests that change files.
-class RewriterTestContext {
- public:
- RewriterTestContext()
- : DiagOpts(new DiagnosticOptions()),
- Diagnostics(llvm::IntrusiveRefCntPtr(new DiagnosticIDs),
- &*DiagOpts),
- DiagnosticPrinter(llvm::outs(), &*DiagOpts),
- Files((FileSystemOptions())),
- Sources(Diagnostics, Files),
- Rewrite(Sources, Options) {
- Diagnostics.setClient(&DiagnosticPrinter, false);
- }
-
- ~RewriterTestContext() {
- if (!TemporaryDirectory.empty()) {
- uint32_t RemovedCount = 0;
- llvm::sys::fs::remove_all(TemporaryDirectory.str(), RemovedCount);
- }
- }
-
- FileID createInMemoryFile(StringRef Name, StringRef Content) {
- const llvm::MemoryBuffer *Source =
- llvm::MemoryBuffer::getMemBuffer(Content);
- const FileEntry *Entry =
- Files.getVirtualFile(Name, Source->getBufferSize(), 0);
- Sources.overrideFileContents(Entry, Source, true);
- assert(Entry != NULL);
- return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
- }
-
- FileID createOnDiskFile(StringRef Name, StringRef Content) {
- if (TemporaryDirectory.empty()) {
- int FD;
- bool error =
- llvm::sys::fs::unique_file("rewriter-test-%%-%%-%%-%%/anchor", FD,
- TemporaryDirectory);
- assert(!error); (void)error;
- llvm::raw_fd_ostream Closer(FD, /*shouldClose=*/true);
- TemporaryDirectory = llvm::sys::path::parent_path(TemporaryDirectory);
- }
- llvm::SmallString<1024> Path(TemporaryDirectory);
- llvm::sys::path::append(Path, Name);
- std::string ErrorInfo;
- llvm::raw_fd_ostream OutStream(Path.c_str(),
- ErrorInfo, llvm::raw_fd_ostream::F_Binary);
- assert(ErrorInfo.empty());
- OutStream << Content;
- OutStream.close();
- const FileEntry *File = Files.getFile(Path);
- assert(File != NULL);
- return Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
- }
-
- SourceLocation getLocation(FileID ID, unsigned Line, unsigned Column) {
- SourceLocation Result = Sources.translateFileLineCol(
- Sources.getFileEntryForID(ID), Line, Column);
- assert(Result.isValid());
- return Result;
- }
-
- std::string getRewrittenText(FileID ID) {
- std::string Result;
- llvm::raw_string_ostream OS(Result);
- Rewrite.getEditBuffer(ID).write(OS);
- OS.flush();
- return Result;
- }
-
- std::string getFileContentFromDisk(StringRef Name) {
- llvm::SmallString<1024> Path(TemporaryDirectory.str());
- llvm::sys::path::append(Path, Name);
- // We need to read directly from the FileManager without relaying through
- // a FileEntry, as otherwise we'd read through an already opened file
- // descriptor, which might not see the changes made.
- // FIXME: Figure out whether there is a way to get the SourceManger to
- // reopen the file.
- return Files.getBufferForFile(Path, NULL)->getBuffer();
- }
-
- llvm::IntrusiveRefCntPtr DiagOpts;
- DiagnosticsEngine Diagnostics;
- TextDiagnosticPrinter DiagnosticPrinter;
- FileManager Files;
- SourceManager Sources;
- LangOptions Options;
- Rewriter Rewrite;
-
- // Will be set once on disk files are generated.
- SmallString<128> TemporaryDirectory;
-};
-
-} // end namespace clang
-
-#endif
Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp (revision 170208)
+++ lib/Format/Format.cpp (working copy)
@@ -38,7 +38,8 @@
TT_PointerOrReference,
TT_ConditionalExpr,
TT_LineComment,
- TT_BlockComment
+ TT_BlockComment,
+ TT_ObjectiveCMethodDecl
};
TokenType Type;
@@ -210,7 +211,8 @@
State.LastSpace[ParenLevel] = State.Indent[ParenLevel];
if (Current.Tok.is(tok::colon) &&
- Annotations[Index].Type != TokenAnnotation::TT_ConditionalExpr) {
+ Annotations[Index].Type != TokenAnnotation::TT_ConditionalExpr &&
+ Annotations[0].Type != TokenAnnotation::TT_ObjectiveCMethodDecl) {
State.Indent[ParenLevel] += 2;
State.CtorInitializerOnNewLine = true;
State.InCtorInitializer = true;
@@ -226,7 +228,8 @@
if (Previous.Tok.is(tok::l_paren) ||
Annotations[Index - 1].Type == TokenAnnotation::TT_TemplateOpener)
State.Indent[ParenLevel] = State.Column;
- if (Current.Tok.is(tok::colon)) {
+ if (Current.Tok.is(tok::colon) &&
+ Annotations[0].Type != TokenAnnotation::TT_ObjectiveCMethodDecl) {
State.Indent[ParenLevel] = State.Column + 3;
State.InCtorInitializer = true;
}
@@ -536,16 +539,48 @@
Parser.parseLine();
determineTokenTypes();
-
+ bool IsObjCMethodDecl = Line.Tokens.size() > 0 &&
+ (Annotations[0].Type == TokenAnnotation::TT_ObjectiveCMethodDecl);
for (int i = 1, e = Line.Tokens.size(); i != e; ++i) {
TokenAnnotation &Annotation = Annotations[i];
Annotation.CanBreakBefore =
canBreakBetween(Line.Tokens[i - 1], Line.Tokens[i]);
-
- if (Line.Tokens[i].Tok.is(tok::colon)) {
+ // In ObjC method declaration, in parameter list ':'
+ // must line break on 2nd as it identifies the next parameter
+ if (IsObjCMethodDecl &&
+ Line.Tokens[i].Tok.is(tok::identifier) &&
+ (i != e-1) && Line.Tokens[i+1].Tok.is(tok::colon) &&
+ Line.Tokens[i-1].Tok.is(tok::identifier)) {
+ Annotation.CanBreakBefore = true;
+ Annotation.SpaceRequiredBefore = true;
+ }
+ else if (IsObjCMethodDecl &&
+ Line.Tokens[i].Tok.is(tok::identifier) &&
+ Line.Tokens[i-1].Tok.is(tok::l_paren) &&
+ Line.Tokens[i-2].Tok.is(tok::colon)) {
+ // Don't break this identifier as ':' or identifier
+ // before it will break.
+ Annotation.CanBreakBefore = false;
+ }
+ else if (Line.Tokens[i].Tok.is(tok::at) &&
+ Line.Tokens[i-2].Tok.is(tok::at)) {
+ // Don't put two objc's '@' on the same line. This could happen,
+ // as in, @optinal @property ...
+ Annotation.MustBreakBefore = true;
+ }
+ else if (Line.Tokens[i].Tok.is(tok::colon)) {
Annotation.SpaceRequiredBefore =
- Line.Tokens[0].Tok.isNot(tok::kw_case) && i != e - 1;
+ Line.Tokens[0].Tok.isNot(tok::kw_case) && !IsObjCMethodDecl &&
+ (i != e - 1);
+ // Don't break at ':' if identifier before it can beak.
+ if (IsObjCMethodDecl &&
+ Line.Tokens[i-1].Tok.is(tok::identifier) &&
+ Annotations[i-1].CanBreakBefore)
+ Annotation.CanBreakBefore = false;
+ } else if (Annotations[i - 1].Type ==
+ TokenAnnotation::TT_ObjectiveCMethodDecl) {
+ Annotation.SpaceRequiredBefore = true;
} else if (Annotations[i - 1].Type == TokenAnnotation::TT_UnaryOperator) {
Annotation.SpaceRequiredBefore = false;
} else if (Annotation.Type == TokenAnnotation::TT_UnaryOperator) {
@@ -570,6 +605,16 @@
} else if (Line.Tokens[i].Tok.is(tok::less) &&
Line.Tokens[0].Tok.is(tok::hash)) {
Annotation.SpaceRequiredBefore = true;
+ } else if (IsObjCMethodDecl &&
+ Line.Tokens[i - 1].Tok.is(tok::r_paren) &&
+ Line.Tokens[i].Tok.is(tok::identifier)) {
+ // Don't space between ')' and
+ Annotation.SpaceRequiredBefore = false;
+ } else if (IsObjCMethodDecl &&
+ Line.Tokens[i - 1].Tok.is(tok::colon) &&
+ Line.Tokens[i].Tok.is(tok::l_paren)) {
+ // Don't space between ':' and '('
+ Annotation.SpaceRequiredBefore = false;
} else {
Annotation.SpaceRequiredBefore =
spaceRequiredBetween(Line.Tokens[i - 1].Tok, Line.Tokens[i].Tok);
@@ -604,6 +649,9 @@
if (Tok.Tok.is(tok::star) || Tok.Tok.is(tok::amp))
Annotation.Type = determineStarAmpUsage(i, AssignmentEncountered);
+ else if ((Tok.Tok.is(tok::minus) || Tok.Tok.is(tok::plus)) &&
+ Tok.Tok.isAtStartOfLine())
+ Annotation.Type = TokenAnnotation::TT_ObjectiveCMethodDecl;
else if (isUnaryOperator(i))
Annotation.Type = TokenAnnotation::TT_UnaryOperator;
else if (isBinaryOperator(Line.Tokens[i]))
@@ -697,6 +745,8 @@
return false;
if (Left.is(tok::exclaim) || Left.is(tok::tilde))
return false;
+ if (Left.is(tok::at) && Right.is(tok::identifier))
+ return false;
if (Left.is(tok::less) || Right.is(tok::greater) || Right.is(tok::less))
return false;
if (Right.is(tok::amp) || Right.is(tok::star))