Index: include/clang/Format/RewriterFormatContext.h =================================================================== --- include/clang/Format/RewriterFormatContext.h (revision 0) +++ include/clang/Format/RewriterFormatContext.h (revision 0) @@ -0,0 +1,128 @@ +//===--- 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/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: tools/libclang/Makefile =================================================================== --- tools/libclang/Makefile (revision 169987) +++ 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 169987) +++ tools/libclang/CMakeLists.txt (working copy) @@ -54,6 +54,7 @@ clangLex clangTooling clangBasic + clangFormat ) set(GENERATED_HEADERS Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp (revision 169987) +++ 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" @@ -63,6 +63,12 @@ // Basic function tests. //===----------------------------------------------------------------------===// +TEST_F(FormatTest, FormatForObjectiveCMethods) { + // FIXME. This format is temporary and will change. + EXPECT_EQ("- (NSUInteger) indexOfObject : (id) anObject;", + format("-(NSUInteger)indexOfObject:(id)anObject;")); +} + TEST_F(FormatTest, DoesNotChangeCorrectlyFormatedCode) { EXPECT_EQ(";", format(";")); } Index: unittests/Tooling/RefactoringTest.cpp =================================================================== --- unittests/Tooling/RefactoringTest.cpp (revision 169987) +++ 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 169987) +++ 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 169987) +++ 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 169987) +++ 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 169987) +++ lib/Format/Format.cpp (working copy) @@ -38,7 +38,8 @@ TT_PointerOrReference, TT_ConditionalExpr, TT_LineComment, - TT_BlockComment + TT_BlockComment, + TT_ObjectiveCMethodDecl }; TokenType Type; @@ -546,6 +547,9 @@ if (Line.Tokens[i].Tok.is(tok::colon)) { Annotation.SpaceRequiredBefore = Line.Tokens[0].Tok.isNot(tok::kw_case) && i != e - 1; + } 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) { @@ -604,6 +608,9 @@ if (Tok.Tok.is(tok::star) || Tok.Tok.is(tok::amp)) Annotation.Type = determineStarAmpUsage(i, AssignmentEncountered); + else if ((i == 0) && + (Tok.Tok.is(tok::minus) || Tok.Tok.is(tok::plus))) + Annotation.Type = TokenAnnotation::TT_ObjectiveCMethodDecl; else if (isUnaryOperator(i)) Annotation.Type = TokenAnnotation::TT_UnaryOperator; else if (isBinaryOperator(Line.Tokens[i]))