summaryrefslogtreecommitdiff
path: root/unittests
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-01-02 19:18:08 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-01-02 19:18:08 +0000
commitbab175ec4b075c8076ba14c762900392533f6ee4 (patch)
tree01f4f29419a2cb10abe13c1e63cd2a66068b0137 /unittests
parent8b7a8012d223fac5d17d16a66bb39168a9a1dfc0 (diff)
Notes
Diffstat (limited to 'unittests')
-rw-r--r--unittests/AST/ASTImporterTest.cpp37
-rw-r--r--unittests/AST/ASTTypeTraitsTest.cpp2
-rw-r--r--unittests/AST/ASTVectorTest.cpp1
-rw-r--r--unittests/AST/CommentParser.cpp1
-rw-r--r--unittests/AST/DeclPrinterTest.cpp126
-rw-r--r--unittests/AST/ExternalASTSourceTest.cpp1
-rw-r--r--unittests/AST/PostOrderASTVisitor.cpp13
-rw-r--r--unittests/AST/SourceLocationTest.cpp90
-rw-r--r--unittests/AST/StmtPrinterTest.cpp2
-rw-r--r--unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp45
-rw-r--r--unittests/ASTMatchers/ASTMatchersNodeTest.cpp7
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h2
-rw-r--r--unittests/ASTMatchers/ASTMatchersTraversalTest.cpp170
-rw-r--r--unittests/ASTMatchers/Dynamic/ParserTest.cpp1
-rw-r--r--unittests/Analysis/CFGTest.cpp68
-rw-r--r--unittests/Basic/FileManagerTest.cpp20
-rw-r--r--unittests/Basic/VirtualFileSystemTest.cpp16
-rw-r--r--unittests/Driver/CMakeLists.txt1
-rw-r--r--unittests/Driver/DistroTest.cpp305
-rw-r--r--unittests/Driver/ToolChainTest.cpp25
-rw-r--r--unittests/Format/CMakeLists.txt1
-rw-r--r--unittests/Format/CleanupTest.cpp492
-rw-r--r--unittests/Format/FormatTest.cpp1075
-rw-r--r--unittests/Format/FormatTestJS.cpp207
-rw-r--r--unittests/Format/FormatTestObjC.cpp822
-rw-r--r--unittests/Format/SortImportsTestJS.cpp55
-rw-r--r--unittests/Format/SortIncludesTest.cpp105
-rw-r--r--unittests/Frontend/CodeGenActionTest.cpp5
-rw-r--r--unittests/Frontend/FrontendActionTest.cpp66
-rw-r--r--unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp17
-rw-r--r--unittests/Tooling/CMakeLists.txt1
-rw-r--r--unittests/Tooling/CompilationDatabaseTest.cpp89
-rw-r--r--unittests/Tooling/LookupTest.cpp61
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTest.cpp22
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTestCallVisitor.cpp1
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp1
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp49
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp1
-rw-r--r--unittests/Tooling/RefactoringTest.cpp855
-rw-r--r--unittests/Tooling/ReplacementTest.h56
-rw-r--r--unittests/Tooling/RewriterTest.cpp7
-rw-r--r--unittests/Tooling/TestVisitor.h29
-rw-r--r--unittests/Tooling/ToolingTest.cpp41
-rw-r--r--unittests/libclang/LibclangTest.cpp82
44 files changed, 3620 insertions, 1453 deletions
diff --git a/unittests/AST/ASTImporterTest.cpp b/unittests/AST/ASTImporterTest.cpp
index 3cc38fb55b2e..57b41f12b0ba 100644
--- a/unittests/AST/ASTImporterTest.cpp
+++ b/unittests/AST/ASTImporterTest.cpp
@@ -71,8 +71,7 @@ testImport(const std::string &FromCode, Language FromLang,
ToCtx.getSourceManager().getFileManager().getVirtualFileSystem().get());
vfs::InMemoryFileSystem *MFS = static_cast<vfs::InMemoryFileSystem *>(
OFS->overlays_begin()->get());
- MFS->addFile(InputFileName, 0,
- llvm::MemoryBuffer::getMemBuffer(FromCode.c_str()));
+ MFS->addFile(InputFileName, 0, llvm::MemoryBuffer::getMemBuffer(FromCode));
ASTImporter Importer(ToCtx, ToAST->getFileManager(),
FromCtx, FromAST->getFileManager(), false);
@@ -456,5 +455,39 @@ TEST(ImportExpr, ImportInitListExpr) {
}
+const internal::VariadicDynCastAllOfMatcher<Expr, VAArgExpr> vaArgExpr;
+
+TEST(ImportExpr, ImportVAArgExpr) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(
+ testImport(
+ "void declToImport(__builtin_va_list list, ...) {"
+ " (void)__builtin_va_arg(list, int); }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ cStyleCastExpr(
+ hasSourceExpression(
+ vaArgExpr()))))))));
+}
+
+
+TEST(ImportType, ImportAtomicType) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(testImport("void declToImport() { typedef _Atomic(int) a_int; }",
+ Lang_CXX11, "", Lang_CXX11, Verifier,
+ functionDecl(
+ hasBody(
+ compoundStmt(
+ has(
+ declStmt(
+ has(
+ typedefDecl(
+ has(atomicType()))))))))));
+}
+
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/unittests/AST/ASTTypeTraitsTest.cpp b/unittests/AST/ASTTypeTraitsTest.cpp
index 436cd7751411..722c468f30f2 100644
--- a/unittests/AST/ASTTypeTraitsTest.cpp
+++ b/unittests/AST/ASTTypeTraitsTest.cpp
@@ -163,7 +163,7 @@ TEST(DynTypedNode, StmtDump) {
TEST(DynTypedNode, DeclPrint) {
PrintVerifier Verifier;
- Verifier.expectString("void f() {\n}\n\n");
+ Verifier.expectString("void f() {\n}\n");
EXPECT_TRUE(Verifier.match("void f() {}", functionDecl()));
}
diff --git a/unittests/AST/ASTVectorTest.cpp b/unittests/AST/ASTVectorTest.cpp
index 55c06d0071fe..359d2f423259 100644
--- a/unittests/AST/ASTVectorTest.cpp
+++ b/unittests/AST/ASTVectorTest.cpp
@@ -11,7 +11,6 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/Compiler.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTVector.h"
#include "clang/Basic/Builtins.h"
diff --git a/unittests/AST/CommentParser.cpp b/unittests/AST/CommentParser.cpp
index f6ef9b9b7cea..a185f73971df 100644
--- a/unittests/AST/CommentParser.cpp
+++ b/unittests/AST/CommentParser.cpp
@@ -20,7 +20,6 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Allocator.h"
#include "gtest/gtest.h"
-#include <vector>
using namespace llvm;
using namespace clang;
diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp
index d06fbfea6f5e..e5a09a31f69f 100644
--- a/unittests/AST/DeclPrinterTest.cpp
+++ b/unittests/AST/DeclPrinterTest.cpp
@@ -45,7 +45,7 @@ public:
PrintMatch() : NumFoundDecls(0) {}
void run(const MatchFinder::MatchResult &Result) override {
- const Decl *D = Result.Nodes.getDeclAs<Decl>("id");
+ const Decl *D = Result.Nodes.getNodeAs<Decl>("id");
if (!D || D->isImplicit())
return;
NumFoundDecls++;
@@ -254,24 +254,21 @@ TEST(DeclPrinter, TestCXXRecordDecl1) {
ASSERT_TRUE(PrintedDeclCXX98Matches(
"class A { int a; };",
"A",
- "class A {\n}"));
- // Should be: with semicolon, with { ... }
+ "class A {}"));
}
TEST(DeclPrinter, TestCXXRecordDecl2) {
ASSERT_TRUE(PrintedDeclCXX98Matches(
"struct A { int a; };",
"A",
- "struct A {\n}"));
- // Should be: with semicolon, with { ... }
+ "struct A {}"));
}
TEST(DeclPrinter, TestCXXRecordDecl3) {
ASSERT_TRUE(PrintedDeclCXX98Matches(
"union A { int a; };",
"A",
- "union A {\n}"));
- // Should be: with semicolon, with { ... }
+ "union A {}"));
}
TEST(DeclPrinter, TestCXXRecordDecl4) {
@@ -279,8 +276,7 @@ TEST(DeclPrinter, TestCXXRecordDecl4) {
"class Z { int a; };"
"class A : Z { int b; };",
"A",
- "class A : Z {\n}"));
- // Should be: with semicolon, with { ... }
+ "class A : Z {}"));
}
TEST(DeclPrinter, TestCXXRecordDecl5) {
@@ -288,8 +284,7 @@ TEST(DeclPrinter, TestCXXRecordDecl5) {
"struct Z { int a; };"
"struct A : Z { int b; };",
"A",
- "struct A : Z {\n}"));
- // Should be: with semicolon, with { ... }
+ "struct A : Z {}"));
}
TEST(DeclPrinter, TestCXXRecordDecl6) {
@@ -297,8 +292,7 @@ TEST(DeclPrinter, TestCXXRecordDecl6) {
"class Z { int a; };"
"class A : public Z { int b; };",
"A",
- "class A : public Z {\n}"));
- // Should be: with semicolon, with { ... }
+ "class A : public Z {}"));
}
TEST(DeclPrinter, TestCXXRecordDecl7) {
@@ -306,8 +300,7 @@ TEST(DeclPrinter, TestCXXRecordDecl7) {
"class Z { int a; };"
"class A : protected Z { int b; };",
"A",
- "class A : protected Z {\n}"));
- // Should be: with semicolon, with { ... }
+ "class A : protected Z {}"));
}
TEST(DeclPrinter, TestCXXRecordDecl8) {
@@ -315,8 +308,7 @@ TEST(DeclPrinter, TestCXXRecordDecl8) {
"class Z { int a; };"
"class A : private Z { int b; };",
"A",
- "class A : private Z {\n}"));
- // Should be: with semicolon, with { ... }
+ "class A : private Z {}"));
}
TEST(DeclPrinter, TestCXXRecordDecl9) {
@@ -324,8 +316,7 @@ TEST(DeclPrinter, TestCXXRecordDecl9) {
"class Z { int a; };"
"class A : virtual Z { int b; };",
"A",
- "class A : virtual Z {\n}"));
- // Should be: with semicolon, with { ... }
+ "class A : virtual Z {}"));
}
TEST(DeclPrinter, TestCXXRecordDecl10) {
@@ -333,8 +324,7 @@ TEST(DeclPrinter, TestCXXRecordDecl10) {
"class Z { int a; };"
"class A : virtual public Z { int b; };",
"A",
- "class A : virtual public Z {\n}"));
- // Should be: with semicolon, with { ... }
+ "class A : virtual public Z {}"));
}
TEST(DeclPrinter, TestCXXRecordDecl11) {
@@ -343,8 +333,7 @@ TEST(DeclPrinter, TestCXXRecordDecl11) {
"class Y : virtual public Z { int b; };"
"class A : virtual public Z, private Y { int c; };",
"A",
- "class A : virtual public Z, private Y {\n}"));
- // Should be: with semicolon, with { ... }
+ "class A : virtual public Z, private Y {}"));
}
TEST(DeclPrinter, TestFunctionDecl1) {
@@ -352,7 +341,6 @@ TEST(DeclPrinter, TestFunctionDecl1) {
"void A();",
"A",
"void A()"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl2) {
@@ -360,7 +348,6 @@ TEST(DeclPrinter, TestFunctionDecl2) {
"void A() {}",
"A",
"void A()"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl3) {
@@ -369,7 +356,6 @@ TEST(DeclPrinter, TestFunctionDecl3) {
"void A() { Z(); }",
"A",
"void A()"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl4) {
@@ -377,7 +363,6 @@ TEST(DeclPrinter, TestFunctionDecl4) {
"extern void A();",
"A",
"extern void A()"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl5) {
@@ -385,7 +370,6 @@ TEST(DeclPrinter, TestFunctionDecl5) {
"static void A();",
"A",
"static void A()"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl6) {
@@ -393,7 +377,6 @@ TEST(DeclPrinter, TestFunctionDecl6) {
"inline void A();",
"A",
"inline void A()"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl7) {
@@ -401,7 +384,6 @@ TEST(DeclPrinter, TestFunctionDecl7) {
"constexpr int A(int a);",
"A",
"constexpr int A(int a)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl8) {
@@ -409,7 +391,6 @@ TEST(DeclPrinter, TestFunctionDecl8) {
"void A(int a);",
"A",
"void A(int a)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl9) {
@@ -417,7 +398,6 @@ TEST(DeclPrinter, TestFunctionDecl9) {
"void A(...);",
"A",
"void A(...)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl10) {
@@ -425,7 +405,6 @@ TEST(DeclPrinter, TestFunctionDecl10) {
"void A(int a, ...);",
"A",
"void A(int a, ...)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl11) {
@@ -435,7 +414,6 @@ TEST(DeclPrinter, TestFunctionDecl11) {
"void A(int a, pInt b, ssize_t c);",
"A",
"void A(int a, pInt b, ssize_t c)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl12) {
@@ -443,7 +421,6 @@ TEST(DeclPrinter, TestFunctionDecl12) {
"void A(int a, int b = 0);",
"A",
"void A(int a, int b = 0)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl13) {
@@ -451,7 +428,7 @@ TEST(DeclPrinter, TestFunctionDecl13) {
"void (*A(int a))(int b);",
"A",
"void (*A(int a))(int)"));
- // Should be: with semicolon, with parameter name (?)
+ // Should be: with parameter name (?)
}
TEST(DeclPrinter, TestFunctionDecl14) {
@@ -461,8 +438,7 @@ TEST(DeclPrinter, TestFunctionDecl14) {
"template<>"
"void A(int N) { }",
functionDecl(hasName("A"), isExplicitTemplateSpecialization()).bind("id"),
- "void A(int N)"));
- // WRONG; Should be: "template <> void A(int N);"));
+ "template<> void A<int>(int N)"));
}
@@ -555,7 +531,6 @@ TEST(DeclPrinter, TestCXXConstructorDecl10) {
"};",
cxxConstructorDecl(ofClass(hasName("A"))).bind("id"),
"A<T...>(const A<T...> &a)"));
- // WRONG; Should be: "A(const A<T...> &a);"
}
TEST(DeclPrinter, TestCXXConstructorDecl11) {
@@ -565,8 +540,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl11) {
" A(T&&... ts) : T(ts)... {}"
"};",
cxxConstructorDecl(ofClass(hasName("A"))).bind("id"),
- "A<T...>(T &&...ts) : T(ts)..."));
- // WRONG; Should be: "A(T &&...ts) : T(ts)... {}"
+ "A<T...>(T &&...ts) : T(ts)... {}"));
}
TEST(DeclPrinter, TestCXXDestructorDecl1) {
@@ -623,7 +597,6 @@ TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction1) {
"};",
cxxMethodDecl(ofClass(hasName("Z"))).bind("id"),
"void *operator new(std::size_t)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction2) {
@@ -634,7 +607,6 @@ TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction2) {
"};",
cxxMethodDecl(ofClass(hasName("Z"))).bind("id"),
"void *operator new[](std::size_t)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction3) {
@@ -644,7 +616,7 @@ TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction3) {
"};",
cxxMethodDecl(ofClass(hasName("Z"))).bind("id"),
"void operator delete(void *) noexcept"));
- // Should be: with semicolon, without noexcept?
+ // Should be: without noexcept?
}
TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction4) {
@@ -654,7 +626,6 @@ TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction4) {
"};",
cxxMethodDecl(ofClass(hasName("Z"))).bind("id"),
"void operator delete(void *)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction5) {
@@ -664,7 +635,7 @@ TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction5) {
"};",
cxxMethodDecl(ofClass(hasName("Z"))).bind("id"),
"void operator delete[](void *) noexcept"));
- // Should be: with semicolon, without noexcept?
+ // Should be: without noexcept?
}
TEST(DeclPrinter, TestCXXMethodDecl_Operator1) {
@@ -686,7 +657,6 @@ TEST(DeclPrinter, TestCXXMethodDecl_Operator1) {
Expected.append("void operator");
Expected.append(OperatorNames[i]);
Expected.append("(Z z)");
- // Should be: with semicolon
ASSERT_TRUE(PrintedDeclCXX98Matches(
Code,
@@ -710,7 +680,6 @@ TEST(DeclPrinter, TestCXXMethodDecl_Operator2) {
Expected.append("void operator");
Expected.append(OperatorNames[i]);
Expected.append("()");
- // Should be: with semicolon
ASSERT_TRUE(PrintedDeclCXX98Matches(
Code,
@@ -726,7 +695,6 @@ TEST(DeclPrinter, TestCXXMethodDecl1) {
"};",
"A",
"void A(int a)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestCXXMethodDecl2) {
@@ -736,7 +704,6 @@ TEST(DeclPrinter, TestCXXMethodDecl2) {
"};",
"A",
"virtual void A(int a)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestCXXMethodDecl3) {
@@ -749,7 +716,6 @@ TEST(DeclPrinter, TestCXXMethodDecl3) {
"};",
"ZZ::A",
"void A(int a)"));
- // Should be: with semicolon
// TODO: should we print "virtual"?
}
@@ -760,7 +726,6 @@ TEST(DeclPrinter, TestCXXMethodDecl4) {
"};",
"A",
"inline void A(int a)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestCXXMethodDecl5) {
@@ -770,7 +735,6 @@ TEST(DeclPrinter, TestCXXMethodDecl5) {
"};",
"A",
"virtual void A(int a) = 0"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier1) {
@@ -780,7 +744,6 @@ TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier1) {
"};",
"A",
"void A(int a) const"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier2) {
@@ -790,7 +753,6 @@ TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier2) {
"};",
"A",
"void A(int a) volatile"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier3) {
@@ -800,7 +762,6 @@ TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier3) {
"};",
"A",
"void A(int a) const volatile"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestCXXMethodDecl_RefQualifier1) {
@@ -810,7 +771,6 @@ TEST(DeclPrinter, TestCXXMethodDecl_RefQualifier1) {
"};",
"A",
"void A(int a) &"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestCXXMethodDecl_RefQualifier2) {
@@ -820,7 +780,6 @@ TEST(DeclPrinter, TestCXXMethodDecl_RefQualifier2) {
"};",
"A",
"void A(int a) &&"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification1) {
@@ -830,7 +789,6 @@ TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification1) {
"};",
"A",
"void A(int a) throw()"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification2) {
@@ -840,7 +798,6 @@ TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification2) {
"};",
"A",
"void A(int a) throw(int)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification3) {
@@ -851,7 +808,6 @@ TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification3) {
"};",
"A",
"void A(int a) throw(ZZ, int)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification4) {
@@ -861,7 +817,6 @@ TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification4) {
"};",
"A",
"void A(int a) noexcept"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification5) {
@@ -942,8 +897,7 @@ TEST(DeclPrinter, TestClassTemplateDecl1) {
"template<typename T>"
"struct A { T a; };",
classTemplateDecl(hasName("A")).bind("id"),
- "template <typename T> struct A {\n}"));
- // Should be: with semicolon, with { ... }
+ "template <typename T> struct A {}"));
}
TEST(DeclPrinter, TestClassTemplateDecl2) {
@@ -951,8 +905,7 @@ TEST(DeclPrinter, TestClassTemplateDecl2) {
"template<typename T = int>"
"struct A { T a; };",
classTemplateDecl(hasName("A")).bind("id"),
- "template <typename T = int> struct A {\n}"));
- // Should be: with semicolon, with { ... }
+ "template <typename T = int> struct A {}"));
}
TEST(DeclPrinter, TestClassTemplateDecl3) {
@@ -960,8 +913,7 @@ TEST(DeclPrinter, TestClassTemplateDecl3) {
"template<class T>"
"struct A { T a; };",
classTemplateDecl(hasName("A")).bind("id"),
- "template <class T> struct A {\n}"));
- // Should be: with semicolon, with { ... }
+ "template <class T> struct A {}"));
}
TEST(DeclPrinter, TestClassTemplateDecl4) {
@@ -969,8 +921,7 @@ TEST(DeclPrinter, TestClassTemplateDecl4) {
"template<typename T, typename U>"
"struct A { T a; U b; };",
classTemplateDecl(hasName("A")).bind("id"),
- "template <typename T, typename U> struct A {\n}"));
- // Should be: with semicolon, with { ... }
+ "template <typename T, typename U> struct A {}"));
}
TEST(DeclPrinter, TestClassTemplateDecl5) {
@@ -978,8 +929,7 @@ TEST(DeclPrinter, TestClassTemplateDecl5) {
"template<int N>"
"struct A { int a[N]; };",
classTemplateDecl(hasName("A")).bind("id"),
- "template <int N> struct A {\n}"));
- // Should be: with semicolon, with { ... }
+ "template <int N> struct A {}"));
}
TEST(DeclPrinter, TestClassTemplateDecl6) {
@@ -987,8 +937,7 @@ TEST(DeclPrinter, TestClassTemplateDecl6) {
"template<int N = 42>"
"struct A { int a[N]; };",
classTemplateDecl(hasName("A")).bind("id"),
- "template <int N = 42> struct A {\n}"));
- // Should be: with semicolon, with { ... }
+ "template <int N = 42> struct A {}"));
}
TEST(DeclPrinter, TestClassTemplateDecl7) {
@@ -997,16 +946,14 @@ TEST(DeclPrinter, TestClassTemplateDecl7) {
"template<MyInt N>"
"struct A { int a[N]; };",
classTemplateDecl(hasName("A")).bind("id"),
- "template <MyInt N> struct A {\n}"));
- // Should be: with semicolon, with { ... }
+ "template <MyInt N> struct A {}"));
}
TEST(DeclPrinter, TestClassTemplateDecl8) {
ASSERT_TRUE(PrintedDeclCXX98Matches(
"template<template<typename U> class T> struct A { };",
classTemplateDecl(hasName("A")).bind("id"),
- "template <template <typename U> class T> struct A {\n}"));
- // Should be: with semicolon, with { ... }
+ "template <template <typename U> class T> struct A {}"));
}
TEST(DeclPrinter, TestClassTemplateDecl9) {
@@ -1014,8 +961,7 @@ TEST(DeclPrinter, TestClassTemplateDecl9) {
"template<typename T> struct Z { };"
"template<template<typename U> class T = Z> struct A { };",
classTemplateDecl(hasName("A")).bind("id"),
- "template <template <typename U> class T> struct A {\n}"));
- // Should be: with semicolon, with { ... }
+ "template <template <typename U> class T> struct A {}"));
}
TEST(DeclPrinter, TestClassTemplateDecl10) {
@@ -1023,8 +969,7 @@ TEST(DeclPrinter, TestClassTemplateDecl10) {
"template<typename... T>"
"struct A { int a; };",
classTemplateDecl(hasName("A")).bind("id"),
- "template <typename ...T> struct A {\n}"));
- // Should be: with semicolon, with { ... }
+ "template <typename ...T> struct A {}"));
}
TEST(DeclPrinter, TestClassTemplateDecl11) {
@@ -1032,8 +977,7 @@ TEST(DeclPrinter, TestClassTemplateDecl11) {
"template<typename... T>"
"struct A : public T... { int a; };",
classTemplateDecl(hasName("A")).bind("id"),
- "template <typename ...T> struct A : public T... {\n}"));
- // Should be: with semicolon, with { ... }
+ "template <typename ...T> struct A : public T... {}"));
}
TEST(DeclPrinter, TestClassTemplatePartialSpecializationDecl1) {
@@ -1043,8 +987,7 @@ TEST(DeclPrinter, TestClassTemplatePartialSpecializationDecl1) {
"template<typename T>"
"struct A<T, int> { T a; };",
classTemplateSpecializationDecl().bind("id"),
- "struct A {\n}"));
- // WRONG; Should be: "template<typename T> struct A<T, int> { ... }"
+ "template <typename T> struct A<T, int> {}"));
}
TEST(DeclPrinter, TestClassTemplatePartialSpecializationDecl2) {
@@ -1054,7 +997,7 @@ TEST(DeclPrinter, TestClassTemplatePartialSpecializationDecl2) {
"template<typename T>"
"struct A<T *> { T a; };",
classTemplateSpecializationDecl().bind("id"),
- "struct A {\n}"));
+ "template <typename T> struct A<type-parameter-0-0 *> {}"));
// WRONG; Should be: "template<typename T> struct A<T *> { ... }"
}
@@ -1065,8 +1008,7 @@ TEST(DeclPrinter, TestClassTemplateSpecializationDecl1) {
"template<>"
"struct A<int> { int a; };",
classTemplateSpecializationDecl().bind("id"),
- "struct A {\n}"));
- // WRONG; Should be: "template<> struct A<int> { ... }"
+ "template<> struct A<int> {}"));
}
TEST(DeclPrinter, TestFunctionTemplateDecl1) {
@@ -1075,7 +1017,6 @@ TEST(DeclPrinter, TestFunctionTemplateDecl1) {
"void A(T &t);",
functionTemplateDecl(hasName("A")).bind("id"),
"template <typename T> void A(T &t)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionTemplateDecl2) {
@@ -1084,7 +1025,6 @@ TEST(DeclPrinter, TestFunctionTemplateDecl2) {
"void A(T &t) { }",
functionTemplateDecl(hasName("A")).bind("id"),
"template <typename T> void A(T &t)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionTemplateDecl3) {
@@ -1093,7 +1033,6 @@ TEST(DeclPrinter, TestFunctionTemplateDecl3) {
"void A(T... a);",
functionTemplateDecl(hasName("A")).bind("id"),
"template <typename ...T> void A(T ...a)"));
- // Should be: with semicolon.
}
TEST(DeclPrinter, TestFunctionTemplateDecl4) {
@@ -1101,7 +1040,6 @@ TEST(DeclPrinter, TestFunctionTemplateDecl4) {
"struct Z { template<typename T> void A(T t); };",
functionTemplateDecl(hasName("A")).bind("id"),
"template <typename T> void A(T t)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionTemplateDecl5) {
@@ -1109,7 +1047,6 @@ TEST(DeclPrinter, TestFunctionTemplateDecl5) {
"struct Z { template<typename T> void A(T t) {} };",
functionTemplateDecl(hasName("A")).bind("id"),
"template <typename T> void A(T t)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionTemplateDecl6) {
@@ -1119,7 +1056,6 @@ TEST(DeclPrinter, TestFunctionTemplateDecl6) {
"};",
functionTemplateDecl(hasName("A")).bind("id"),
"template <typename U> void A(U t)"));
- // Should be: with semicolon
}
TEST(DeclPrinter, TestTemplateArgumentList1) {
diff --git a/unittests/AST/ExternalASTSourceTest.cpp b/unittests/AST/ExternalASTSourceTest.cpp
index 4f42dcf10336..4b3bb3e2b69b 100644
--- a/unittests/AST/ExternalASTSourceTest.cpp
+++ b/unittests/AST/ExternalASTSourceTest.cpp
@@ -17,6 +17,7 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "gtest/gtest.h"
using namespace clang;
diff --git a/unittests/AST/PostOrderASTVisitor.cpp b/unittests/AST/PostOrderASTVisitor.cpp
index 012f63a48ade..2921f3ead50e 100644
--- a/unittests/AST/PostOrderASTVisitor.cpp
+++ b/unittests/AST/PostOrderASTVisitor.cpp
@@ -34,6 +34,11 @@ namespace {
bool shouldTraversePostOrder() const { return VisitPostOrder; }
+ bool VisitUnaryOperator(UnaryOperator *Op) {
+ VisitedNodes.push_back(Op->getOpcodeStr(Op->getOpcode()));
+ return true;
+ }
+
bool VisitBinaryOperator(BinaryOperator *Op) {
VisitedNodes.push_back(Op->getOpcodeStr());
return true;
@@ -76,7 +81,7 @@ TEST(RecursiveASTVisitor, PostOrderTraversal) {
auto ASTUnit = tooling::buildASTFromCode(
"class A {"
" class B {"
- " int foo() { while(4) { int i = 9; } return (1 + 3) + 2; }"
+ " int foo() { while(4) { int i = 9; int j = -5; } return (1 + 3) + 2; }"
" };"
"};"
);
@@ -86,9 +91,9 @@ TEST(RecursiveASTVisitor, PostOrderTraversal) {
RecordingVisitor Visitor(true);
Visitor.TraverseTranslationUnitDecl(TU);
- std::vector<std::string> expected = {
- "4", "9", "i", "1", "3", "+", "2", "+", "return", "A::B::foo", "A::B", "A"
- };
+ std::vector<std::string> expected = {"4", "9", "i", "5", "-",
+ "j", "1", "3", "+", "2",
+ "+", "return", "A::B::foo", "A::B", "A"};
// Compare the list of actually visited nodes
// with the expected list of visited nodes.
ASSERT_EQ(expected.size(), Visitor.VisitedNodes.size());
diff --git a/unittests/AST/SourceLocationTest.cpp b/unittests/AST/SourceLocationTest.cpp
index 9fae8d862aef..add85c366024 100644
--- a/unittests/AST/SourceLocationTest.cpp
+++ b/unittests/AST/SourceLocationTest.cpp
@@ -148,6 +148,96 @@ TEST(VarDecl, VMTypeFixedVarDeclRange) {
varDecl(), Lang_C89));
}
+TEST(TypeLoc, IntRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 1, 1, 1);
+ EXPECT_TRUE(Verifier.match("int a;", typeLoc()));
+}
+
+TEST(TypeLoc, LongRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 1, 1, 1);
+ EXPECT_TRUE(Verifier.match("long a;", typeLoc()));
+}
+
+TEST(TypeLoc, LongDoubleRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 1, 1, 6);
+ EXPECT_TRUE(Verifier.match("long double a;", typeLoc()));
+}
+
+TEST(TypeLoc, DoubleLongRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 1, 1, 8);
+ EXPECT_TRUE(Verifier.match("double long a;", typeLoc()));
+}
+
+TEST(TypeLoc, LongIntRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 1, 1, 6);
+ EXPECT_TRUE(Verifier.match("long int a;", typeLoc()));
+}
+
+TEST(TypeLoc, IntLongRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 1, 1, 5);
+ EXPECT_TRUE(Verifier.match("int long a;", typeLoc()));
+}
+
+TEST(TypeLoc, UnsignedIntRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 1, 1, 10);
+ EXPECT_TRUE(Verifier.match("unsigned int a;", typeLoc()));
+}
+
+TEST(TypeLoc, IntUnsignedRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 1, 1, 5);
+ EXPECT_TRUE(Verifier.match("int unsigned a;", typeLoc()));
+}
+
+TEST(TypeLoc, LongLongRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 1, 1, 6);
+ EXPECT_TRUE(Verifier.match("long long a;", typeLoc()));
+}
+
+TEST(TypeLoc, UnsignedLongLongRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 1, 1, 15);
+ EXPECT_TRUE(Verifier.match("unsigned long long a;", typeLoc()));
+}
+
+TEST(TypeLoc, LongUnsignedLongRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 1, 1, 15);
+ EXPECT_TRUE(Verifier.match("long unsigned long a;", typeLoc()));
+}
+
+TEST(TypeLoc, LongLongUnsignedRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 1, 1, 11);
+ EXPECT_TRUE(Verifier.match("long long unsigned a;", typeLoc()));
+}
+
+TEST(TypeLoc, ConstLongLongRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 7, 1, 12);
+ EXPECT_TRUE(Verifier.match("const long long a = 0;", typeLoc()));
+}
+
+TEST(TypeLoc, LongConstLongRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 1, 1, 12);
+ EXPECT_TRUE(Verifier.match("long const long a = 0;", typeLoc()));
+}
+
+TEST(TypeLoc, LongLongConstRange) {
+ RangeVerifier<TypeLoc> Verifier;
+ Verifier.expectRange(1, 1, 1, 6);
+ EXPECT_TRUE(Verifier.match("long long const a = 0;", typeLoc()));
+}
+
TEST(CXXConstructorDecl, NoRetFunTypeLocRange) {
RangeVerifier<CXXConstructorDecl> Verifier;
Verifier.expectRange(1, 11, 1, 13);
diff --git a/unittests/AST/StmtPrinterTest.cpp b/unittests/AST/StmtPrinterTest.cpp
index bc7fd54e4ad9..12b203236c99 100644
--- a/unittests/AST/StmtPrinterTest.cpp
+++ b/unittests/AST/StmtPrinterTest.cpp
@@ -45,7 +45,7 @@ public:
PrintMatch() : NumFoundStmts(0) {}
void run(const MatchFinder::MatchResult &Result) override {
- const Stmt *S = Result.Nodes.getStmtAs<Stmt>("id");
+ const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id");
if (!S)
return;
NumFoundStmts++;
diff --git a/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 82c5139a78f5..6037127feb52 100644
--- a/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -669,7 +669,7 @@ TEST(Matcher, VarDecl_Storage) {
TEST(Matcher, VarDecl_StorageDuration) {
std::string T =
- "void f() { int x; static int y; } int a;";
+ "void f() { int x; static int y; } int a;static int b;extern int c;";
EXPECT_TRUE(matches(T, varDecl(hasName("x"), hasAutomaticStorageDuration())));
EXPECT_TRUE(
@@ -679,6 +679,8 @@ TEST(Matcher, VarDecl_StorageDuration) {
EXPECT_TRUE(matches(T, varDecl(hasName("y"), hasStaticStorageDuration())));
EXPECT_TRUE(matches(T, varDecl(hasName("a"), hasStaticStorageDuration())));
+ EXPECT_TRUE(matches(T, varDecl(hasName("b"), hasStaticStorageDuration())));
+ EXPECT_TRUE(matches(T, varDecl(hasName("c"), hasStaticStorageDuration())));
EXPECT_TRUE(notMatches(T, varDecl(hasName("x"), hasStaticStorageDuration())));
// FIXME: It is really hard to test with thread_local itself because not all
@@ -842,6 +844,21 @@ TEST(IsExternC, MatchesExternCFunctionDeclarations) {
EXPECT_TRUE(notMatches("void f() {}", functionDecl(isExternC())));
}
+TEST(IsExternC, MatchesExternCVariableDeclarations) {
+ EXPECT_TRUE(matches("extern \"C\" int i;", varDecl(isExternC())));
+ EXPECT_TRUE(matches("extern \"C\" { int i; }", varDecl(isExternC())));
+ EXPECT_TRUE(notMatches("int i;", varDecl(isExternC())));
+}
+
+TEST(IsStaticStorageClass, MatchesStaticDeclarations) {
+ EXPECT_TRUE(
+ matches("static void f() {}", functionDecl(isStaticStorageClass())));
+ EXPECT_TRUE(matches("static int i = 1;", varDecl(isStaticStorageClass())));
+ EXPECT_TRUE(notMatches("int i = 1;", varDecl(isStaticStorageClass())));
+ EXPECT_TRUE(notMatches("extern int i;", varDecl(isStaticStorageClass())));
+ EXPECT_TRUE(notMatches("void f() {}", functionDecl(isStaticStorageClass())));
+}
+
TEST(IsDefaulted, MatchesDefaultedFunctionDeclarations) {
EXPECT_TRUE(notMatches("class A { ~A(); };",
functionDecl(hasName("~A"), isDefaulted())));
@@ -1387,6 +1404,16 @@ TEST(Member, BitFields) {
fieldDecl(isBitField(), hasBitWidth(2), hasName("a"))));
}
+TEST(Member, InClassInitializer) {
+ EXPECT_TRUE(
+ matches("class C { int a = 2; int b; };",
+ fieldDecl(hasInClassInitializer(integerLiteral(equals(2))),
+ hasName("a"))));
+ EXPECT_TRUE(
+ notMatches("class C { int a = 2; int b; };",
+ fieldDecl(hasInClassInitializer(anything()), hasName("b"))));
+}
+
TEST(Member, UnderstandsAccess) {
EXPECT_TRUE(matches(
"struct A { int i; };", fieldDecl(isPublic(), hasName("i"))));
@@ -1931,5 +1958,21 @@ TEST(NullPointerConstants, Basic) {
EXPECT_TRUE(notMatches("int i = 0;", expr(nullPointerConstant())));
}
+TEST(HasExternalFormalLinkage, Basic) {
+ EXPECT_TRUE(matches("int a = 0;", namedDecl(hasExternalFormalLinkage())));
+ EXPECT_TRUE(
+ notMatches("static int a = 0;", namedDecl(hasExternalFormalLinkage())));
+ EXPECT_TRUE(notMatches("static void f(void) { int a = 0; }",
+ namedDecl(hasExternalFormalLinkage())));
+ EXPECT_TRUE(matches("void f(void) { int a = 0; }",
+ namedDecl(hasExternalFormalLinkage())));
+
+ // Despite having internal semantic linkage, the anonymous namespace member
+ // has external linkage because the member has a unique name in all
+ // translation units.
+ EXPECT_TRUE(matches("namespace { int a = 0; }",
+ namedDecl(hasExternalFormalLinkage())));
+}
+
} // namespace ast_matchers
} // namespace clang
diff --git a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index 6c8a5e000f49..dd45ca3ced92 100644
--- a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -528,6 +528,11 @@ TEST(Matcher, ConstructorCall) {
EXPECT_TRUE(matches("class X {}; void x(int) { X x; }", Constructor));
}
+TEST(Match, ConstructorInitializers) {
+ EXPECT_TRUE(matches("class C { int i; public: C(int ii) : i(ii) {} };",
+ cxxCtorInitializer(forField(hasName("i")))));
+}
+
TEST(Matcher, ThisExpr) {
EXPECT_TRUE(
matches("struct X { int a; int f () { return a; } };", cxxThisExpr()));
@@ -589,7 +594,7 @@ TEST(MaterializeTemporaryExpr, MatchesTemporary) {
materializeTemporaryExpr()));
EXPECT_TRUE(
- notMatches(ClassString +
+ matches(ClassString +
"string GetStringByValue();"
"void run() { int k = GetStringByValue().length(); }",
materializeTemporaryExpr()));
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index 4b3387c0ba72..fdb273c672da 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -189,7 +189,7 @@ testing::AssertionResult matchesConditionallyWithCuda(
// avoid constructing a full system triple.
std::vector<std::string> Args = {
"-xcuda", "-fno-ms-extensions", "--cuda-host-only", "-nocudainc",
- "-target", "nvptx64-unknown-unknown", CompileArg};
+ "-target", "x86_64-unknown-unknown", CompileArg};
if (!runToolOnCodeWithArgs(Factory->create(),
CudaHeader + Code, Args)) {
return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
diff --git a/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index 4149d4fd0b11..67a4a3b2fc09 100644
--- a/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -241,6 +241,36 @@ TEST(HasDeclaration, HasDeclarationOfTemplateSpecializationType) {
hasDeclaration(namedDecl(hasName("A"))))))));
}
+TEST(HasDeclaration, HasDeclarationOfCXXNewExpr) {
+ EXPECT_TRUE(
+ matches("int *A = new int();",
+ cxxNewExpr(hasDeclaration(functionDecl(parameterCountIs(1))))));
+}
+
+TEST(HasUnqualifiedDesugaredType, DesugarsUsing) {
+ EXPECT_TRUE(
+ matches("struct A {}; using B = A; B b;",
+ varDecl(hasType(hasUnqualifiedDesugaredType(recordType())))));
+ EXPECT_TRUE(
+ matches("struct A {}; using B = A; using C = B; C b;",
+ varDecl(hasType(hasUnqualifiedDesugaredType(recordType())))));
+}
+
+TEST(HasUnderlyingDecl, Matches) {
+ EXPECT_TRUE(matches("namespace N { template <class T> void f(T t); }"
+ "template <class T> void g() { using N::f; f(T()); }",
+ unresolvedLookupExpr(hasAnyDeclaration(
+ namedDecl(hasUnderlyingDecl(hasName("::N::f")))))));
+ EXPECT_TRUE(matches(
+ "namespace N { template <class T> void f(T t); }"
+ "template <class T> void g() { N::f(T()); }",
+ unresolvedLookupExpr(hasAnyDeclaration(namedDecl(hasName("::N::f"))))));
+ EXPECT_TRUE(notMatches(
+ "namespace N { template <class T> void f(T t); }"
+ "template <class T> void g() { using N::f; f(T()); }",
+ unresolvedLookupExpr(hasAnyDeclaration(namedDecl(hasName("::N::f"))))));
+}
+
TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X")));
EXPECT_TRUE(
@@ -543,6 +573,14 @@ TEST(Matcher, MatchesTypeTemplateArgument) {
asString("int"))))));
}
+TEST(Matcher, MatchesTemplateTemplateArgument) {
+ EXPECT_TRUE(matches("template<template <typename> class S> class X {};"
+ "template<typename T> class Y {};"
+ "X<Y> xi;",
+ classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToTemplate(templateName())))));
+}
+
TEST(Matcher, MatchesDeclarationReferenceTemplateArgument) {
EXPECT_TRUE(matches(
"struct B { int next; };"
@@ -594,6 +632,14 @@ TEST(Matcher, MatchesSpecificArgument) {
"A<int, bool> a;",
templateSpecializationType(hasTemplateArgument(
1, refersToType(asString("int"))))));
+
+ EXPECT_TRUE(matches(
+ "template<typename T> void f() {};"
+ "void func() { f<int>(); }",
+ functionDecl(hasTemplateArgument(0, refersToType(asString("int"))))));
+ EXPECT_TRUE(notMatches(
+ "template<typename T> void f() {};",
+ functionDecl(hasTemplateArgument(0, refersToType(asString("int"))))));
}
TEST(TemplateArgument, Matches) {
@@ -603,6 +649,94 @@ TEST(TemplateArgument, Matches) {
EXPECT_TRUE(matches(
"template<typename T> struct C {}; C<int> c;",
templateSpecializationType(hasAnyTemplateArgument(templateArgument()))));
+
+ EXPECT_TRUE(matches(
+ "template<typename T> void f() {};"
+ "void func() { f<int>(); }",
+ functionDecl(hasAnyTemplateArgument(templateArgument()))));
+}
+
+TEST(TemplateTypeParmDecl, CXXMethodDecl) {
+ const char input[] =
+ "template<typename T>\n"
+ "class Class {\n"
+ " void method();\n"
+ "};\n"
+ "template<typename U>\n"
+ "void Class<U>::method() {}\n";
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T"))));
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U"))));
+}
+
+TEST(TemplateTypeParmDecl, VarDecl) {
+ const char input[] =
+ "template<typename T>\n"
+ "class Class {\n"
+ " static T pi;\n"
+ "};\n"
+ "template<typename U>\n"
+ "U Class<U>::pi = U(3.1415926535897932385);\n";
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T"))));
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U"))));
+}
+
+TEST(TemplateTypeParmDecl, VarTemplatePartialSpecializationDecl) {
+ const char input[] =
+ "template<typename T>\n"
+ "struct Struct {\n"
+ " template<typename T2> static int field;\n"
+ "};\n"
+ "template<typename U>\n"
+ "template<typename U2>\n"
+ "int Struct<U>::field<U2*> = 123;\n";
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T"))));
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T2"))));
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U"))));
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U2"))));
+}
+
+TEST(TemplateTypeParmDecl, ClassTemplatePartialSpecializationDecl) {
+ const char input[] =
+ "template<typename T>\n"
+ "class Class {\n"
+ " template<typename T2> struct Struct;\n"
+ "};\n"
+ "template<typename U>\n"
+ "template<typename U2>\n"
+ "struct Class<U>::Struct<U2*> {};\n";
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T"))));
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T2"))));
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U"))));
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U2"))));
+}
+
+TEST(TemplateTypeParmDecl, EnumDecl) {
+ const char input[] =
+ "template<typename T>\n"
+ "struct Struct {\n"
+ " enum class Enum : T;\n"
+ "};\n"
+ "template<typename U>\n"
+ "enum class Struct<U>::Enum : U {\n"
+ " e1,\n"
+ " e2\n"
+ "};\n";
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T"))));
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U"))));
+}
+
+TEST(TemplateTypeParmDecl, RecordDecl) {
+ const char input[] =
+ "template<typename T>\n"
+ "class Class {\n"
+ " struct Struct;\n"
+ "};\n"
+ "template<typename U>\n"
+ "struct Class<U>::Struct {\n"
+ " U field;\n"
+ "};\n";
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T"))));
+ EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U"))));
}
TEST(RefersToIntegralType, Matches) {
@@ -2051,5 +2185,41 @@ TEST(Matcher, ForEachOverriden) {
EXPECT_TRUE(notMatches(Code2, ForEachOverriddenInClass("A1")));
}
+TEST(Matcher, HasAnyDeclaration) {
+ std::string Fragment = "void foo(int p1);"
+ "void foo(int *p2);"
+ "void bar(int p3);"
+ "template <typename T> void baz(T t) { foo(t); }";
+
+ EXPECT_TRUE(
+ matches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl(
+ hasParameter(0, parmVarDecl(hasName("p1"))))))));
+ EXPECT_TRUE(
+ matches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl(
+ hasParameter(0, parmVarDecl(hasName("p2"))))))));
+ EXPECT_TRUE(
+ notMatches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl(
+ hasParameter(0, parmVarDecl(hasName("p3"))))))));
+ EXPECT_TRUE(notMatches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(
+ functionDecl(hasName("bar"))))));
+}
+
+TEST(SubstTemplateTypeParmType, HasReplacementType)
+{
+ std::string Fragment = "template<typename T>"
+ "double F(T t);"
+ "int i;"
+ "double j = F(i);";
+ EXPECT_TRUE(matches(Fragment, substTemplateTypeParmType(hasReplacementType(
+ qualType(asString("int"))))));
+ EXPECT_TRUE(notMatches(Fragment, substTemplateTypeParmType(hasReplacementType(
+ qualType(asString("double"))))));
+ EXPECT_TRUE(
+ notMatches("template<int N>"
+ "double F();"
+ "double j = F<5>();",
+ substTemplateTypeParmType(hasReplacementType(qualType()))));
+}
+
} // namespace ast_matchers
} // namespace clang
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index 553427c9a403..d241f5ba2f86 100644
--- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -11,7 +11,6 @@
#include "clang/ASTMatchers/Dynamic/Parser.h"
#include "clang/ASTMatchers/Dynamic/Registry.h"
#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringMap.h"
#include "gtest/gtest.h"
#include <string>
#include <vector>
diff --git a/unittests/Analysis/CFGTest.cpp b/unittests/Analysis/CFGTest.cpp
index a8d397e9a534..e691110050a2 100644
--- a/unittests/Analysis/CFGTest.cpp
+++ b/unittests/Analysis/CFGTest.cpp
@@ -18,6 +18,41 @@ namespace clang {
namespace analysis {
namespace {
+enum BuildResult {
+ ToolFailed,
+ ToolRan,
+ SawFunctionBody,
+ BuiltCFG,
+};
+
+class CFGCallback : public ast_matchers::MatchFinder::MatchCallback {
+public:
+ BuildResult TheBuildResult = ToolRan;
+
+ void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
+ const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
+ Stmt *Body = Func->getBody();
+ if (!Body)
+ return;
+ TheBuildResult = SawFunctionBody;
+ if (CFG::buildCFG(nullptr, Body, Result.Context, CFG::BuildOptions()))
+ TheBuildResult = BuiltCFG;
+ }
+};
+
+BuildResult BuildCFG(const char *Code) {
+ CFGCallback Callback;
+
+ ast_matchers::MatchFinder Finder;
+ Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback);
+ std::unique_ptr<tooling::FrontendActionFactory> Factory(
+ tooling::newFrontendActionFactory(&Finder));
+ std::vector<std::string> Args = {"-std=c++11", "-fno-delayed-template-parsing"};
+ if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args))
+ return ToolFailed;
+ return Callback.TheBuildResult;
+}
+
// Constructing a CFG for a range-based for over a dependent type fails (but
// should not crash).
TEST(CFG, RangeBasedForOverDependentType) {
@@ -27,30 +62,17 @@ TEST(CFG, RangeBasedForOverDependentType) {
" for (const Foo *TheFoo : Range) {\n"
" }\n"
"}\n";
+ EXPECT_EQ(SawFunctionBody, BuildCFG(Code));
+}
- class CFGCallback : public ast_matchers::MatchFinder::MatchCallback {
- public:
- bool SawFunctionBody = false;
-
- void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
- const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
- Stmt *Body = Func->getBody();
- if (!Body)
- return;
- SawFunctionBody = true;
- std::unique_ptr<CFG> cfg =
- CFG::buildCFG(nullptr, Body, Result.Context, CFG::BuildOptions());
- EXPECT_EQ(nullptr, cfg);
- }
- } Callback;
-
- ast_matchers::MatchFinder Finder;
- Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback);
- std::unique_ptr<tooling::FrontendActionFactory> Factory(
- tooling::newFrontendActionFactory(&Finder));
- std::vector<std::string> Args = {"-std=c++11", "-fno-delayed-template-parsing"};
- ASSERT_TRUE(tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args));
- EXPECT_TRUE(Callback.SawFunctionBody);
+// Constructing a CFG containing a delete expression on a dependent type should
+// not crash.
+TEST(CFG, DeleteExpressionOnDependentType) {
+ const char *Code = "template<class T>\n"
+ "void f(T t) {\n"
+ " delete t;\n"
+ "}\n";
+ EXPECT_EQ(BuiltCFG, BuildCFG(Code));
}
} // namespace
diff --git a/unittests/Basic/FileManagerTest.cpp b/unittests/Basic/FileManagerTest.cpp
index d8d85dd76c38..4cf21cd8459a 100644
--- a/unittests/Basic/FileManagerTest.cpp
+++ b/unittests/Basic/FileManagerTest.cpp
@@ -52,7 +52,7 @@ public:
}
// Implement FileSystemStatCache::getStat().
- LookupResult getStat(const char *Path, FileData &Data, bool isFile,
+ LookupResult getStat(StringRef Path, FileData &Data, bool isFile,
std::unique_ptr<vfs::File> *F,
vfs::FileSystem &FS) override {
if (StatCalls.count(Path) != 0) {
@@ -82,14 +82,14 @@ TEST_F(FileManagerTest, getVirtualFileSetsTheDirFieldCorrectly) {
const DirectoryEntry *dir = file->getDir();
ASSERT_TRUE(dir != nullptr);
- EXPECT_STREQ(".", dir->getName());
+ EXPECT_EQ(".", dir->getName());
file = manager.getVirtualFile("x/y/z.cpp", 42, 0);
ASSERT_TRUE(file != nullptr);
dir = file->getDir();
ASSERT_TRUE(dir != nullptr);
- EXPECT_STREQ("x/y", dir->getName());
+ EXPECT_EQ("x/y", dir->getName());
}
// Before any virtual file is added, no virtual directory exists.
@@ -115,11 +115,11 @@ TEST_F(FileManagerTest, getVirtualFileCreatesDirectoryEntriesForAncestors) {
const DirectoryEntry *dir = manager.getDirectory("virtual/dir");
ASSERT_TRUE(dir != nullptr);
- EXPECT_STREQ("virtual/dir", dir->getName());
+ EXPECT_EQ("virtual/dir", dir->getName());
dir = manager.getDirectory("virtual");
ASSERT_TRUE(dir != nullptr);
- EXPECT_STREQ("virtual", dir->getName());
+ EXPECT_EQ("virtual", dir->getName());
}
// getFile() returns non-NULL if a real file exists at the given path.
@@ -140,11 +140,11 @@ TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
const FileEntry *file = manager.getFile("/tmp/test");
ASSERT_TRUE(file != nullptr);
- EXPECT_STREQ("/tmp/test", file->getName());
+ EXPECT_EQ("/tmp/test", file->getName());
const DirectoryEntry *dir = file->getDir();
ASSERT_TRUE(dir != nullptr);
- EXPECT_STREQ("/tmp", dir->getName());
+ EXPECT_EQ("/tmp", dir->getName());
#ifdef LLVM_ON_WIN32
file = manager.getFile(FileName);
@@ -152,7 +152,7 @@ TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
dir = file->getDir();
ASSERT_TRUE(dir != NULL);
- EXPECT_STREQ(DirName, dir->getName());
+ EXPECT_EQ(DirName, dir->getName());
#endif
}
@@ -164,11 +164,11 @@ TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingVirtualFile) {
manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
const FileEntry *file = manager.getFile("virtual/dir/bar.h");
ASSERT_TRUE(file != nullptr);
- EXPECT_STREQ("virtual/dir/bar.h", file->getName());
+ EXPECT_EQ("virtual/dir/bar.h", file->getName());
const DirectoryEntry *dir = file->getDir();
ASSERT_TRUE(dir != nullptr);
- EXPECT_STREQ("virtual/dir", dir->getName());
+ EXPECT_EQ("virtual/dir", dir->getName());
}
// getFile() returns different FileEntries for different paths when
diff --git a/unittests/Basic/VirtualFileSystemTest.cpp b/unittests/Basic/VirtualFileSystemTest.cpp
index 3b26488a7fd9..580343d93ea1 100644
--- a/unittests/Basic/VirtualFileSystemTest.cpp
+++ b/unittests/Basic/VirtualFileSystemTest.cpp
@@ -12,7 +12,6 @@
#include "llvm/Support/Errc.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"
#include <map>
@@ -116,20 +115,23 @@ public:
}
void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
- vfs::Status S(Path, UniqueID(FSID, FileID++), sys::TimeValue::now(), 0, 0,
- 1024, sys::fs::file_type::regular_file, Perms);
+ vfs::Status S(Path, UniqueID(FSID, FileID++),
+ std::chrono::system_clock::now(), 0, 0, 1024,
+ sys::fs::file_type::regular_file, Perms);
addEntry(Path, S);
}
void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
- vfs::Status S(Path, UniqueID(FSID, FileID++), sys::TimeValue::now(), 0, 0,
- 0, sys::fs::file_type::directory_file, Perms);
+ vfs::Status S(Path, UniqueID(FSID, FileID++),
+ std::chrono::system_clock::now(), 0, 0, 0,
+ sys::fs::file_type::directory_file, Perms);
addEntry(Path, S);
}
void addSymlink(StringRef Path) {
- vfs::Status S(Path, UniqueID(FSID, FileID++), sys::TimeValue::now(), 0, 0,
- 0, sys::fs::file_type::symlink_file, sys::fs::all_all);
+ vfs::Status S(Path, UniqueID(FSID, FileID++),
+ std::chrono::system_clock::now(), 0, 0, 0,
+ sys::fs::file_type::symlink_file, sys::fs::all_all);
addEntry(Path, S);
}
};
diff --git a/unittests/Driver/CMakeLists.txt b/unittests/Driver/CMakeLists.txt
index 2df1eb24fd44..b9c52f7a53f9 100644
--- a/unittests/Driver/CMakeLists.txt
+++ b/unittests/Driver/CMakeLists.txt
@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_unittest(ClangDriverTests
+ DistroTest.cpp
ToolChainTest.cpp
MultilibTest.cpp
)
diff --git a/unittests/Driver/DistroTest.cpp b/unittests/Driver/DistroTest.cpp
new file mode 100644
index 000000000000..e3686e498060
--- /dev/null
+++ b/unittests/Driver/DistroTest.cpp
@@ -0,0 +1,305 @@
+//===- unittests/Driver/DistroTest.cpp --- ToolChains tests ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Unit tests for Distro detection.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Distro.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+using namespace clang;
+using namespace clang::driver;
+
+namespace {
+
+// The tests include all release-related files for each distribution
+// in the VFS, in order to make sure that earlier tests do not
+// accidentally result in incorrect distribution guess.
+
+TEST(DistroTest, DetectUbuntu) {
+ vfs::InMemoryFileSystem UbuntuTrustyFileSystem;
+ // Ubuntu uses Debian Sid version.
+ UbuntuTrustyFileSystem.addFile("/etc/debian_version", 0,
+ llvm::MemoryBuffer::getMemBuffer("jessie/sid\n"));
+ UbuntuTrustyFileSystem.addFile("/etc/lsb-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("DISTRIB_ID=Ubuntu\n"
+ "DISTRIB_RELEASE=14.04\n"
+ "DISTRIB_CODENAME=trusty\n"
+ "DISTRIB_DESCRIPTION=\"Ubuntu 14.04 LTS\"\n"));
+ UbuntuTrustyFileSystem.addFile("/etc/os-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("NAME=\"Ubuntu\"\n"
+ "VERSION=\"14.04, Trusty Tahr\"\n"
+ "ID=ubuntu\n"
+ "ID_LIKE=debian\n"
+ "PRETTY_NAME=\"Ubuntu 14.04 LTS\"\n"
+ "VERSION_ID=\"14.04\"\n"
+ "HOME_URL=\"http://www.ubuntu.com/\"\n"
+ "SUPPORT_URL=\"http://help.ubuntu.com/\"\n"
+ "BUG_REPORT_URL=\"http://bugs.launchpad.net/ubuntu/\"\n"));
+
+ Distro UbuntuTrusty{UbuntuTrustyFileSystem};
+ ASSERT_EQ(Distro(Distro::UbuntuTrusty), UbuntuTrusty);
+ ASSERT_TRUE(UbuntuTrusty.IsUbuntu());
+ ASSERT_FALSE(UbuntuTrusty.IsRedhat());
+ ASSERT_FALSE(UbuntuTrusty.IsOpenSUSE());
+ ASSERT_FALSE(UbuntuTrusty.IsDebian());
+
+ vfs::InMemoryFileSystem UbuntuYakketyFileSystem;
+ UbuntuYakketyFileSystem.addFile("/etc/debian_version", 0,
+ llvm::MemoryBuffer::getMemBuffer("stretch/sid\n"));
+ UbuntuYakketyFileSystem.addFile("/etc/lsb-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("DISTRIB_ID=Ubuntu\n"
+ "DISTRIB_RELEASE=16.10\n"
+ "DISTRIB_CODENAME=yakkety\n"
+ "DISTRIB_DESCRIPTION=\"Ubuntu 16.10\"\n"));
+ UbuntuYakketyFileSystem.addFile("/etc/os-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("NAME=\"Ubuntu\"\n"
+ "VERSION=\"16.10 (Yakkety Yak)\"\n"
+ "ID=ubuntu\n"
+ "ID_LIKE=debian\n"
+ "PRETTY_NAME=\"Ubuntu 16.10\"\n"
+ "VERSION_ID=\"16.10\"\n"
+ "HOME_URL=\"http://www.ubuntu.com/\"\n"
+ "SUPPORT_URL=\"http://help.ubuntu.com/\"\n"
+ "BUG_REPORT_URL=\"http://bugs.launchpad.net/ubuntu/\"\n"
+ "PRIVACY_POLICY_URL=\"http://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\n"
+ "VERSION_CODENAME=yakkety\n"
+ "UBUNTU_CODENAME=yakkety\n"));
+
+ Distro UbuntuYakkety{UbuntuYakketyFileSystem};
+ ASSERT_EQ(Distro(Distro::UbuntuYakkety), UbuntuYakkety);
+ ASSERT_TRUE(UbuntuYakkety.IsUbuntu());
+ ASSERT_FALSE(UbuntuYakkety.IsRedhat());
+ ASSERT_FALSE(UbuntuYakkety.IsOpenSUSE());
+ ASSERT_FALSE(UbuntuYakkety.IsDebian());
+}
+
+TEST(DistroTest, DetectRedhat) {
+ vfs::InMemoryFileSystem Fedora25FileSystem;
+ Fedora25FileSystem.addFile("/etc/system-release-cpe", 0,
+ llvm::MemoryBuffer::getMemBuffer("cpe:/o:fedoraproject:fedora:25\n"));
+ // Both files are symlinks to fedora-release.
+ Fedora25FileSystem.addFile("/etc/system-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("Fedora release 25 (Twenty Five)\n"));
+ Fedora25FileSystem.addFile("/etc/redhat-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("Fedora release 25 (Twenty Five)\n"));
+ Fedora25FileSystem.addFile("/etc/fedora-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("Fedora release 25 (Twenty Five)\n"));
+ Fedora25FileSystem.addFile("/etc/os-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("NAME=Fedora\n"
+ "VERSION=\"25 (Twenty Five)\"\n"
+ "ID=fedora\n"
+ "VERSION_ID=25\n"
+ "PRETTY_NAME=\"Fedora 25 (Twenty Five)\"\n"
+ "ANSI_COLOR=\"0;34\"\n"
+ "CPE_NAME=\"cpe:/o:fedoraproject:fedora:25\"\n"
+ "HOME_URL=\"https://fedoraproject.org/\"\n"
+ "BUG_REPORT_URL=\"https://bugzilla.redhat.com/\"\n"
+ "REDHAT_BUGZILLA_PRODUCT=\"Fedora\"\n"
+ "REDHAT_BUGZILLA_PRODUCT_VERSION=25\n"
+ "REDHAT_SUPPORT_PRODUCT=\"Fedora\"\n"
+ "REDHAT_SUPPORT_PRODUCT_VERSION=25\n"
+ "PRIVACY_POLICY_URL=https://fedoraproject.org/wiki/Legal:PrivacyPolicy\n"));
+ Distro Fedora25{Fedora25FileSystem};
+ ASSERT_EQ(Distro(Distro::Fedora), Fedora25);
+ ASSERT_FALSE(Fedora25.IsUbuntu());
+ ASSERT_TRUE(Fedora25.IsRedhat());
+ ASSERT_FALSE(Fedora25.IsOpenSUSE());
+ ASSERT_FALSE(Fedora25.IsDebian());
+
+ vfs::InMemoryFileSystem CentOS7FileSystem;
+ CentOS7FileSystem.addFile("/etc/system-release-cpe", 0,
+ llvm::MemoryBuffer::getMemBuffer("cpe:/o:centos:centos:7\n"));
+ // Both files are symlinks to centos-release.
+ CentOS7FileSystem.addFile("/etc/system-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("CentOS Linux release 7.2.1511 (Core) \n"));
+ CentOS7FileSystem.addFile("/etc/redhat-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("CentOS Linux release 7.2.1511 (Core) \n"));
+ CentOS7FileSystem.addFile("/etc/centos-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("CentOS Linux release 7.2.1511 (Core) \n"));
+ CentOS7FileSystem.addFile("/etc/centos-release-upstream", 0,
+ llvm::MemoryBuffer::getMemBuffer("Derived from Red Hat Enterprise Linux 7.2 (Source)\n"));
+ CentOS7FileSystem.addFile("/etc/os-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("NAME=\"CentOS Linux\"\n"
+ "VERSION=\"7 (Core)\"\n"
+ "ID=\"centos\"\n"
+ "ID_LIKE=\"rhel fedora\"\n"
+ "VERSION_ID=\"7\"\n"
+ "PRETTY_NAME=\"CentOS Linux 7 (Core)\"\n"
+ "ANSI_COLOR=\"0;31\"\n"
+ "CPE_NAME=\"cpe:/o:centos:centos:7\"\n"
+ "HOME_URL=\"https://www.centos.org/\"\n"
+ "BUG_REPORT_URL=\"https://bugs.centos.org/\"\n"
+ "\n"
+ "CENTOS_MANTISBT_PROJECT=\"CentOS-7\"\n"
+ "CENTOS_MANTISBT_PROJECT_VERSION=\"7\"\n"
+ "REDHAT_SUPPORT_PRODUCT=\"centos\"\n"
+ "REDHAT_SUPPORT_PRODUCT_VERSION=\"7\"\n"));
+
+ Distro CentOS7{CentOS7FileSystem};
+ ASSERT_EQ(Distro(Distro::RHEL7), CentOS7);
+ ASSERT_FALSE(CentOS7.IsUbuntu());
+ ASSERT_TRUE(CentOS7.IsRedhat());
+ ASSERT_FALSE(CentOS7.IsOpenSUSE());
+ ASSERT_FALSE(CentOS7.IsDebian());
+}
+
+TEST(DistroTest, DetectOpenSUSE) {
+ vfs::InMemoryFileSystem OpenSUSELeap421FileSystem;
+ OpenSUSELeap421FileSystem.addFile("/etc/SuSE-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("openSUSE 42.1 (x86_64)\n"
+ "VERSION = 42.1\n"
+ "CODENAME = Malachite\n"
+ "# /etc/SuSE-release is deprecated and will be removed in the future, use /etc/os-release instead\n"));
+ OpenSUSELeap421FileSystem.addFile("/etc/os-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("NAME=\"openSUSE Leap\"\n"
+ "VERSION=\"42.1\"\n"
+ "VERSION_ID=\"42.1\"\n"
+ "PRETTY_NAME=\"openSUSE Leap 42.1 (x86_64)\"\n"
+ "ID=opensuse\n"
+ "ANSI_COLOR=\"0;32\"\n"
+ "CPE_NAME=\"cpe:/o:opensuse:opensuse:42.1\"\n"
+ "BUG_REPORT_URL=\"https://bugs.opensuse.org\"\n"
+ "HOME_URL=\"https://opensuse.org/\"\n"
+ "ID_LIKE=\"suse\"\n"));
+
+ Distro OpenSUSELeap421{OpenSUSELeap421FileSystem};
+ ASSERT_EQ(Distro(Distro::OpenSUSE), OpenSUSELeap421);
+ ASSERT_FALSE(OpenSUSELeap421.IsUbuntu());
+ ASSERT_FALSE(OpenSUSELeap421.IsRedhat());
+ ASSERT_TRUE(OpenSUSELeap421.IsOpenSUSE());
+ ASSERT_FALSE(OpenSUSELeap421.IsDebian());
+
+ vfs::InMemoryFileSystem OpenSUSE132FileSystem;
+ OpenSUSE132FileSystem.addFile("/etc/SuSE-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("openSUSE 13.2 (x86_64)\n"
+ "VERSION = 13.2\n"
+ "CODENAME = Harlequin\n"
+ "# /etc/SuSE-release is deprecated and will be removed in the future, use /etc/os-release instead\n"));
+ OpenSUSE132FileSystem.addFile("/etc/os-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("NAME=openSUSE\n"
+ "VERSION=\"13.2 (Harlequin)\"\n"
+ "VERSION_ID=\"13.2\"\n"
+ "PRETTY_NAME=\"openSUSE 13.2 (Harlequin) (x86_64)\"\n"
+ "ID=opensuse\n"
+ "ANSI_COLOR=\"0;32\"\n"
+ "CPE_NAME=\"cpe:/o:opensuse:opensuse:13.2\"\n"
+ "BUG_REPORT_URL=\"https://bugs.opensuse.org\"\n"
+ "HOME_URL=\"https://opensuse.org/\"\n"
+ "ID_LIKE=\"suse\"\n"));
+
+ Distro OpenSUSE132{OpenSUSE132FileSystem};
+ ASSERT_EQ(Distro(Distro::OpenSUSE), OpenSUSE132);
+ ASSERT_FALSE(OpenSUSE132.IsUbuntu());
+ ASSERT_FALSE(OpenSUSE132.IsRedhat());
+ ASSERT_TRUE(OpenSUSE132.IsOpenSUSE());
+ ASSERT_FALSE(OpenSUSE132.IsDebian());
+
+ vfs::InMemoryFileSystem SLES10FileSystem;
+ SLES10FileSystem.addFile("/etc/SuSE-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("SUSE Linux Enterprise Server 10 (x86_64)\n"
+ "VERSION = 10\n"
+ "PATCHLEVEL = 4\n"));
+ SLES10FileSystem.addFile("/etc/lsb_release", 0,
+ llvm::MemoryBuffer::getMemBuffer("LSB_VERSION=\"core-2.0-noarch:core-3.0-noarch:core-2.0-x86_64:core-3.0-x86_64\"\n"));
+
+ // SLES10 is unsupported and therefore evaluates to unknown
+ Distro SLES10{SLES10FileSystem};
+ ASSERT_EQ(Distro(Distro::UnknownDistro), SLES10);
+ ASSERT_FALSE(SLES10.IsUbuntu());
+ ASSERT_FALSE(SLES10.IsRedhat());
+ ASSERT_FALSE(SLES10.IsOpenSUSE());
+ ASSERT_FALSE(SLES10.IsDebian());
+}
+
+TEST(DistroTest, DetectDebian) {
+ vfs::InMemoryFileSystem DebianJessieFileSystem;
+ DebianJessieFileSystem.addFile("/etc/debian_version", 0,
+ llvm::MemoryBuffer::getMemBuffer("8.6\n"));
+ DebianJessieFileSystem.addFile("/etc/os-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("PRETTY_NAME=\"Debian GNU/Linux 8 (jessie)\"\n"
+ "NAME=\"Debian GNU/Linux\"\n"
+ "VERSION_ID=\"8\"\n"
+ "VERSION=\"8 (jessie)\"\n"
+ "ID=debian\n"
+ "HOME_URL=\"http://www.debian.org/\"\n"
+ "SUPPORT_URL=\"http://www.debian.org/support\"\n"
+ "BUG_REPORT_URL=\"https://bugs.debian.org/\"\n"));
+
+ Distro DebianJessie{DebianJessieFileSystem};
+ ASSERT_EQ(Distro(Distro::DebianJessie), DebianJessie);
+ ASSERT_FALSE(DebianJessie.IsUbuntu());
+ ASSERT_FALSE(DebianJessie.IsRedhat());
+ ASSERT_FALSE(DebianJessie.IsOpenSUSE());
+ ASSERT_TRUE(DebianJessie.IsDebian());
+
+ vfs::InMemoryFileSystem DebianStretchSidFileSystem;
+ DebianStretchSidFileSystem.addFile("/etc/debian_version", 0,
+ llvm::MemoryBuffer::getMemBuffer("stretch/sid\n"));
+ DebianStretchSidFileSystem.addFile("/etc/os-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("PRETTY_NAME=\"Debian GNU/Linux stretch/sid\"\n"
+ "NAME=\"Debian GNU/Linux\"\n"
+ "ID=debian\n"
+ "HOME_URL=\"http://www.debian.org/\"\n"
+ "SUPPORT_URL=\"http://www.debian.org/support\"\n"
+ "BUG_REPORT_URL=\"https://bugs.debian.org/\"\n"));
+
+ Distro DebianStretchSid{DebianStretchSidFileSystem};
+ ASSERT_EQ(Distro(Distro::DebianStretch), DebianStretchSid);
+ ASSERT_FALSE(DebianStretchSid.IsUbuntu());
+ ASSERT_FALSE(DebianStretchSid.IsRedhat());
+ ASSERT_FALSE(DebianStretchSid.IsOpenSUSE());
+ ASSERT_TRUE(DebianStretchSid.IsDebian());
+}
+
+TEST(DistroTest, DetectExherbo) {
+ vfs::InMemoryFileSystem ExherboFileSystem;
+ ExherboFileSystem.addFile("/etc/exherbo-release", 0, // (ASCII art)
+ llvm::MemoryBuffer::getMemBuffer(""));
+ ExherboFileSystem.addFile("/etc/os-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("NAME=\"Exherbo\"\n"
+ "PRETTY_NAME=\"Exherbo Linux\"\n"
+ "ID=\"exherbo\"\n"
+ "ANSI_COLOR=\"0;32\"\n"
+ "HOME_URL=\"https://www.exherbo.org/\"\n"
+ "SUPPORT_URL=\"irc://irc.freenode.net/#exherbo\"\n"
+ "BUG_REPORT_URL=\"https://bugs.exherbo.org/\"\n"));
+
+ Distro Exherbo{ExherboFileSystem};
+ ASSERT_EQ(Distro(Distro::Exherbo), Exherbo);
+ ASSERT_FALSE(Exherbo.IsUbuntu());
+ ASSERT_FALSE(Exherbo.IsRedhat());
+ ASSERT_FALSE(Exherbo.IsOpenSUSE());
+ ASSERT_FALSE(Exherbo.IsDebian());
+}
+
+TEST(DistroTest, DetectArchLinux) {
+ vfs::InMemoryFileSystem ArchLinuxFileSystem;
+ ArchLinuxFileSystem.addFile("/etc/arch-release", 0, // (empty)
+ llvm::MemoryBuffer::getMemBuffer(""));
+ ArchLinuxFileSystem.addFile("/etc/os-release", 0,
+ llvm::MemoryBuffer::getMemBuffer("NAME=\"Arch Linux\"\n"
+ "ID=arch\n"
+ "PRETTY_NAME=\"Arch Linux\"\n"
+ "ANSI_COLOR=\"0;36\"\n"
+ "HOME_URL=\"https://www.archlinux.org/\"\n"
+ "SUPPORT_URL=\"https://bbs.archlinux.org/\"\n"
+ "BUG_REPORT_URL=\"https://bugs.archlinux.org/\"\n"));
+
+ Distro ArchLinux{ArchLinuxFileSystem};
+ ASSERT_EQ(Distro(Distro::ArchLinux), ArchLinux);
+ ASSERT_FALSE(ArchLinux.IsUbuntu());
+ ASSERT_FALSE(ArchLinux.IsRedhat());
+ ASSERT_FALSE(ArchLinux.IsOpenSUSE());
+ ASSERT_FALSE(ArchLinux.IsDebian());
+}
+
+} // end anonymous namespace
diff --git a/unittests/Driver/ToolChainTest.cpp b/unittests/Driver/ToolChainTest.cpp
index ef21e2d17c6c..f7ba3eeab21b 100644
--- a/unittests/Driver/ToolChainTest.cpp
+++ b/unittests/Driver/ToolChainTest.cpp
@@ -117,4 +117,29 @@ TEST(ToolChainTest, VFSGCCInstallationRelativeDir) {
S);
}
+TEST(ToolChainTest, DefaultDriverMode) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ struct TestDiagnosticConsumer : public DiagnosticConsumer {};
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+ IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
+ new vfs::InMemoryFileSystem);
+
+ Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
+ InMemoryFileSystem);
+ Driver CXXDriver("/home/test/bin/clang++", "arm-linux-gnueabi", Diags,
+ InMemoryFileSystem);
+ Driver CLDriver("/home/test/bin/clang-cl", "arm-linux-gnueabi", Diags,
+ InMemoryFileSystem);
+
+ std::unique_ptr<Compilation> CC(CCDriver.BuildCompilation({"foo.cpp"}));
+ std::unique_ptr<Compilation> CXX(CXXDriver.BuildCompilation({"foo.cpp"}));
+ std::unique_ptr<Compilation> CL(CLDriver.BuildCompilation({"foo.cpp"}));
+
+ EXPECT_TRUE(CCDriver.CCCIsCC());
+ EXPECT_TRUE(CXXDriver.CCCIsCXX());
+ EXPECT_TRUE(CLDriver.IsCLMode());
+}
+
} // end anonymous namespace
diff --git a/unittests/Format/CMakeLists.txt b/unittests/Format/CMakeLists.txt
index 240be6ead2a5..eb7756a0ba56 100644
--- a/unittests/Format/CMakeLists.txt
+++ b/unittests/Format/CMakeLists.txt
@@ -7,6 +7,7 @@ add_clang_unittest(FormatTests
FormatTest.cpp
FormatTestJava.cpp
FormatTestJS.cpp
+ FormatTestObjC.cpp
FormatTestProto.cpp
FormatTestSelective.cpp
SortImportsTestJS.cpp
diff --git a/unittests/Format/CleanupTest.cpp b/unittests/Format/CleanupTest.cpp
index 5f85c53b780a..6ac5f695d437 100644
--- a/unittests/Format/CleanupTest.cpp
+++ b/unittests/Format/CleanupTest.cpp
@@ -9,11 +9,15 @@
#include "clang/Format/Format.h"
+#include "../Tooling/ReplacementTest.h"
#include "../Tooling/RewriterTestContext.h"
#include "clang/Tooling/Core/Replacement.h"
#include "gtest/gtest.h"
+using clang::tooling::ReplacementTest;
+using clang::tooling::toReplacements;
+
namespace clang {
namespace format {
namespace {
@@ -29,6 +33,15 @@ protected:
EXPECT_TRUE(static_cast<bool>(Result));
return *Result;
}
+
+ // Returns code after cleanup around \p Offsets.
+ std::string cleanupAroundOffsets(llvm::ArrayRef<unsigned> Offsets,
+ llvm::StringRef Code) {
+ std::vector<tooling::Range> Ranges;
+ for (auto Offset : Offsets)
+ Ranges.push_back(tooling::Range(Offset, 0));
+ return cleanup(Code, Ranges);
+ }
};
TEST_F(CleanupTest, DeleteEmptyNamespaces) {
@@ -43,12 +56,7 @@ TEST_F(CleanupTest, DeleteEmptyNamespaces) {
std::string Expected = "\n\n\n\n\nnamespace C {\n"
"namespace D { int i; }\n \n"
"}";
- std::vector<tooling::Range> Ranges;
- Ranges.push_back(tooling::Range(28, 0));
- Ranges.push_back(tooling::Range(91, 6));
- Ranges.push_back(tooling::Range(132, 0));
- std::string Result = cleanup(Code, Ranges);
- EXPECT_EQ(Expected, Result);
+ EXPECT_EQ(Expected, cleanupAroundOffsets({28, 91, 132}, Code));
}
TEST_F(CleanupTest, NamespaceWithSyntaxError) {
@@ -64,8 +72,7 @@ TEST_F(CleanupTest, NamespaceWithSyntaxError) {
"namespace D int i; }\n \n"
"}";
std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
- std::string Result = cleanup(Code, Ranges);
- EXPECT_EQ(Expected, Result);
+ EXPECT_EQ(Expected, cleanup(Code, Ranges));
}
TEST_F(CleanupTest, EmptyNamespaceNotAffected) {
@@ -76,9 +83,7 @@ TEST_F(CleanupTest, EmptyNamespaceNotAffected) {
std::string Expected = "namespace A {\n\n"
"namespace {\n\n}}";
// Set the changed range to be the second "\n".
- std::vector<tooling::Range> Ranges(1, tooling::Range(14, 0));
- std::string Result = cleanup(Code, Ranges);
- EXPECT_EQ(Expected, Result);
+ EXPECT_EQ(Expected, cleanupAroundOffsets({14}, Code));
}
TEST_F(CleanupTest, EmptyNamespaceWithCommentsNoBreakBeforeBrace) {
@@ -114,55 +119,94 @@ TEST_F(CleanupTest, EmptyNamespaceWithCommentsBreakBeforeBrace) {
EXPECT_EQ(Expected, Result);
}
+TEST_F(CleanupTest, EmptyNamespaceAroundConditionalCompilation) {
+ std::string Code = "#ifdef A\n"
+ "int a;\n"
+ "int b;\n"
+ "#else\n"
+ "#endif\n"
+ "namespace {}";
+ std::string Expected = "#ifdef A\n"
+ "int a;\n"
+ "int b;\n"
+ "#else\n"
+ "#endif\n";
+ std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
+ FormatStyle Style = getLLVMStyle();
+ std::string Result = cleanup(Code, Ranges, Style);
+ EXPECT_EQ(Expected, Result);
+}
+
TEST_F(CleanupTest, CtorInitializationSimpleRedundantComma) {
std::string Code = "class A {\nA() : , {} };";
std::string Expected = "class A {\nA() {} };";
- std::vector<tooling::Range> Ranges;
- Ranges.push_back(tooling::Range(17, 0));
- Ranges.push_back(tooling::Range(19, 0));
- std::string Result = cleanup(Code, Ranges);
- EXPECT_EQ(Expected, Result);
+ EXPECT_EQ(Expected, cleanupAroundOffsets({17, 19}, Code));
Code = "class A {\nA() : x(1), {} };";
Expected = "class A {\nA() : x(1) {} };";
- Ranges.clear();
- Ranges.push_back(tooling::Range(23, 0));
- Result = cleanup(Code, Ranges);
- EXPECT_EQ(Expected, Result);
+ EXPECT_EQ(Expected, cleanupAroundOffsets({23}, Code));
Code = "class A {\nA() :,,,,{} };";
Expected = "class A {\nA() {} };";
- Ranges.clear();
- Ranges.push_back(tooling::Range(15, 0));
- Result = cleanup(Code, Ranges);
- EXPECT_EQ(Expected, Result);
+ EXPECT_EQ(Expected, cleanupAroundOffsets({15}, Code));
}
-TEST_F(CleanupTest, ListSimpleRedundantComma) {
+TEST_F(CleanupTest, CtorInitializationSimpleRedundantColon) {
+ std::string Code = "class A {\nA() : =default; };";
+ std::string Expected = "class A {\nA() =default; };";
+ EXPECT_EQ(Expected, cleanupAroundOffsets({15}, Code));
+
+ Code = "class A {\nA() : , =default; };";
+ Expected = "class A {\nA() =default; };";
+ EXPECT_EQ(Expected, cleanupAroundOffsets({15}, Code));
+}
+
+TEST_F(CleanupTest, ListRedundantComma) {
std::string Code = "void f() { std::vector<int> v = {1,2,,,3,{4,5}}; }";
std::string Expected = "void f() { std::vector<int> v = {1,2,3,{4,5}}; }";
- std::vector<tooling::Range> Ranges;
- Ranges.push_back(tooling::Range(40, 0));
- std::string Result = cleanup(Code, Ranges);
- EXPECT_EQ(Expected, Result);
+ EXPECT_EQ(Expected, cleanupAroundOffsets({40}, Code));
Code = "int main() { f(1,,2,3,,4);}";
Expected = "int main() { f(1,2,3,4);}";
- Ranges.clear();
- Ranges.push_back(tooling::Range(17, 0));
- Ranges.push_back(tooling::Range(22, 0));
- Result = cleanup(Code, Ranges);
- EXPECT_EQ(Expected, Result);
+ EXPECT_EQ(Expected, cleanupAroundOffsets({17, 22}, Code));
+}
+
+TEST_F(CleanupTest, TrailingCommaInParens) {
+ std::string Code = "int main() { f(,1,,2,3,f(1,2,),4,,);}";
+ std::string Expected = "int main() { f(1,2,3,f(1,2),4);}";
+ EXPECT_EQ(Expected, cleanupAroundOffsets({15, 18, 29, 33}, Code));
+}
+
+TEST_F(CleanupTest, TrailingCommaInBraces) {
+ // Trainling comma is allowed in brace list.
+ // If there was trailing comma in the original code, then trailing comma is
+ // preserved. In this example, element between the last two commas is deleted
+ // causing the second-last comma to be redundant.
+ std::string Code = "void f() { std::vector<int> v = {1,2,3,,}; }";
+ std::string Expected = "void f() { std::vector<int> v = {1,2,3,}; }";
+ EXPECT_EQ(Expected, cleanupAroundOffsets({39}, Code));
+
+ // If there was no trailing comma in the original code, then trainling comma
+ // introduced by replacements should be cleaned up. In this example, the
+ // element after the last comma is deleted causing the last comma to be
+ // redundant.
+ Code = "void f() { std::vector<int> v = {1,2,3,}; }";
+ // FIXME: redundant trailing comma should be removed.
+ Expected = "void f() { std::vector<int> v = {1,2,3,}; }";
+ EXPECT_EQ(Expected, cleanupAroundOffsets({39}, Code));
+
+ // Still no trailing comma in the original code, but two elements are deleted,
+ // which makes it seems like there was trailing comma.
+ Code = "void f() { std::vector<int> v = {1, 2, 3, , }; }";
+ // FIXME: redundant trailing comma should also be removed.
+ Expected = "void f() { std::vector<int> v = {1, 2, 3, }; }";
+ EXPECT_EQ(Expected, cleanupAroundOffsets({42, 44}, Code));
}
TEST_F(CleanupTest, CtorInitializationBracesInParens) {
std::string Code = "class A {\nA() : x({1}),, {} };";
std::string Expected = "class A {\nA() : x({1}) {} };";
- std::vector<tooling::Range> Ranges;
- Ranges.push_back(tooling::Range(24, 0));
- Ranges.push_back(tooling::Range(26, 0));
- std::string Result = cleanup(Code, Ranges);
- EXPECT_EQ(Expected, Result);
+ EXPECT_EQ(Expected, cleanupAroundOffsets({24, 26}, Code));
}
TEST_F(CleanupTest, RedundantCommaNotInAffectedRanges) {
@@ -184,44 +228,35 @@ TEST_F(CleanupTest, RedundantCommaNotInAffectedRanges) {
EXPECT_EQ(Expected, Result);
}
-// FIXME: delete comments too.
-TEST_F(CleanupTest, CtorInitializationCommentAroundCommas) {
- // Remove redundant commas around comment.
- std::string Code = "class A {\nA() : x({1}), /* comment */, {} };";
- std::string Expected = "class A {\nA() : x({1}) /* comment */ {} };";
- std::vector<tooling::Range> Ranges;
- Ranges.push_back(tooling::Range(25, 0));
- Ranges.push_back(tooling::Range(40, 0));
- std::string Result = cleanup(Code, Ranges);
- EXPECT_EQ(Expected, Result);
+TEST_F(CleanupTest, RemoveCommentsAroundDeleteCode) {
+ std::string Code =
+ "class A {\nA() : x({1}), /* comment */, /* comment */ {} };";
+ std::string Expected = "class A {\nA() : x({1}) {} };";
+ EXPECT_EQ(Expected, cleanupAroundOffsets({25, 40}, Code));
- // Remove trailing comma and ignore comment.
- Code = "class A {\nA() : x({1}), // comment\n{} };";
- Expected = "class A {\nA() : x({1}) // comment\n{} };";
- Ranges = std::vector<tooling::Range>(1, tooling::Range(25, 0));
- Result = cleanup(Code, Ranges);
- EXPECT_EQ(Expected, Result);
+ Code = "class A {\nA() : x({1}), // comment\n {} };";
+ Expected = "class A {\nA() : x({1})\n {} };";
+ EXPECT_EQ(Expected, cleanupAroundOffsets({25}, Code));
- // Remove trailing comma and ignore comment.
Code = "class A {\nA() : x({1}), // comment\n , y(1),{} };";
- Expected = "class A {\nA() : x({1}), // comment\n y(1){} };";
- Ranges = std::vector<tooling::Range>(1, tooling::Range(38, 0));
- Result = cleanup(Code, Ranges);
- EXPECT_EQ(Expected, Result);
+ Expected = "class A {\nA() : x({1}), y(1){} };";
+ EXPECT_EQ(Expected, cleanupAroundOffsets({38}, Code));
- // Remove trailing comma and ignore comment.
Code = "class A {\nA() : x({1}), \n/* comment */, y(1),{} };";
- Expected = "class A {\nA() : x({1}), \n/* comment */ y(1){} };";
- Ranges = std::vector<tooling::Range>(1, tooling::Range(40, 0));
- Result = cleanup(Code, Ranges);
- EXPECT_EQ(Expected, Result);
+ Expected = "class A {\nA() : x({1}), \n y(1){} };";
+ EXPECT_EQ(Expected, cleanupAroundOffsets({40}, Code));
- // Remove trailing comma and ignore comment.
Code = "class A {\nA() : , // comment\n y(1),{} };";
Expected = "class A {\nA() : // comment\n y(1){} };";
- Ranges = std::vector<tooling::Range>(1, tooling::Range(17, 0));
- Result = cleanup(Code, Ranges);
- EXPECT_EQ(Expected, Result);
+ EXPECT_EQ(Expected, cleanupAroundOffsets({17}, Code));
+
+ Code = "class A {\nA() // comment\n : ,,{} };";
+ Expected = "class A {\nA() // comment\n {} };";
+ EXPECT_EQ(Expected, cleanupAroundOffsets({30}, Code));
+
+ Code = "class A {\nA() // comment\n : ,,=default; };";
+ Expected = "class A {\nA() // comment\n =default; };";
+ EXPECT_EQ(Expected, cleanupAroundOffsets({30}, Code));
}
TEST_F(CleanupTest, CtorInitializerInNamespace) {
@@ -241,15 +276,19 @@ TEST_F(CleanupTest, CtorInitializerInNamespace) {
EXPECT_EQ(Expected, Result);
}
-class CleanUpReplacementsTest : public ::testing::Test {
+class CleanUpReplacementsTest : public ReplacementTest {
protected:
tooling::Replacement createReplacement(unsigned Offset, unsigned Length,
StringRef Text) {
return tooling::Replacement(FileName, Offset, Length, Text);
}
- tooling::Replacement createInsertion(StringRef HeaderName) {
- return createReplacement(UINT_MAX, 0, HeaderName);
+ tooling::Replacement createInsertion(StringRef IncludeDirective) {
+ return createReplacement(UINT_MAX, 0, IncludeDirective);
+ }
+
+ tooling::Replacement createDeletion(StringRef HeaderName) {
+ return createReplacement(UINT_MAX, 1, HeaderName);
}
inline std::string apply(StringRef Code,
@@ -304,9 +343,9 @@ TEST_F(CleanUpReplacementsTest, FixOnlyAffectedCodeAfterReplacements) {
"namespace D { int i; }\n\n"
"int x= 0;"
"}";
- tooling::Replacements Replaces = {
- createReplacement(getOffset(Code, 3, 3), 6, ""),
- createReplacement(getOffset(Code, 9, 34), 6, "")};
+ tooling::Replacements Replaces =
+ toReplacements({createReplacement(getOffset(Code, 3, 3), 6, ""),
+ createReplacement(getOffset(Code, 9, 34), 6, "")});
EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
}
@@ -315,7 +354,8 @@ TEST_F(CleanUpReplacementsTest, NoExistingIncludeWithoutDefine) {
std::string Code = "int main() {}";
std::string Expected = "#include \"a.h\"\n"
"int main() {}";
- tooling::Replacements Replaces = {createInsertion("#include \"a.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"a.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -332,7 +372,8 @@ TEST_F(CleanUpReplacementsTest, NoExistingIncludeWithDefine) {
"#define MMM 123\n"
"#endif";
- tooling::Replacements Replaces = {createInsertion("#include \"b.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"b.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -357,7 +398,8 @@ TEST_F(CleanUpReplacementsTest, InsertBeforeCategoryWithLowerPriority) {
"#define MMM 123\n"
"#endif";
- tooling::Replacements Replaces = {createInsertion("#include \"a.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"a.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -369,7 +411,8 @@ TEST_F(CleanUpReplacementsTest, InsertAfterMainHeader) {
"#include <a>\n"
"\n"
"int main() {}";
- tooling::Replacements Replaces = {createInsertion("#include <a>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <a>")});
Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -382,7 +425,8 @@ TEST_F(CleanUpReplacementsTest, InsertBeforeSystemHeaderLLVM) {
"#include <memory>\n"
"\n"
"int main() {}";
- tooling::Replacements Replaces = {createInsertion("#include \"z.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"z.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -394,7 +438,8 @@ TEST_F(CleanUpReplacementsTest, InsertAfterSystemHeaderGoogle) {
"#include \"z.h\"\n"
"\n"
"int main() {}";
- tooling::Replacements Replaces = {createInsertion("#include \"z.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"z.h\"")});
Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -412,8 +457,9 @@ TEST_F(CleanUpReplacementsTest, InsertOneIncludeLLVMStyle) {
"#include \"clang/Format/Format.h\"\n"
"#include \"llvm/x/y.h\"\n"
"#include <memory>\n";
- tooling::Replacements Replaces = {createInsertion("#include \"d.h\""),
- createInsertion("#include \"llvm/x/y.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"d.h\""),
+ createInsertion("#include \"llvm/x/y.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -430,8 +476,9 @@ TEST_F(CleanUpReplacementsTest, InsertMultipleIncludesLLVMStyle) {
"#include \"clang/Format/Format.h\"\n"
"#include <memory>\n"
"#include <list>\n";
- tooling::Replacements Replaces = {createInsertion("#include <list>"),
- createInsertion("#include \"new/new.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <list>"),
+ createInsertion("#include \"new/new.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -447,7 +494,8 @@ TEST_F(CleanUpReplacementsTest, InsertNewSystemIncludeGoogleStyle) {
"\n"
"#include \"y/a.h\"\n"
"#include \"z/b.h\"\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -467,8 +515,9 @@ TEST_F(CleanUpReplacementsTest, InsertMultipleIncludesGoogleStyle) {
"#include \"y/a.h\"\n"
"#include \"z/b.h\"\n"
"#include \"x/x.h\"\n";
- tooling::Replacements Replaces = {createInsertion("#include <list>"),
- createInsertion("#include \"x/x.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <list>"),
+ createInsertion("#include \"x/x.h\"")});
Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -482,12 +531,11 @@ TEST_F(CleanUpReplacementsTest, InsertMultipleNewHeadersAndSortLLVM) {
"#include <list>\n"
"#include <vector>\n"
"int x;";
- tooling::Replacements Replaces = {createInsertion("#include \"a.h\""),
- createInsertion("#include \"c.h\""),
- createInsertion("#include \"b.h\""),
- createInsertion("#include <vector>"),
- createInsertion("#include <list>"),
- createInsertion("#include \"fix.h\"")};
+ tooling::Replacements Replaces = toReplacements(
+ {createInsertion("#include \"a.h\""), createInsertion("#include \"c.h\""),
+ createInsertion("#include \"b.h\""),
+ createInsertion("#include <vector>"), createInsertion("#include <list>"),
+ createInsertion("#include \"fix.h\"")});
EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
}
@@ -500,12 +548,11 @@ TEST_F(CleanUpReplacementsTest, InsertMultipleNewHeadersAndSortGoogle) {
"#include \"b.h\"\n"
"#include \"c.h\"\n"
"int x;";
- tooling::Replacements Replaces = {createInsertion("#include \"a.h\""),
- createInsertion("#include \"c.h\""),
- createInsertion("#include \"b.h\""),
- createInsertion("#include <vector>"),
- createInsertion("#include <list>"),
- createInsertion("#include \"fix.h\"")};
+ tooling::Replacements Replaces = toReplacements(
+ {createInsertion("#include \"a.h\""), createInsertion("#include \"c.h\""),
+ createInsertion("#include \"b.h\""),
+ createInsertion("#include <vector>"), createInsertion("#include <list>"),
+ createInsertion("#include \"fix.h\"")});
Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
}
@@ -526,13 +573,12 @@ TEST_F(CleanUpReplacementsTest, FormatCorrectLineWhenHeadersAreInserted) {
"int a;\n"
"int b;\n"
"int a;";
- tooling::Replacements Replaces = {
- createReplacement(getOffset(Code, 4, 8), 1, "b"),
- createInsertion("#include <vector>"),
- createInsertion("#include <list>"),
- createInsertion("#include \"clang/x/x.h\""),
- createInsertion("#include \"y.h\""),
- createInsertion("#include \"x.h\"")};
+ tooling::Replacements Replaces = toReplacements(
+ {createReplacement(getOffset(Code, 4, 8), 1, "b"),
+ createInsertion("#include <vector>"), createInsertion("#include <list>"),
+ createInsertion("#include \"clang/x/x.h\""),
+ createInsertion("#include \"y.h\""),
+ createInsertion("#include \"x.h\"")});
EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
}
@@ -544,7 +590,8 @@ TEST_F(CleanUpReplacementsTest, NotConfusedByDefine) {
"void f() {}\n"
"#define A \\\n"
" int i;";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
}
@@ -556,7 +603,8 @@ TEST_F(CleanUpReplacementsTest, SkippedTopComment) {
"\n"
" // comment\n"
"#include <vector>\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -574,7 +622,8 @@ TEST_F(CleanUpReplacementsTest, SkippedMixedComments) {
"* comment\n"
"*/\n"
"#include <vector>\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -592,7 +641,8 @@ TEST_F(CleanUpReplacementsTest, MultipleBlockCommentsInOneLine) {
"\n\n"
"/* c1 */ /*c2 */\n"
"#include <vector>\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -614,7 +664,8 @@ TEST_F(CleanUpReplacementsTest, CodeAfterComments) {
"\n"
"#include <vector>\n"
"int x;\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -626,7 +677,8 @@ TEST_F(CleanUpReplacementsTest, FakeHeaderGuardIfDef) {
"#include <vector>\n"
"#ifdef X\n"
"#define X\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -642,7 +694,8 @@ TEST_F(CleanUpReplacementsTest, RealHeaderGuardAfterComments) {
"#include <vector>\n"
"int x;\n"
"#define Y 1\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -656,7 +709,21 @@ TEST_F(CleanUpReplacementsTest, IfNDefWithNoDefine) {
"#ifndef X\n"
"int x;\n"
"#define Y 1\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
+ EXPECT_EQ(Expected, apply(Code, Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, FakeHeaderGuard) {
+ std::string Code = "// comment \n"
+ "#ifndef X\n"
+ "#define 1\n";
+ std::string Expected = "// comment \n"
+ "#include <vector>\n"
+ "#ifndef X\n"
+ "#define 1\n";
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -678,23 +745,34 @@ TEST_F(CleanUpReplacementsTest, HeaderGuardWithComment) {
"#include <vector>\n"
"int x;\n"
"#define Y 1\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
TEST_F(CleanUpReplacementsTest, EmptyCode) {
std::string Code = "";
std::string Expected = "#include <vector>\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
-// FIXME: although this case does not crash, the insertion is wrong. A '\n'
-// should be inserted between the two #includes.
TEST_F(CleanUpReplacementsTest, NoNewLineAtTheEndOfCode) {
std::string Code = "#include <map>";
- std::string Expected = "#include <map>#include <vector>\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ std::string Expected = "#include <map>\n#include <vector>\n";
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
+ EXPECT_EQ(Expected, apply(Code, Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, NoNewLineAtTheEndOfCodeMultipleInsertions) {
+ std::string Code = "#include <map>";
+ std::string Expected =
+ "#include <map>\n#include <string>\n#include <vector>\n";
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <string>"),
+ createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -703,8 +781,9 @@ TEST_F(CleanUpReplacementsTest, SkipExistingHeaders) {
"#include <vector>\n";
std::string Expected = "#include \"a.h\"\n"
"#include <vector>\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>"),
- createInsertion("#include \"a.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>"),
+ createInsertion("#include \"a.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -716,8 +795,171 @@ TEST_F(CleanUpReplacementsTest, AddIncludesWithDifferentForms) {
"#include \"vector\"\n"
"#include <vector>\n"
"#include <a.h>\n";
- tooling::Replacements Replaces = {createInsertion("#include \"vector\""),
- createInsertion("#include <a.h>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"vector\""),
+ createInsertion("#include <a.h>")});
+ EXPECT_EQ(Expected, apply(Code, Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, SimpleDeleteIncludes) {
+ std::string Code = "#include \"abc.h\"\n"
+ "#include \"xyz.h\" // comment\n"
+ "#include \"xyz\"\n"
+ "int x;\n";
+ std::string Expected = "#include \"xyz\"\n"
+ "int x;\n";
+ tooling::Replacements Replaces =
+ toReplacements({createDeletion("abc.h"), createDeletion("xyz.h")});
+ EXPECT_EQ(Expected, apply(Code, Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, DeleteAllCode) {
+ std::string Code = "#include \"xyz.h\"\n"
+ "#include <xyz.h>";
+ std::string Expected = "";
+ tooling::Replacements Replaces = toReplacements({createDeletion("xyz.h")});
+ EXPECT_EQ(Expected, apply(Code, Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, DeleteAllIncludesWithSameNameIfNoType) {
+ std::string Code = "#include \"xyz.h\"\n"
+ "#include \"xyz\"\n"
+ "#include <xyz.h>\n";
+ std::string Expected = "#include \"xyz\"\n";
+ tooling::Replacements Replaces = toReplacements({createDeletion("xyz.h")});
+ EXPECT_EQ(Expected, apply(Code, Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, OnlyDeleteHeaderWithType) {
+ std::string Code = "#include \"xyz.h\"\n"
+ "#include \"xyz\"\n"
+ "#include <xyz.h>";
+ std::string Expected = "#include \"xyz.h\"\n"
+ "#include \"xyz\"\n";
+ tooling::Replacements Replaces = toReplacements({createDeletion("<xyz.h>")});
+ EXPECT_EQ(Expected, apply(Code, Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, InsertionAndDeleteHeader) {
+ std::string Code = "#include \"a.h\"\n"
+ "\n"
+ "#include <vector>\n";
+ std::string Expected = "#include \"a.h\"\n"
+ "\n"
+ "#include <map>\n";
+ tooling::Replacements Replaces = toReplacements(
+ {createDeletion("<vector>"), createInsertion("#include <map>")});
+ EXPECT_EQ(Expected, apply(Code, Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, NoInsertionAfterCode) {
+ std::string Code = "#include \"a.h\"\n"
+ "void f() {}\n"
+ "#include \"b.h\"\n";
+ std::string Expected = "#include \"a.h\"\n"
+ "#include \"c.h\"\n"
+ "void f() {}\n"
+ "#include \"b.h\"\n";
+ tooling::Replacements Replaces = toReplacements(
+ {createInsertion("#include \"c.h\"")});
+ EXPECT_EQ(Expected, apply(Code, Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, NoInsertionInStringLiteral) {
+ std::string Code = "#include \"a.h\"\n"
+ "const char[] = R\"(\n"
+ "#include \"b.h\"\n"
+ ")\";\n";
+ std::string Expected = "#include \"a.h\"\n"
+ "#include \"c.h\"\n"
+ "const char[] = R\"(\n"
+ "#include \"b.h\"\n"
+ ")\";\n";
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"c.h\"")});
+ EXPECT_EQ(Expected, apply(Code, Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, NoInsertionAfterOtherDirective) {
+ std::string Code = "#include \"a.h\"\n"
+ "#ifdef X\n"
+ "#include \"b.h\"\n"
+ "#endif\n";
+ std::string Expected = "#include \"a.h\"\n"
+ "#include \"c.h\"\n"
+ "#ifdef X\n"
+ "#include \"b.h\"\n"
+ "#endif\n";
+ tooling::Replacements Replaces = toReplacements(
+ {createInsertion("#include \"c.h\"")});
+ EXPECT_EQ(Expected, apply(Code, Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, CanInsertAfterLongSystemInclude) {
+ std::string Code = "#include \"a.h\"\n"
+ "// comment\n\n"
+ "#include <a/b/c/d/e.h>\n";
+ std::string Expected = "#include \"a.h\"\n"
+ "// comment\n\n"
+ "#include <a/b/c/d/e.h>\n"
+ "#include <x.h>\n";
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <x.h>")});
+ EXPECT_EQ(Expected, apply(Code, Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, CanInsertAfterComment) {
+ std::string Code = "#include \"a.h\"\n"
+ "// Comment\n"
+ "\n"
+ "/* Comment */\n"
+ "// Comment\n"
+ "\n"
+ "#include \"b.h\"\n";
+ std::string Expected = "#include \"a.h\"\n"
+ "// Comment\n"
+ "\n"
+ "/* Comment */\n"
+ "// Comment\n"
+ "\n"
+ "#include \"b.h\"\n"
+ "#include \"c.h\"\n";
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"c.h\"")});
+ EXPECT_EQ(Expected, apply(Code, Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, LongCommentsInTheBeginningOfFile) {
+ std::string Code = "// Loooooooooooooooooooooooooong comment\n"
+ "// Loooooooooooooooooooooooooong comment\n"
+ "// Loooooooooooooooooooooooooong comment\n"
+ "#include <string>\n"
+ "#include <vector>\n"
+ "\n"
+ "#include \"a.h\"\n"
+ "#include \"b.h\"\n";
+ std::string Expected = "// Loooooooooooooooooooooooooong comment\n"
+ "// Loooooooooooooooooooooooooong comment\n"
+ "// Loooooooooooooooooooooooooong comment\n"
+ "#include <string>\n"
+ "#include <vector>\n"
+ "\n"
+ "#include \"a.h\"\n"
+ "#include \"b.h\"\n"
+ "#include \"third.h\"\n";
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"third.h\"")});
+ Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
+ EXPECT_EQ(Expected, apply(Code, Replaces));
+}
+
+TEST_F(CleanUpReplacementsTest, CanDeleteAfterCode) {
+ std::string Code = "#include \"a.h\"\n"
+ "void f() {}\n"
+ "#include \"b.h\"\n";
+ std::string Expected = "#include \"a.h\"\n"
+ "void f() {}\n";
+ tooling::Replacements Replaces = toReplacements({createDeletion("\"b.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 8d46ba6efcfe..6f9df680eef5 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -9,7 +9,7 @@
#include "clang/Format/Format.h"
-#include "../Tooling/RewriterTestContext.h"
+#include "../Tooling/ReplacementTest.h"
#include "FormatTestUtils.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
@@ -19,6 +19,9 @@
#define DEBUG_TYPE "format-test"
+using clang::tooling::ReplacementTest;
+using clang::tooling::toReplacements;
+
namespace clang {
namespace format {
namespace {
@@ -273,6 +276,30 @@ TEST_F(FormatTest, RemovesEmptyLines) {
"int i;\n"
"\n"
"} // namespace"));
+
+ FormatStyle Style = getLLVMStyle();
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
+ Style.MaxEmptyLinesToKeep = 2;
+ Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+ Style.BraceWrapping.AfterClass = true;
+ Style.BraceWrapping.AfterFunction = true;
+ Style.KeepEmptyLinesAtTheStartOfBlocks = false;
+
+ EXPECT_EQ("class Foo\n"
+ "{\n"
+ " Foo() {}\n"
+ "\n"
+ " void funk() {}\n"
+ "};",
+ format("class Foo\n"
+ "{\n"
+ " Foo()\n"
+ " {\n"
+ " }\n"
+ "\n"
+ " void funk() {}\n"
+ "};",
+ Style));
}
TEST_F(FormatTest, RecognizesBinaryOperatorKeywords) {
@@ -1110,6 +1137,12 @@ TEST_F(FormatTest, KeepsParameterWithTrailingCommentsOnTheirOwnLine) {
format("SomeFunction(a, // comment\n"
" b,\n"
" c); // comment"));
+ EXPECT_EQ("aaaaaaaaaa(aaaa(aaaa,\n"
+ " aaaa), //\n"
+ " aaaa, bbbbb);",
+ format("aaaaaaaaaa(aaaa(aaaa,\n"
+ "aaaa), //\n"
+ "aaaa, bbbbb);"));
}
TEST_F(FormatTest, RemovesTrailingWhitespaceOfComments) {
@@ -1934,6 +1967,10 @@ TEST_F(FormatTest, UnderstandsAccessSpecifiers) {
verifyFormat("{\n"
" signals.set(); // This needs indentation.\n"
"}");
+ verifyFormat("void f() {\n"
+ "label:\n"
+ " signals.baz();\n"
+ "}");
}
TEST_F(FormatTest, SeparatesLogicalBlocks) {
@@ -2456,42 +2493,6 @@ TEST_F(FormatTest, FormatTryCatchBraceStyles) {
Style);
}
-TEST_F(FormatTest, FormatObjCTryCatch) {
- verifyFormat("@try {\n"
- " f();\n"
- "} @catch (NSException e) {\n"
- " @throw;\n"
- "} @finally {\n"
- " exit(42);\n"
- "}");
- verifyFormat("DEBUG({\n"
- " @try {\n"
- " } @finally {\n"
- " }\n"
- "});\n");
-}
-
-TEST_F(FormatTest, FormatObjCAutoreleasepool) {
- FormatStyle Style = getLLVMStyle();
- verifyFormat("@autoreleasepool {\n"
- " f();\n"
- "}\n"
- "@autoreleasepool {\n"
- " f();\n"
- "}\n",
- Style);
- Style.BreakBeforeBraces = FormatStyle::BS_Allman;
- verifyFormat("@autoreleasepool\n"
- "{\n"
- " f();\n"
- "}\n"
- "@autoreleasepool\n"
- "{\n"
- " f();\n"
- "}\n",
- Style);
-}
-
TEST_F(FormatTest, StaticInitializers) {
verifyFormat("static SomeClass SC = {1, 'a'};");
@@ -4540,12 +4541,13 @@ TEST_F(FormatTest, ParenthesesAndOperandAlignment) {
TEST_F(FormatTest, BreaksConditionalExpressions) {
verifyFormat(
- "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ "aaaa(aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
verifyFormat(
- "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ "aaaa(aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
verifyFormat(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaa ? aaaa(aaaaaa)\n"
" : aaaaaaaaaaaaa);");
@@ -4595,11 +4597,12 @@ TEST_F(FormatTest, BreaksConditionalExpressions) {
" ? aaaa\n"
" : bbbb;");
verifyFormat("unsigned Indent =\n"
- " format(TheLine.First, IndentForLevel[TheLine.Level] >= 0\n"
- " ? IndentForLevel[TheLine.Level]\n"
- " : TheLine * 2,\n"
+ " format(TheLine.First,\n"
+ " IndentForLevel[TheLine.Level] >= 0\n"
+ " ? IndentForLevel[TheLine.Level]\n"
+ " : TheLine * 2,\n"
" TheLine.InPPDirective, PreviousEndOfLineColumn);",
- getLLVMStyleWithColumns(70));
+ getLLVMStyleWithColumns(60));
verifyFormat("bool aaaaaa = aaaaaaaaaaaaa //\n"
" ? aaaaaaaaaaaaaaa\n"
" : bbbbbbbbbbbbbbb //\n"
@@ -4674,13 +4677,14 @@ TEST_F(FormatTest, BreaksConditionalExpressionsAfterOperator) {
Style.BreakBeforeTernaryOperators = false;
Style.ColumnLimit = 70;
verifyFormat(
- "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaa ?\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ "aaaa(aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
Style);
verifyFormat(
- "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ "aaaa(aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
Style);
verifyFormat(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaa ? aaaa(aaaaaa) :\n"
@@ -4736,13 +4740,13 @@ TEST_F(FormatTest, BreaksConditionalExpressionsAfterOperator) {
" b :\n"
" c);",
Style);
- verifyFormat(
- "unsigned Indent =\n"
- " format(TheLine.First, IndentForLevel[TheLine.Level] >= 0 ?\n"
- " IndentForLevel[TheLine.Level] :\n"
- " TheLine * 2,\n"
- " TheLine.InPPDirective, PreviousEndOfLineColumn);",
- Style);
+ verifyFormat("unsigned Indent =\n"
+ " format(TheLine.First,\n"
+ " IndentForLevel[TheLine.Level] >= 0 ?\n"
+ " IndentForLevel[TheLine.Level] :\n"
+ " TheLine * 2,\n"
+ " TheLine.InPPDirective, PreviousEndOfLineColumn);",
+ Style);
verifyFormat("bool aaaaaa = aaaaaaaaaaaaa ? //\n"
" aaaaaaaaaaaaaaa :\n"
" bbbbbbbbbbbbbbb ? //\n"
@@ -4795,6 +4799,8 @@ TEST_F(FormatTest, DeclarationsOfMultipleVariables) {
verifyFormat("aaaaaaaaa *a = aaaaaaaaaaaaaaaaaaa, *b = bbbbbbbbbbbbbbbbbbb,\n"
" *b = bbbbbbbbbbbbbbbbbbb, *d = ddddddddddddddddddd;",
Style);
+ verifyFormat("vector<int*> a, b;", Style);
+ verifyFormat("for (int *p, *q; p != q; p = p->next) {\n}", Style);
}
TEST_F(FormatTest, ConditionalExpressionsInBrackets) {
@@ -5086,6 +5092,9 @@ TEST_F(FormatTest, AlignsPipes) {
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" << aaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaaaaa << aaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
+ verifyFormat(
"llvm::outs() << \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n"
" \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"\n"
" << \"ccccccccccccccccccccccccccccccccccccccccccccccccc\";");
@@ -5103,29 +5112,6 @@ TEST_F(FormatTest, AlignsPipes) {
"llvm::errs() << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
- verifyFormat("return out << \"somepacket = {\\n\"\n"
- " << \" aaaaaa = \" << pkt.aaaaaa << \"\\n\"\n"
- " << \" bbbb = \" << pkt.bbbb << \"\\n\"\n"
- " << \" cccccc = \" << pkt.cccccc << \"\\n\"\n"
- " << \" ddd = [\" << pkt.ddd << \"]\\n\"\n"
- " << \"}\";");
-
- verifyFormat("llvm::outs() << \"aaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaa\n"
- " << \"aaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaa\n"
- " << \"aaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaa;");
- verifyFormat(
- "llvm::outs() << \"aaaaaaaaaaaaaaaaa = \" << aaaaaaaaaaaaaaaaa\n"
- " << \"bbbbbbbbbbbbbbbbb = \" << bbbbbbbbbbbbbbbbb\n"
- " << \"ccccccccccccccccc = \" << ccccccccccccccccc\n"
- " << \"ddddddddddddddddd = \" << ddddddddddddddddd\n"
- " << \"eeeeeeeeeeeeeeeee = \" << eeeeeeeeeeeeeeeee;");
- verifyFormat("llvm::outs() << aaaaaaaaaaaaaaaaaaaaaaaa << \"=\"\n"
- " << bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;");
- verifyFormat(
- "void f() {\n"
- " llvm::outs() << \"aaaaaaaaaaaaaaaaaaaa: \"\n"
- " << aaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaa);\n"
- "}");
verifyFormat("llvm::outs() << \"aaaaaaaaaaaaaaaa: \"\n"
" << aaaaaaaa.aaaaaaaaaaaa(aaa)->aaaaaaaaaaaaaa();");
verifyFormat("llvm::errs() << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
@@ -5136,22 +5122,6 @@ TEST_F(FormatTest, AlignsPipes) {
" bbb)\n"
" << a << b;");
- // Breaking before the first "<<" is generally not desirable.
- verifyFormat(
- "llvm::errs()\n"
- " << \"aaaaaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " << \"aaaaaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " << \"aaaaaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " << \"aaaaaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
- getLLVMStyleWithColumns(70));
- verifyFormat("llvm::errs() << \"aaaaaaaaaaaaaaaaaaa: \"\n"
- " << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " << \"aaaaaaaaaaaaaaaaaaa: \"\n"
- " << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " << \"aaaaaaaaaaaaaaaaaaa: \"\n"
- " << aaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
- getLLVMStyleWithColumns(70));
-
// But sometimes, breaking before the first "<<" is desirable.
verifyFormat("Diag(aaaaaaaaaaaaaaaaaaaa, aaaaaaaa)\n"
" << aaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa);");
@@ -5197,6 +5167,65 @@ TEST_F(FormatTest, AlignsPipes) {
verifyFormat("llvm::errs() << \"\\n\" << bbbbbbbbbbbbbbbbbbbbbb << \"\\n\";");
}
+TEST_F(FormatTest, KeepStringLabelValuePairsOnALine) {
+ verifyFormat("return out << \"somepacket = {\\n\"\n"
+ " << \" aaaaaa = \" << pkt.aaaaaa << \"\\n\"\n"
+ " << \" bbbb = \" << pkt.bbbb << \"\\n\"\n"
+ " << \" cccccc = \" << pkt.cccccc << \"\\n\"\n"
+ " << \" ddd = [\" << pkt.ddd << \"]\\n\"\n"
+ " << \"}\";");
+
+ verifyFormat("llvm::outs() << \"aaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaa\n"
+ " << \"aaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaa\n"
+ " << \"aaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaa;");
+ verifyFormat(
+ "llvm::outs() << \"aaaaaaaaaaaaaaaaa = \" << aaaaaaaaaaaaaaaaa\n"
+ " << \"bbbbbbbbbbbbbbbbb = \" << bbbbbbbbbbbbbbbbb\n"
+ " << \"ccccccccccccccccc = \" << ccccccccccccccccc\n"
+ " << \"ddddddddddddddddd = \" << ddddddddddddddddd\n"
+ " << \"eeeeeeeeeeeeeeeee = \" << eeeeeeeeeeeeeeeee;");
+ verifyFormat("llvm::outs() << aaaaaaaaaaaaaaaaaaaaaaaa << \"=\"\n"
+ " << bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;");
+ verifyFormat(
+ "void f() {\n"
+ " llvm::outs() << \"aaaaaaaaaaaaaaaaaaaa: \"\n"
+ " << aaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaa);\n"
+ "}");
+
+ // Breaking before the first "<<" is generally not desirable.
+ verifyFormat(
+ "llvm::errs()\n"
+ " << \"aaaaaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << \"aaaaaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << \"aaaaaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << \"aaaaaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
+ getLLVMStyleWithColumns(70));
+ verifyFormat("llvm::errs() << \"aaaaaaaaaaaaaaaaaaa: \"\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << \"aaaaaaaaaaaaaaaaaaa: \"\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << \"aaaaaaaaaaaaaaaaaaa: \"\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
+ getLLVMStyleWithColumns(70));
+
+ verifyFormat("string v = \"aaaaaaaaaaaaaaaa: \" + aaaaaaaaaaaaaaaa +\n"
+ " \"aaaaaaaaaaaaaaaa: \" + aaaaaaaaaaaaaaaa +\n"
+ " \"aaaaaaaaaaaaaaaa: \" + aaaaaaaaaaaaaaaa;");
+ verifyFormat("string v = StrCat(\"aaaaaaaaaaaaaaaa: \", aaaaaaaaaaaaaaaa,\n"
+ " \"aaaaaaaaaaaaaaaa: \", aaaaaaaaaaaaaaaa,\n"
+ " \"aaaaaaaaaaaaaaaa: \", aaaaaaaaaaaaaaaa);");
+ verifyFormat("string v = \"aaaaaaaaaaaaaaaa: \" +\n"
+ " (aaaa + aaaa);",
+ getLLVMStyleWithColumns(40));
+ verifyFormat("string v = StrCat(\"aaaaaaaaaaaa: \" +\n"
+ " (aaaaaaa + aaaaa));",
+ getLLVMStyleWithColumns(40));
+ verifyFormat(
+ "string v = StrCat(\"aaaaaaaaaaaaaaaaaaaaaaaaaaa: \",\n"
+ " SomeFunction(aaaaaaaaaaaa, aaaaaaaa.aaaaaaa),\n"
+ " bbbbbbbbbbbbbbbbbbbbbbb);");
+}
+
TEST_F(FormatTest, UnderstandsEquals) {
verifyFormat(
"aaaaaaaaaaaaaaaaa =\n"
@@ -5492,6 +5521,18 @@ TEST_F(FormatTest, UnderstandsTemplateParameters) {
verifyFormat("< < < < < < < < < < < < < < < < < < < < < < < < < < < < < <");
}
+TEST_F(FormatTest, BitshiftOperatorWidth) {
+ EXPECT_EQ("int a = 1 << 2; /* foo\n"
+ " bar */",
+ format("int a=1<<2; /* foo\n"
+ " bar */"));
+
+ EXPECT_EQ("int b = 256 >> 1; /* foo\n"
+ " bar */",
+ format("int b =256>>1 ; /* foo\n"
+ " bar */"));
+}
+
TEST_F(FormatTest, UnderstandsBinaryOperators) {
verifyFormat("COMPARE(a, ==, b);");
verifyFormat("auto s = sizeof...(Ts) - 1;");
@@ -5628,6 +5669,9 @@ TEST_F(FormatTest, UnderstandsFunctionRefQualification) {
verifyFormat("SomeType MemberFunction(const Deleted &) && final {}");
verifyFormat("SomeType MemberFunction(const Deleted &) && override {}");
verifyFormat("SomeType MemberFunction(const Deleted &) const &;");
+ verifyFormat("template <typename T>\n"
+ "void F(T) && = delete;",
+ getGoogleStyle());
FormatStyle AlignLeft = getLLVMStyle();
AlignLeft.PointerAlignment = FormatStyle::PAS_Left;
@@ -5780,7 +5824,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
FormatStyle Left = getLLVMStyle();
Left.PointerAlignment = FormatStyle::PAS_Left;
verifyFormat("x = *a(x) = *a(y);", Left);
- verifyFormat("for (;; * = b) {\n}", Left);
+ verifyFormat("for (;; *a = b) {\n}", Left);
verifyFormat("return *this += 1;", Left);
verifyIndependentOfContext("a = *(x + y);");
@@ -5845,11 +5889,12 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyFormat("foo<b & 1>();");
verifyFormat("decltype(*::std::declval<const T &>()) void F();");
verifyFormat(
- "template <class T, class = typename std::enable_if<\n"
- " std::is_integral<T>::value &&\n"
- " (sizeof(T) > 1 || sizeof(T) < 8)>::type>\n"
+ "template <class T,\n"
+ " class = typename std::enable_if<\n"
+ " std::is_integral<T>::value &&\n"
+ " (sizeof(T) > 1 || sizeof(T) < 8)>::type>\n"
"void F();",
- getLLVMStyleWithColumns(76));
+ getLLVMStyleWithColumns(70));
verifyFormat(
"template <class T,\n"
" class = typename ::std::enable_if<\n"
@@ -5861,6 +5906,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyIndependentOfContext("MACRO(auto *a);");
verifyIndependentOfContext("MACRO(const A *a);");
verifyIndependentOfContext("MACRO('0' <= c && c <= '9');");
+ verifyFormat("void f() { f(float{1}, a * a); }");
// FIXME: Is there a way to make this work?
// verifyIndependentOfContext("MACRO(A *a);");
@@ -6481,6 +6527,19 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
"};");
verifyFormat("#define A {a, a},");
+ // Cases where distinguising braced lists and blocks is hard.
+ verifyFormat("vector<int> v{12} GUARDED_BY(mutex);");
+ verifyFormat("void f() {\n"
+ " return; // comment\n"
+ "}\n"
+ "SomeType t;");
+ verifyFormat("void f() {\n"
+ " if (a) {\n"
+ " f();\n"
+ " }\n"
+ "}\n"
+ "SomeType t;");
+
// In combination with BinPackArguments = false.
FormatStyle NoBinPacking = getLLVMStyle();
NoBinPacking.BinPackArguments = false;
@@ -6595,7 +6654,7 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
"std::this_thread::sleep_for(\n"
" std::chrono::nanoseconds{ std::chrono::seconds{ 1 } } / 5);",
ExtraSpaces);
- verifyFormat("std::vector<MyValues> aaaaaaaaaaaaaaaaaaa{\n"
+ verifyFormat("std::vector<MyValues> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{\n"
" aaaaaaa,\n"
" aaaaaaaaaa,\n"
" aaaaa,\n"
@@ -6733,6 +6792,26 @@ TEST_F(FormatTest, FormatsBracedListsInColumnLayout) {
" 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
" 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
" 1, 22, 333, 4444, 55555, 666666, 7777777});");
+
+ // Allow "single-column" layout even if that violates the column limit. There
+ // isn't going to be a better way.
+ verifyFormat("std::vector<int> a = {\n"
+ " aaaaaaaa,\n"
+ " aaaaaaaa,\n"
+ " aaaaaaaa,\n"
+ " aaaaaaaa,\n"
+ " aaaaaaaaaa,\n"
+ " aaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa};",
+ getLLVMStyleWithColumns(30));
+ verifyFormat("vector<int> aaaa = {\n"
+ " aaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaa.aaaaaaa,\n"
+ " aaaaaa.aaaaaaa,\n"
+ " aaaaaa.aaaaaaa,\n"
+ " aaaaaa.aaaaaaa,\n"
+ "};");
}
TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {
@@ -7170,6 +7249,30 @@ TEST_F(FormatTest, SpecialTokensAtEndOfLine) {
verifyFormat("operator");
}
+TEST_F(FormatTest, SkipsDeeplyNestedLines) {
+ // This code would be painfully slow to format if we didn't skip it.
+ std::string Code("A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(\n" // 20x
+ "A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(\n"
+ "A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(\n"
+ "A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(\n"
+ "A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(\n"
+ "A(1, 1)\n"
+ ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n" // 10x
+ ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+ ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+ ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+ ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+ ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+ ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+ ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+ ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+ ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1);\n");
+ // Deeply nested part is untouched, rest is formatted.
+ EXPECT_EQ(std::string("int i;\n") + Code + "int j;\n",
+ format(std::string("int i;\n") + Code + "int j;\n",
+ getLLVMStyle(), IC_ExpectIncomplete));
+}
+
//===----------------------------------------------------------------------===//
// Objective-C tests.
//===----------------------------------------------------------------------===//
@@ -7240,684 +7343,6 @@ TEST_F(FormatTest, FormatForObjectiveCMethodDecls) {
verifyGoogleFormat("- foo:(int)foo;");
}
-TEST_F(FormatTest, FormatObjCInterface) {
- verifyFormat("@interface Foo : NSObject <NSSomeDelegate> {\n"
- "@public\n"
- " int field1;\n"
- "@protected\n"
- " int field2;\n"
- "@private\n"
- " int field3;\n"
- "@package\n"
- " int field4;\n"
- "}\n"
- "+ (id)init;\n"
- "@end");
-
- verifyGoogleFormat("@interface Foo : NSObject<NSSomeDelegate> {\n"
- " @public\n"
- " int field1;\n"
- " @protected\n"
- " int field2;\n"
- " @private\n"
- " int field3;\n"
- " @package\n"
- " int field4;\n"
- "}\n"
- "+ (id)init;\n"
- "@end");
-
- verifyFormat("@interface /* wait for it */ Foo\n"
- "+ (id)init;\n"
- "// Look, a comment!\n"
- "- (int)answerWith:(int)i;\n"
- "@end");
-
- verifyFormat("@interface Foo\n"
- "@end\n"
- "@interface Bar\n"
- "@end");
-
- verifyFormat("@interface Foo : Bar\n"
- "+ (id)init;\n"
- "@end");
-
- verifyFormat("@interface Foo : /**/ Bar /**/ <Baz, /**/ Quux>\n"
- "+ (id)init;\n"
- "@end");
-
- verifyGoogleFormat("@interface Foo : Bar<Baz, Quux>\n"
- "+ (id)init;\n"
- "@end");
-
- verifyFormat("@interface Foo (HackStuff)\n"
- "+ (id)init;\n"
- "@end");
-
- verifyFormat("@interface Foo ()\n"
- "+ (id)init;\n"
- "@end");
-
- verifyFormat("@interface Foo (HackStuff) <MyProtocol>\n"
- "+ (id)init;\n"
- "@end");
-
- verifyGoogleFormat("@interface Foo (HackStuff)<MyProtocol>\n"
- "+ (id)init;\n"
- "@end");
-
- verifyFormat("@interface Foo {\n"
- " int _i;\n"
- "}\n"
- "+ (id)init;\n"
- "@end");
-
- verifyFormat("@interface Foo : Bar {\n"
- " int _i;\n"
- "}\n"
- "+ (id)init;\n"
- "@end");
-
- verifyFormat("@interface Foo : Bar <Baz, Quux> {\n"
- " int _i;\n"
- "}\n"
- "+ (id)init;\n"
- "@end");
-
- verifyFormat("@interface Foo (HackStuff) {\n"
- " int _i;\n"
- "}\n"
- "+ (id)init;\n"
- "@end");
-
- verifyFormat("@interface Foo () {\n"
- " int _i;\n"
- "}\n"
- "+ (id)init;\n"
- "@end");
-
- verifyFormat("@interface Foo (HackStuff) <MyProtocol> {\n"
- " int _i;\n"
- "}\n"
- "+ (id)init;\n"
- "@end");
-
- FormatStyle OnePerLine = getGoogleStyle();
- OnePerLine.BinPackParameters = false;
- verifyFormat("@interface aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ()<\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> {\n"
- "}",
- OnePerLine);
-}
-
-TEST_F(FormatTest, FormatObjCImplementation) {
- verifyFormat("@implementation Foo : NSObject {\n"
- "@public\n"
- " int field1;\n"
- "@protected\n"
- " int field2;\n"
- "@private\n"
- " int field3;\n"
- "@package\n"
- " int field4;\n"
- "}\n"
- "+ (id)init {\n}\n"
- "@end");
-
- verifyGoogleFormat("@implementation Foo : NSObject {\n"
- " @public\n"
- " int field1;\n"
- " @protected\n"
- " int field2;\n"
- " @private\n"
- " int field3;\n"
- " @package\n"
- " int field4;\n"
- "}\n"
- "+ (id)init {\n}\n"
- "@end");
-
- verifyFormat("@implementation Foo\n"
- "+ (id)init {\n"
- " if (true)\n"
- " return nil;\n"
- "}\n"
- "// Look, a comment!\n"
- "- (int)answerWith:(int)i {\n"
- " return i;\n"
- "}\n"
- "+ (int)answerWith:(int)i {\n"
- " return i;\n"
- "}\n"
- "@end");
-
- verifyFormat("@implementation Foo\n"
- "@end\n"
- "@implementation Bar\n"
- "@end");
-
- EXPECT_EQ("@implementation Foo : Bar\n"
- "+ (id)init {\n}\n"
- "- (void)foo {\n}\n"
- "@end",
- format("@implementation Foo : Bar\n"
- "+(id)init{}\n"
- "-(void)foo{}\n"
- "@end"));
-
- verifyFormat("@implementation Foo {\n"
- " int _i;\n"
- "}\n"
- "+ (id)init {\n}\n"
- "@end");
-
- verifyFormat("@implementation Foo : Bar {\n"
- " int _i;\n"
- "}\n"
- "+ (id)init {\n}\n"
- "@end");
-
- verifyFormat("@implementation Foo (HackStuff)\n"
- "+ (id)init {\n}\n"
- "@end");
- verifyFormat("@implementation ObjcClass\n"
- "- (void)method;\n"
- "{}\n"
- "@end");
-}
-
-TEST_F(FormatTest, FormatObjCProtocol) {
- verifyFormat("@protocol Foo\n"
- "@property(weak) id delegate;\n"
- "- (NSUInteger)numberOfThings;\n"
- "@end");
-
- verifyFormat("@protocol MyProtocol <NSObject>\n"
- "- (NSUInteger)numberOfThings;\n"
- "@end");
-
- verifyGoogleFormat("@protocol MyProtocol<NSObject>\n"
- "- (NSUInteger)numberOfThings;\n"
- "@end");
-
- verifyFormat("@protocol Foo;\n"
- "@protocol Bar;\n");
-
- verifyFormat("@protocol Foo\n"
- "@end\n"
- "@protocol Bar\n"
- "@end");
-
- verifyFormat("@protocol myProtocol\n"
- "- (void)mandatoryWithInt:(int)i;\n"
- "@optional\n"
- "- (void)optional;\n"
- "@required\n"
- "- (void)required;\n"
- "@optional\n"
- "@property(assign) int madProp;\n"
- "@end\n");
-
- verifyFormat("@property(nonatomic, assign, readonly)\n"
- " int *looooooooooooooooooooooooooooongNumber;\n"
- "@property(nonatomic, assign, readonly)\n"
- " NSString *looooooooooooooooooooooooooooongName;");
-
- verifyFormat("@implementation PR18406\n"
- "}\n"
- "@end");
-}
-
-TEST_F(FormatTest, FormatObjCMethodDeclarations) {
- verifyFormat("- (void)doSomethingWith:(GTMFoo *)theFoo\n"
- " rect:(NSRect)theRect\n"
- " interval:(float)theInterval {\n"
- "}");
- verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n"
- " longKeyword:(NSRect)theRect\n"
- " longerKeyword:(float)theInterval\n"
- " error:(NSError **)theError {\n"
- "}");
- verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n"
- " longKeyword:(NSRect)theRect\n"
- " evenLongerKeyword:(float)theInterval\n"
- " error:(NSError **)theError {\n"
- "}");
- verifyFormat("- (instancetype)initXxxxxx:(id<x>)x\n"
- " y:(id<yyyyyyyyyyyyyyyyyyyy>)y\n"
- " NS_DESIGNATED_INITIALIZER;",
- getLLVMStyleWithColumns(60));
-
- // Continuation indent width should win over aligning colons if the function
- // name is long.
- FormatStyle continuationStyle = getGoogleStyle();
- continuationStyle.ColumnLimit = 40;
- continuationStyle.IndentWrappedFunctionNames = true;
- verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n"
- " dontAlignNamef:(NSRect)theRect {\n"
- "}",
- continuationStyle);
-
- // Make sure we don't break aligning for short parameter names.
- verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n"
- " aShortf:(NSRect)theRect {\n"
- "}",
- continuationStyle);
-}
-
-TEST_F(FormatTest, FormatObjCMethodExpr) {
- verifyFormat("[foo bar:baz];");
- verifyFormat("return [foo bar:baz];");
- verifyFormat("return (a)[foo bar:baz];");
- verifyFormat("f([foo bar:baz]);");
- verifyFormat("f(2, [foo bar:baz]);");
- verifyFormat("f(2, a ? b : c);");
- verifyFormat("[[self initWithInt:4] bar:[baz quux:arrrr]];");
-
- // Unary operators.
- verifyFormat("int a = +[foo bar:baz];");
- verifyFormat("int a = -[foo bar:baz];");
- verifyFormat("int a = ![foo bar:baz];");
- verifyFormat("int a = ~[foo bar:baz];");
- verifyFormat("int a = ++[foo bar:baz];");
- verifyFormat("int a = --[foo bar:baz];");
- verifyFormat("int a = sizeof [foo bar:baz];");
- verifyFormat("int a = alignof [foo bar:baz];", getGoogleStyle());
- verifyFormat("int a = &[foo bar:baz];");
- verifyFormat("int a = *[foo bar:baz];");
- // FIXME: Make casts work, without breaking f()[4].
- // verifyFormat("int a = (int)[foo bar:baz];");
- // verifyFormat("return (int)[foo bar:baz];");
- // verifyFormat("(void)[foo bar:baz];");
- verifyFormat("return (MyType *)[self.tableView cellForRowAtIndexPath:cell];");
-
- // Binary operators.
- verifyFormat("[foo bar:baz], [foo bar:baz];");
- verifyFormat("[foo bar:baz] = [foo bar:baz];");
- verifyFormat("[foo bar:baz] *= [foo bar:baz];");
- verifyFormat("[foo bar:baz] /= [foo bar:baz];");
- verifyFormat("[foo bar:baz] %= [foo bar:baz];");
- verifyFormat("[foo bar:baz] += [foo bar:baz];");
- verifyFormat("[foo bar:baz] -= [foo bar:baz];");
- verifyFormat("[foo bar:baz] <<= [foo bar:baz];");
- verifyFormat("[foo bar:baz] >>= [foo bar:baz];");
- verifyFormat("[foo bar:baz] &= [foo bar:baz];");
- verifyFormat("[foo bar:baz] ^= [foo bar:baz];");
- verifyFormat("[foo bar:baz] |= [foo bar:baz];");
- verifyFormat("[foo bar:baz] ? [foo bar:baz] : [foo bar:baz];");
- verifyFormat("[foo bar:baz] || [foo bar:baz];");
- verifyFormat("[foo bar:baz] && [foo bar:baz];");
- verifyFormat("[foo bar:baz] | [foo bar:baz];");
- verifyFormat("[foo bar:baz] ^ [foo bar:baz];");
- verifyFormat("[foo bar:baz] & [foo bar:baz];");
- verifyFormat("[foo bar:baz] == [foo bar:baz];");
- verifyFormat("[foo bar:baz] != [foo bar:baz];");
- verifyFormat("[foo bar:baz] >= [foo bar:baz];");
- verifyFormat("[foo bar:baz] <= [foo bar:baz];");
- verifyFormat("[foo bar:baz] > [foo bar:baz];");
- verifyFormat("[foo bar:baz] < [foo bar:baz];");
- verifyFormat("[foo bar:baz] >> [foo bar:baz];");
- verifyFormat("[foo bar:baz] << [foo bar:baz];");
- verifyFormat("[foo bar:baz] - [foo bar:baz];");
- verifyFormat("[foo bar:baz] + [foo bar:baz];");
- verifyFormat("[foo bar:baz] * [foo bar:baz];");
- verifyFormat("[foo bar:baz] / [foo bar:baz];");
- verifyFormat("[foo bar:baz] % [foo bar:baz];");
- // Whew!
-
- verifyFormat("return in[42];");
- verifyFormat("for (auto v : in[1]) {\n}");
- verifyFormat("for (int i = 0; i < in[a]; ++i) {\n}");
- verifyFormat("for (int i = 0; in[a] < i; ++i) {\n}");
- verifyFormat("for (int i = 0; i < n; ++i, ++in[a]) {\n}");
- verifyFormat("for (int i = 0; i < n; ++i, in[a]++) {\n}");
- verifyFormat("for (int i = 0; i < f(in[a]); ++i, in[a]++) {\n}");
- verifyFormat("for (id foo in [self getStuffFor:bla]) {\n"
- "}");
- verifyFormat("[self aaaaa:MACRO(a, b:, c:)];");
- verifyFormat("[self aaaaa:(1 + 2) bbbbb:3];");
- verifyFormat("[self aaaaa:(Type)a bbbbb:3];");
-
- verifyFormat("[self stuffWithInt:(4 + 2) float:4.5];");
- verifyFormat("[self stuffWithInt:a ? b : c float:4.5];");
- verifyFormat("[self stuffWithInt:a ? [self foo:bar] : c];");
- verifyFormat("[self stuffWithInt:a ? (e ? f : g) : c];");
- verifyFormat("[cond ? obj1 : obj2 methodWithParam:param]");
- verifyFormat("[button setAction:@selector(zoomOut:)];");
- verifyFormat("[color getRed:&r green:&g blue:&b alpha:&a];");
-
- verifyFormat("arr[[self indexForFoo:a]];");
- verifyFormat("throw [self errorFor:a];");
- verifyFormat("@throw [self errorFor:a];");
-
- verifyFormat("[(id)foo bar:(id)baz quux:(id)snorf];");
- verifyFormat("[(id)foo bar:(id) ? baz : quux];");
- verifyFormat("4 > 4 ? (id)a : (id)baz;");
-
- // This tests that the formatter doesn't break after "backing" but before ":",
- // which would be at 80 columns.
- verifyFormat(
- "void f() {\n"
- " if ((self = [super initWithContentRect:contentRect\n"
- " styleMask:styleMask ?: otherMask\n"
- " backing:NSBackingStoreBuffered\n"
- " defer:YES]))");
-
- verifyFormat(
- "[foo checkThatBreakingAfterColonWorksOk:\n"
- " [bar ifItDoes:reduceOverallLineLengthLikeInThisCase]];");
-
- verifyFormat("[myObj short:arg1 // Force line break\n"
- " longKeyword:arg2 != nil ? arg2 : @\"longKeyword\"\n"
- " evenLongerKeyword:arg3 ?: @\"evenLongerKeyword\"\n"
- " error:arg4];");
- verifyFormat(
- "void f() {\n"
- " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n"
- " initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,\n"
- " pos.width(), pos.height())\n"
- " styleMask:NSBorderlessWindowMask\n"
- " backing:NSBackingStoreBuffered\n"
- " defer:NO]);\n"
- "}");
- verifyFormat(
- "void f() {\n"
- " popup_wdow_.reset([[RenderWidgetPopupWindow alloc]\n"
- " iniithContentRect:NSMakRet(origin_global.x, origin_global.y,\n"
- " pos.width(), pos.height())\n"
- " syeMask:NSBorderlessWindowMask\n"
- " bking:NSBackingStoreBuffered\n"
- " der:NO]);\n"
- "}",
- getLLVMStyleWithColumns(70));
- verifyFormat(
- "void f() {\n"
- " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n"
- " initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,\n"
- " pos.width(), pos.height())\n"
- " styleMask:NSBorderlessWindowMask\n"
- " backing:NSBackingStoreBuffered\n"
- " defer:NO]);\n"
- "}",
- getChromiumStyle(FormatStyle::LK_Cpp));
- verifyFormat("[contentsContainer replaceSubview:[subviews objectAtIndex:0]\n"
- " with:contentsNativeView];");
-
- verifyFormat(
- "[pboard addTypes:[NSArray arrayWithObject:kBookmarkButtonDragType]\n"
- " owner:nillllll];");
-
- verifyFormat(
- "[pboard setData:[NSData dataWithBytes:&button length:sizeof(button)]\n"
- " forType:kBookmarkButtonDragType];");
-
- verifyFormat("[defaultCenter addObserver:self\n"
- " selector:@selector(willEnterFullscreen)\n"
- " name:kWillEnterFullscreenNotification\n"
- " object:nil];");
- verifyFormat("[image_rep drawInRect:drawRect\n"
- " fromRect:NSZeroRect\n"
- " operation:NSCompositeCopy\n"
- " fraction:1.0\n"
- " respectFlipped:NO\n"
- " hints:nil];");
- verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];");
- verifyFormat("[aaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaa)\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];");
- verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaa[aaaaaaaaaaaaaaaaaaaaa]\n"
- " aaaaaaaaaaaaaaaaaaaaaa];");
- verifyFormat("[call aaaaaaaa.aaaaaa.aaaaaaaa.aaaaaaaa.aaaaaaaa.aaaaaaaa\n"
- " .aaaaaaaa];", // FIXME: Indentation seems off.
- getLLVMStyleWithColumns(60));
-
- verifyFormat(
- "scoped_nsobject<NSTextField> message(\n"
- " // The frame will be fixed up when |-setMessageText:| is called.\n"
- " [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]);");
- verifyFormat("[self aaaaaa:bbbbbbbbbbbbb\n"
- " aaaaaaaaaa:bbbbbbbbbbbbbbbbb\n"
- " aaaaa:bbbbbbbbbbb + bbbbbbbbbbbb\n"
- " aaaa:bbb];");
- verifyFormat("[self param:function( //\n"
- " parameter)]");
- verifyFormat(
- "[self aaaaaaaaaa:aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |\n"
- " aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |\n"
- " aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa];");
-
- // FIXME: This violates the column limit.
- verifyFormat(
- "[aaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " aaaaaaaaaaaaaaaaa:aaaaaaaa\n"
- " aaa:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];",
- getLLVMStyleWithColumns(60));
-
- // Variadic parameters.
- verifyFormat(
- "NSArray *myStrings = [NSArray stringarray:@\"a\", @\"b\", nil];");
- verifyFormat(
- "[self aaaaaaaaaaaaa:aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa];");
- verifyFormat("[self // break\n"
- " a:a\n"
- " aaa:aaa];");
- verifyFormat("bool a = ([aaaaaaaa aaaaa] == aaaaaaaaaaaaaaaaa ||\n"
- " [aaaaaaaa aaaaa] == aaaaaaaaaaaaaaaaaaaa);");
-}
-
-TEST_F(FormatTest, ObjCAt) {
- verifyFormat("@autoreleasepool");
- verifyFormat("@catch");
- verifyFormat("@class");
- verifyFormat("@compatibility_alias");
- verifyFormat("@defs");
- verifyFormat("@dynamic");
- verifyFormat("@encode");
- verifyFormat("@end");
- verifyFormat("@finally");
- verifyFormat("@implementation");
- verifyFormat("@import");
- verifyFormat("@interface");
- verifyFormat("@optional");
- verifyFormat("@package");
- verifyFormat("@private");
- verifyFormat("@property");
- verifyFormat("@protected");
- verifyFormat("@protocol");
- verifyFormat("@public");
- verifyFormat("@required");
- verifyFormat("@selector");
- verifyFormat("@synchronized");
- verifyFormat("@synthesize");
- verifyFormat("@throw");
- verifyFormat("@try");
-
- EXPECT_EQ("@interface", format("@ interface"));
-
- // The precise formatting of this doesn't matter, nobody writes code like
- // this.
- verifyFormat("@ /*foo*/ interface");
-}
-
-TEST_F(FormatTest, ObjCSnippets) {
- verifyFormat("@autoreleasepool {\n"
- " foo();\n"
- "}");
- verifyFormat("@class Foo, Bar;");
- verifyFormat("@compatibility_alias AliasName ExistingClass;");
- verifyFormat("@dynamic textColor;");
- verifyFormat("char *buf1 = @encode(int *);");
- verifyFormat("char *buf1 = @encode(typeof(4 * 5));");
- verifyFormat("char *buf1 = @encode(int **);");
- verifyFormat("Protocol *proto = @protocol(p1);");
- verifyFormat("SEL s = @selector(foo:);");
- verifyFormat("@synchronized(self) {\n"
- " f();\n"
- "}");
-
- verifyFormat("@synthesize dropArrowPosition = dropArrowPosition_;");
- verifyGoogleFormat("@synthesize dropArrowPosition = dropArrowPosition_;");
-
- verifyFormat("@property(assign, nonatomic) CGFloat hoverAlpha;");
- verifyFormat("@property(assign, getter=isEditable) BOOL editable;");
- verifyGoogleFormat("@property(assign, getter=isEditable) BOOL editable;");
- verifyFormat("@property (assign, getter=isEditable) BOOL editable;",
- getMozillaStyle());
- verifyFormat("@property BOOL editable;", getMozillaStyle());
- verifyFormat("@property (assign, getter=isEditable) BOOL editable;",
- getWebKitStyle());
- verifyFormat("@property BOOL editable;", getWebKitStyle());
-
- verifyFormat("@import foo.bar;\n"
- "@import baz;");
-}
-
-TEST_F(FormatTest, ObjCForIn) {
- verifyFormat("- (void)test {\n"
- " for (NSString *n in arrayOfStrings) {\n"
- " foo(n);\n"
- " }\n"
- "}");
- verifyFormat("- (void)test {\n"
- " for (NSString *n in (__bridge NSArray *)arrayOfStrings) {\n"
- " foo(n);\n"
- " }\n"
- "}");
-}
-
-TEST_F(FormatTest, ObjCLiterals) {
- verifyFormat("@\"String\"");
- verifyFormat("@1");
- verifyFormat("@+4.8");
- verifyFormat("@-4");
- verifyFormat("@1LL");
- verifyFormat("@.5");
- verifyFormat("@'c'");
- verifyFormat("@true");
-
- verifyFormat("NSNumber *smallestInt = @(-INT_MAX - 1);");
- verifyFormat("NSNumber *piOverTwo = @(M_PI / 2);");
- verifyFormat("NSNumber *favoriteColor = @(Green);");
- verifyFormat("NSString *path = @(getenv(\"PATH\"));");
-
- verifyFormat("[dictionary setObject:@(1) forKey:@\"number\"];");
-}
-
-TEST_F(FormatTest, ObjCDictLiterals) {
- verifyFormat("@{");
- verifyFormat("@{}");
- verifyFormat("@{@\"one\" : @1}");
- verifyFormat("return @{@\"one\" : @1;");
- verifyFormat("@{@\"one\" : @1}");
-
- verifyFormat("@{@\"one\" : @{@2 : @1}}");
- verifyFormat("@{\n"
- " @\"one\" : @{@2 : @1},\n"
- "}");
-
- verifyFormat("@{1 > 2 ? @\"one\" : @\"two\" : 1 > 2 ? @1 : @2}");
- verifyIncompleteFormat("[self setDict:@{}");
- verifyIncompleteFormat("[self setDict:@{@1 : @2}");
- verifyFormat("NSLog(@\"%@\", @{@1 : @2, @2 : @3}[@1]);");
- verifyFormat(
- "NSDictionary *masses = @{@\"H\" : @1.0078, @\"He\" : @4.0026};");
- verifyFormat(
- "NSDictionary *settings = @{AVEncoderKey : @(AVAudioQualityMax)};");
-
- verifyFormat("NSDictionary *d = @{\n"
- " @\"nam\" : NSUserNam(),\n"
- " @\"dte\" : [NSDate date],\n"
- " @\"processInfo\" : [NSProcessInfo processInfo]\n"
- "};");
- verifyFormat(
- "@{\n"
- " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee : "
- "regularFont,\n"
- "};");
- verifyGoogleFormat(
- "@{\n"
- " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee : "
- "regularFont,\n"
- "};");
- verifyFormat(
- "@{\n"
- " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee :\n"
- " reeeeeeeeeeeeeeeeeeeeeeeegularFont,\n"
- "};");
-
- // We should try to be robust in case someone forgets the "@".
- verifyFormat("NSDictionary *d = {\n"
- " @\"nam\" : NSUserNam(),\n"
- " @\"dte\" : [NSDate date],\n"
- " @\"processInfo\" : [NSProcessInfo processInfo]\n"
- "};");
- verifyFormat("NSMutableDictionary *dictionary =\n"
- " [NSMutableDictionary dictionaryWithDictionary:@{\n"
- " aaaaaaaaaaaaaaaaaaaaa : aaaaaaaaaaaaa,\n"
- " bbbbbbbbbbbbbbbbbb : bbbbb,\n"
- " cccccccccccccccc : ccccccccccccccc\n"
- " }];");
-
- // Ensure that casts before the key are kept on the same line as the key.
- verifyFormat(
- "NSDictionary *d = @{\n"
- " (aaaaaaaa id)aaaaaaaaa : (aaaaaaaa id)aaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " (aaaaaaaa id)aaaaaaaaaaaaaa : (aaaaaaaa id)aaaaaaaaaaaaaa,\n"
- "};");
-}
-
-TEST_F(FormatTest, ObjCArrayLiterals) {
- verifyIncompleteFormat("@[");
- verifyFormat("@[]");
- verifyFormat(
- "NSArray *array = @[ @\" Hey \", NSApp, [NSNumber numberWithInt:42] ];");
- verifyFormat("return @[ @3, @[], @[ @4, @5 ] ];");
- verifyFormat("NSArray *array = @[ [foo description] ];");
-
- verifyFormat(
- "NSArray *some_variable = @[\n"
- " aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- "];");
- verifyFormat(
- "NSArray *some_variable = @[\n"
- " aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaa\", @\"aaaaaaaaaaaaaaaa\", @\"aaaaaaaaaaaaaaaa\"\n"
- "];");
- verifyFormat("NSArray *some_variable = @[\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- "];");
- verifyFormat("NSArray *array = @[\n"
- " @\"a\",\n"
- " @\"a\",\n" // Trailing comma -> one per line.
- "];");
-
- // We should try to be robust in case someone forgets the "@".
- verifyFormat("NSArray *some_variable = [\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- "];");
- verifyFormat(
- "- (NSAttributedString *)attributedStringForSegment:(NSUInteger)segment\n"
- " index:(NSUInteger)index\n"
- " nonDigitAttributes:\n"
- " (NSDictionary *)noDigitAttributes;");
- verifyFormat("[someFunction someLooooooooooooongParameter:@[\n"
- " NSBundle.mainBundle.infoDictionary[@\"a\"]\n"
- "]];");
-}
TEST_F(FormatTest, BreaksStringLiterals) {
EXPECT_EQ("\"some text \"\n"
@@ -10184,6 +9609,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
CHECK_PARSE_BOOL(SpacesInContainerLiterals);
CHECK_PARSE_BOOL(SpacesInCStyleCastParentheses);
CHECK_PARSE_BOOL(SpaceAfterCStyleCast);
+ CHECK_PARSE_BOOL(SpaceAfterTemplateKeyword);
CHECK_PARSE_BOOL(SpaceBeforeAssignmentOperators);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterClass);
@@ -10920,6 +10346,7 @@ TEST_F(FormatTest, FormatsLambdas) {
verifyFormat("int c = [&a, &a, a] { [=, a, b, &c] { return b++; }(); }();\n");
verifyFormat("auto c = {[&a, &a, a] { [=, a, b, &c] { return b++; }(); }}\n");
verifyFormat("auto c = {[&a, &a, a] { [=, a, b, &c] {}(); }}\n");
+ verifyFormat("int x = f(*+[] {});");
verifyFormat("void f() {\n"
" other(x.begin(), x.end(), [&](int, int) { return 1; });\n"
"}\n");
@@ -11147,6 +10574,8 @@ TEST_F(FormatTest, FormatsBlocks) {
" }\n"
"});");
verifyFormat("Block b = ^int *(A *a, B *b) {}");
+ verifyFormat("BOOL (^aaa)(void) = ^BOOL {\n"
+ "};");
FormatStyle FourIndent = getLLVMStyle();
FourIndent.ObjCBlockIndentWidth = 4;
@@ -11322,6 +10751,12 @@ TEST_F(FormatTest, SpacesInAngles) {
verifyFormat("A<A<int>>();", Spaces);
}
+TEST_F(FormatTest, SpaceAfterTemplateKeyword) {
+ FormatStyle Style = getLLVMStyle();
+ Style.SpaceAfterTemplateKeyword = false;
+ verifyFormat("template<int> void foo();", Style);
+}
+
TEST_F(FormatTest, TripleAngleBrackets) {
verifyFormat("f<<<1, 1>>>();");
verifyFormat("f<<<1, 1, 1, s>>>();");
@@ -11332,6 +10767,8 @@ TEST_F(FormatTest, TripleAngleBrackets) {
EXPECT_EQ("f<param><<<1, 1>>>();", format("f< param > <<< 1, 1 >>> ();"));
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaa<<<\n 1, 1>>>();");
+ verifyFormat("aaaaaaaaaaaaaaa<aaaaaaaaa, aaaaaaaaaa, aaaaaaaaaaaaaa>\n"
+ " <<<aaaaaaaaa, aaaaaaaaaa, aaaaaaaaaaaaaaaaaa>>>();");
}
TEST_F(FormatTest, MergeLessLessAtEnd) {
@@ -11483,9 +10920,25 @@ TEST_F(FormatTest, FormatsTableGenCode) {
verifyFormat("include \"a.td\"\ninclude \"b.td\"", Style);
}
-// Since this test case uses UNIX-style file path. We disable it for MS
-// compiler.
-#if !defined(_MSC_VER) && !defined(__MINGW32__)
+TEST_F(FormatTest, ArrayOfTemplates) {
+ EXPECT_EQ("auto a = new unique_ptr<int>[10];",
+ format("auto a = new unique_ptr<int > [ 10];"));
+
+ FormatStyle Spaces = getLLVMStyle();
+ Spaces.SpacesInSquareBrackets = true;
+ EXPECT_EQ("auto a = new unique_ptr<int>[ 10 ];",
+ format("auto a = new unique_ptr<int > [10];", Spaces));
+}
+
+TEST_F(FormatTest, ArrayAsTemplateType) {
+ EXPECT_EQ("auto a = unique_ptr<Foo<Bar>[10]>;",
+ format("auto a = unique_ptr < Foo < Bar>[ 10]> ;"));
+
+ FormatStyle Spaces = getLLVMStyle();
+ Spaces.SpacesInSquareBrackets = true;
+ EXPECT_EQ("auto a = unique_ptr<Foo<Bar>[ 10 ]>;",
+ format("auto a = unique_ptr < Foo < Bar>[10]> ;", Spaces));
+}
TEST(FormatStyle, GetStyleOfFile) {
vfs::InMemoryFileSystem FS;
@@ -11495,13 +10948,13 @@ TEST(FormatStyle, GetStyleOfFile) {
llvm::MemoryBuffer::getMemBuffer("BasedOnStyle: LLVM")));
ASSERT_TRUE(
FS.addFile("/a/test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int i;")));
- auto Style1 = getStyle("file", "/a/.clang-format", "Google", &FS);
+ auto Style1 = getStyle("file", "/a/.clang-format", "Google", "", &FS);
ASSERT_EQ(Style1, getLLVMStyle());
// Test 2: fallback to default.
ASSERT_TRUE(
FS.addFile("/b/test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int i;")));
- auto Style2 = getStyle("file", "/b/test.cpp", "Mozilla", &FS);
+ auto Style2 = getStyle("file", "/b/test.cpp", "Mozilla", "", &FS);
ASSERT_EQ(Style2, getMozillaStyle());
// Test 3: format file in parent directory.
@@ -11510,23 +10963,10 @@ TEST(FormatStyle, GetStyleOfFile) {
llvm::MemoryBuffer::getMemBuffer("BasedOnStyle: Google")));
ASSERT_TRUE(FS.addFile("/c/sub/sub/sub/test.cpp", 0,
llvm::MemoryBuffer::getMemBuffer("int i;")));
- auto Style3 = getStyle("file", "/c/sub/sub/sub/test.cpp", "LLVM", &FS);
+ auto Style3 = getStyle("file", "/c/sub/sub/sub/test.cpp", "LLVM", "", &FS);
ASSERT_EQ(Style3, getGoogleStyle());
}
-#endif // _MSC_VER
-
-class ReplacementTest : public ::testing::Test {
-protected:
- tooling::Replacement createReplacement(SourceLocation Start, unsigned Length,
- llvm::StringRef ReplacementText) {
- return tooling::Replacement(Context.Sources, Start, Length,
- ReplacementText);
- }
-
- RewriterTestContext Context;
-};
-
TEST_F(ReplacementTest, FormatCodeAfterReplacements) {
// Column limit is 20.
std::string Code = "Type *a =\n"
@@ -11541,15 +10981,15 @@ TEST_F(ReplacementTest, FormatCodeAfterReplacements) {
" mm);\n"
"int bad = format ;";
FileID ID = Context.createInMemoryFile("format.cpp", Code);
- tooling::Replacements Replaces;
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID, 1, 1), 6, "auto "));
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID, 3, 10), 1, "nullptr"));
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID, 4, 3), 1, "nullptr"));
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID, 4, 13), 1, "nullptr"));
+ tooling::Replacements Replaces = toReplacements(
+ {tooling::Replacement(Context.Sources, Context.getLocation(ID, 1, 1), 6,
+ "auto "),
+ tooling::Replacement(Context.Sources, Context.getLocation(ID, 3, 10), 1,
+ "nullptr"),
+ tooling::Replacement(Context.Sources, Context.getLocation(ID, 4, 3), 1,
+ "nullptr"),
+ tooling::Replacement(Context.Sources, Context.getLocation(ID, 4, 13), 1,
+ "nullptr")});
format::FormatStyle Style = format::getLLVMStyle();
Style.ColumnLimit = 20; // Set column limit to 20 to increase readibility.
@@ -11576,9 +11016,9 @@ TEST_F(ReplacementTest, SortIncludesAfterReplacement) {
" return 0;\n"
"}";
FileID ID = Context.createInMemoryFile("fix.cpp", Code);
- tooling::Replacements Replaces;
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID, 1, 1), 0, "#include \"b.h\"\n"));
+ tooling::Replacements Replaces = toReplacements(
+ {tooling::Replacement(Context.Sources, Context.getLocation(ID, 1, 1), 0,
+ "#include \"b.h\"\n")});
format::FormatStyle Style = format::getLLVMStyle();
Style.SortIncludes = true;
@@ -11590,6 +11030,17 @@ TEST_F(ReplacementTest, SortIncludesAfterReplacement) {
EXPECT_EQ(Expected, *Result);
}
+TEST_F(FormatTest, AllignTrailingComments) {
+ EXPECT_EQ("#define MACRO(V) \\\n"
+ " V(Rt2) /* one more char */ \\\n"
+ " V(Rs) /* than here */ \\\n"
+ "/* comment 3 */\n",
+ format("#define MACRO(V)\\\n"
+ "V(Rt2) /* one more char */ \\\n"
+ "V(Rs) /* than here */ \\\n"
+ "/* comment 3 */ \\\n",
+ getLLVMStyleWithColumns(40)));
+}
} // end namespace
} // end namespace format
} // end namespace clang
diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp
index 2819383a3585..6f494db71d15 100644
--- a/unittests/Format/FormatTestJS.cpp
+++ b/unittests/Format/FormatTestJS.cpp
@@ -135,6 +135,8 @@ TEST_F(FormatTestJS, ReservedWords) {
verifyFormat("x.in() = 1;");
verifyFormat("x.let() = 1;");
verifyFormat("x.var() = 1;");
+ verifyFormat("x.for() = 1;");
+ verifyFormat("x.as() = 1;");
verifyFormat("x = {\n"
" a: 12,\n"
" interface: 1,\n"
@@ -147,6 +149,21 @@ TEST_F(FormatTestJS, ReservedWords) {
verifyFormat("x = interface instanceof y;");
}
+TEST_F(FormatTestJS, ReservedWordsMethods) {
+ verifyFormat(
+ "class X {\n"
+ " delete() {\n"
+ " x();\n"
+ " }\n"
+ " interface() {\n"
+ " x();\n"
+ " }\n"
+ " let() {\n"
+ " x();\n"
+ " }\n"
+ "}\n");
+}
+
TEST_F(FormatTestJS, CppKeywords) {
// Make sure we don't mess stuff up because of C++ keywords.
verifyFormat("return operator && (aa);");
@@ -161,7 +178,11 @@ TEST_F(FormatTestJS, ES6DestructuringAssignment) {
}
TEST_F(FormatTestJS, ContainerLiterals) {
- verifyFormat("var x = {y: function(a) { return a; }};");
+ verifyFormat("var x = {\n"
+ " y: function(a) {\n"
+ " return a;\n"
+ " }\n"
+ "};");
verifyFormat("return {\n"
" link: function() {\n"
" f(); //\n"
@@ -212,7 +233,11 @@ TEST_F(FormatTestJS, ContainerLiterals) {
verifyFormat("x = foo && {a: 123};");
// Arrow functions in object literals.
- verifyFormat("var x = {y: (a) => { return a; }};");
+ verifyFormat("var x = {\n"
+ " y: (a) => {\n"
+ " return a;\n"
+ " }\n"
+ "};");
verifyFormat("var x = {y: (a) => a};");
// Computed keys.
@@ -234,6 +259,13 @@ TEST_F(FormatTestJS, ContainerLiterals) {
" b: b,\n"
" 'c': c,\n"
"};");
+
+ // Dict literals can skip the label names.
+ verifyFormat("var x = {\n"
+ " aaa,\n"
+ " aaa,\n"
+ " aaa,\n"
+ "};");
}
TEST_F(FormatTestJS, MethodsInObjectLiterals) {
@@ -324,13 +356,48 @@ TEST_F(FormatTestJS, FormatsNamespaces) {
"}\n");
}
+TEST_F(FormatTestJS, NamespacesMayNotWrap) {
+ verifyFormat("declare namespace foobarbaz {\n"
+ "}\n", getGoogleJSStyleWithColumns(18));
+ verifyFormat("declare module foobarbaz {\n"
+ "}\n", getGoogleJSStyleWithColumns(15));
+ verifyFormat("namespace foobarbaz {\n"
+ "}\n", getGoogleJSStyleWithColumns(10));
+ verifyFormat("module foobarbaz {\n"
+ "}\n", getGoogleJSStyleWithColumns(7));
+}
+
+TEST_F(FormatTestJS, AmbientDeclarations) {
+ FormatStyle NineCols = getGoogleJSStyleWithColumns(9);
+ verifyFormat(
+ "declare class\n"
+ " X {}",
+ NineCols);
+ verifyFormat(
+ "declare function\n"
+ "x();", // TODO(martinprobst): should ideally be indented.
+ NineCols);
+ verifyFormat(
+ "declare enum X {\n"
+ "}",
+ NineCols);
+ verifyFormat(
+ "declare let\n"
+ " x: number;",
+ NineCols);
+}
+
TEST_F(FormatTestJS, FormatsFreestandingFunctions) {
verifyFormat("function outer1(a, b) {\n"
- " function inner1(a, b) { return a; }\n"
+ " function inner1(a, b) {\n"
+ " return a;\n"
+ " }\n"
" inner1(a, b);\n"
"}\n"
"function outer2(a, b) {\n"
- " function inner2(a, b) { return a; }\n"
+ " function inner2(a, b) {\n"
+ " return a;\n"
+ " }\n"
" inner2(a, b);\n"
"}");
verifyFormat("function f() {}");
@@ -341,6 +408,8 @@ TEST_F(FormatTestJS, GeneratorFunctions) {
" let x = 1;\n"
" yield x;\n"
" yield* something();\n"
+ " yield [1, 2];\n"
+ " yield {a: 1};\n"
"}");
verifyFormat("function*\n"
" f() {\n"
@@ -350,8 +419,15 @@ TEST_F(FormatTestJS, GeneratorFunctions) {
" yield 1;\n"
"}\n");
verifyFormat("class X {\n"
- " * generatorMethod() { yield x; }\n"
+ " * generatorMethod() {\n"
+ " yield x;\n"
+ " }\n"
"}");
+ verifyFormat("var x = {\n"
+ " a: function*() {\n"
+ " //\n"
+ " }\n"
+ "}\n");
}
TEST_F(FormatTestJS, AsyncFunctions) {
@@ -366,7 +442,9 @@ TEST_F(FormatTestJS, AsyncFunctions) {
" return fetch(x);\n"
"}");
verifyFormat("class X {\n"
- " async asyncMethod() { return fetch(1); }\n"
+ " async asyncMethod() {\n"
+ " return fetch(1);\n"
+ " }\n"
"}");
verifyFormat("function initialize() {\n"
" // Comment.\n"
@@ -423,8 +501,10 @@ TEST_F(FormatTestJS, ColumnLayoutForArrayLiterals) {
}
TEST_F(FormatTestJS, FunctionLiterals) {
+ FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
verifyFormat("doFoo(function() {});");
- verifyFormat("doFoo(function() { return 1; });");
+ verifyFormat("doFoo(function() { return 1; });", Style);
verifyFormat("var func = function() {\n"
" return 1;\n"
"};");
@@ -438,7 +518,8 @@ TEST_F(FormatTestJS, FunctionLiterals) {
" getAttribute: function(key) { return this[key]; },\n"
" style: {direction: ''}\n"
" }\n"
- "};");
+ "};",
+ Style);
verifyFormat("abc = xyz ? function() {\n"
" return 1;\n"
"} : function() {\n"
@@ -476,13 +557,6 @@ TEST_F(FormatTestJS, FunctionLiterals) {
" // code\n"
" });");
- verifyFormat("f({a: function() { return 1; }});",
- getGoogleJSStyleWithColumns(33));
- verifyFormat("f({\n"
- " a: function() { return 1; }\n"
- "});",
- getGoogleJSStyleWithColumns(32));
-
verifyFormat("return {\n"
" a: function SomeFunction() {\n"
" // ...\n"
@@ -510,6 +584,15 @@ TEST_F(FormatTestJS, FunctionLiterals) {
" .doSomethingElse(\n"
" // break\n"
" );");
+
+ Style.ColumnLimit = 33;
+ verifyFormat("f({a: function() { return 1; }});", Style);
+ Style.ColumnLimit = 32;
+ verifyFormat("f({\n"
+ " a: function() { return 1; }\n"
+ "});",
+ Style);
+
}
TEST_F(FormatTestJS, InliningFunctionLiterals) {
@@ -570,6 +653,8 @@ TEST_F(FormatTestJS, InliningFunctionLiterals) {
}
TEST_F(FormatTestJS, MultipleFunctionLiterals) {
+ FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
verifyFormat("promise.then(\n"
" function success() {\n"
" doFoo();\n"
@@ -606,7 +691,8 @@ TEST_F(FormatTestJS, MultipleFunctionLiterals) {
" .thenCatch(function(error) {\n"
" body();\n"
" body();\n"
- " });");
+ " });",
+ Style);
verifyFormat("getSomeLongPromise()\n"
" .then(function(value) {\n"
" body();\n"
@@ -619,7 +705,8 @@ TEST_F(FormatTestJS, MultipleFunctionLiterals) {
verifyFormat("getSomeLongPromise()\n"
" .then(function(value) { body(); })\n"
- " .thenCatch(function(error) { body(); });");
+ " .thenCatch(function(error) { body(); });",
+ Style);
verifyFormat("return [aaaaaaaaaaaaaaaaaaaaaa]\n"
" .aaaaaaa(function() {\n"
@@ -633,7 +720,9 @@ TEST_F(FormatTestJS, ArrowFunctions) {
" return a;\n"
"};");
verifyFormat("var x = (a) => {\n"
- " function y() { return 42; }\n"
+ " function y() {\n"
+ " return 42;\n"
+ " }\n"
" return a;\n"
"};");
verifyFormat("var x = (a: type): {some: type} => {\n"
@@ -686,7 +775,9 @@ TEST_F(FormatTestJS, WrapRespectsAutomaticSemicolonInsertion) {
// would change due to automatic semicolon insertion.
// See http://www.ecma-international.org/ecma-262/5.1/#sec-7.9.1.
verifyFormat("return aaaaa;", getGoogleJSStyleWithColumns(10));
+ verifyFormat("return /* hello! */ aaaaa;", getGoogleJSStyleWithColumns(10));
verifyFormat("continue aaaaa;", getGoogleJSStyleWithColumns(10));
+ verifyFormat("continue /* hello! */ aaaaa;", getGoogleJSStyleWithColumns(10));
verifyFormat("break aaaaa;", getGoogleJSStyleWithColumns(10));
verifyFormat("throw aaaaa;", getGoogleJSStyleWithColumns(10));
verifyFormat("aaaaaaaaa++;", getGoogleJSStyleWithColumns(10));
@@ -745,6 +836,18 @@ TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
"String");
verifyFormat("function f(@Foo bar) {}", "function f(@Foo\n"
" bar) {}");
+ verifyFormat("a = true\n"
+ "return 1",
+ "a = true\n"
+ " return 1");
+ verifyFormat("a = 's'\n"
+ "return 1",
+ "a = 's'\n"
+ " return 1");
+ verifyFormat("a = null\n"
+ "return 1",
+ "a = null\n"
+ " return 1");
}
TEST_F(FormatTestJS, ClosureStyleCasts) {
@@ -899,8 +1002,16 @@ TEST_F(FormatTestJS, TypeAnnotations) {
verifyFormat("((a: string, b: number): string => a + b);");
verifyFormat("var x: (y: number) => string;");
verifyFormat("var x: P<string, (a: number) => string>;");
- verifyFormat("var x = {y: function(): z { return 1; }};");
- verifyFormat("var x = {y: function(): {a: number} { return 1; }};");
+ verifyFormat("var x = {\n"
+ " y: function(): z {\n"
+ " return 1;\n"
+ " }\n"
+ "};");
+ verifyFormat("var x = {\n"
+ " y: function(): {a: number} {\n"
+ " return 1;\n"
+ " }\n"
+ "};");
verifyFormat("function someFunc(args: string[]):\n"
" {longReturnValue: string[]} {}",
getGoogleJSStyleWithColumns(60));
@@ -928,7 +1039,7 @@ TEST_F(FormatTestJS, ClassDeclarations) {
verifyFormat("class C {\n ['x' + 2]: string = 12;\n}");
verifyFormat("class C {\n private x: string = 12;\n}");
verifyFormat("class C {\n private static x: string = 12;\n}");
- verifyFormat("class C {\n static x(): string { return 'asd'; }\n}");
+ verifyFormat("class C {\n static x(): string {\n return 'asd';\n }\n}");
verifyFormat("class C extends P implements I {}");
verifyFormat("class C extends p.P implements i.I {}");
verifyFormat("class Test {\n"
@@ -1091,7 +1202,9 @@ TEST_F(FormatTestJS, Modules) {
verifyFormat("export default () => {};");
verifyFormat("export interface Foo { foo: number; }\n"
"export class Bar {\n"
- " blah(): string { return this.blah; };\n"
+ " blah(): string {\n"
+ " return this.blah;\n"
+ " };\n"
"}");
}
@@ -1122,7 +1235,7 @@ TEST_F(FormatTestJS, ImportWrapping) {
TEST_F(FormatTestJS, TemplateStrings) {
// Keeps any whitespace/indentation within the template string.
verifyFormat("var x = `hello\n"
- " ${ name }\n"
+ " ${name}\n"
" !`;",
"var x = `hello\n"
" ${ name }\n"
@@ -1206,6 +1319,27 @@ TEST_F(FormatTestJS, TemplateStrings) {
"var y;",
"var x = ` \\` a`;\n"
"var y;");
+ // Escaped dollar.
+ verifyFormat("var x = ` \\${foo}`;\n");
+}
+
+TEST_F(FormatTestJS, TemplateStringASI) {
+ verifyFormat("var x = `hello${world}`;", "var x = `hello${\n"
+ " world\n"
+ "}`;");
+}
+
+TEST_F(FormatTestJS, NestedTemplateStrings) {
+ verifyFormat(
+ "var x = `<ul>${xs.map(x => `<li>${x}</li>`).join('\\n')}</ul>`;");
+ verifyFormat("var x = `he${({text: 'll'}.text)}o`;");
+
+ // Crashed at some point.
+ verifyFormat("}");
+}
+
+TEST_F(FormatTestJS, TaggedTemplateStrings) {
+ verifyFormat("var x = html`<ul>`;");
}
TEST_F(FormatTestJS, CastSyntax) {
@@ -1218,6 +1352,11 @@ TEST_F(FormatTestJS, CastSyntax) {
" 1, //\n"
" 2\n"
"];");
+ verifyFormat("var x = [{x: 1} as type];");
+ verifyFormat("x = x as [a, b];");
+ verifyFormat("x = x as {a: string};");
+ verifyFormat("x = x as (string);");
+ verifyFormat("x = x! as (string);");
}
TEST_F(FormatTestJS, TypeArguments) {
@@ -1318,6 +1457,21 @@ TEST_F(FormatTestJS, RequoteStringsSingle) {
"let x = \"single\";\n");
}
+TEST_F(FormatTestJS, RequoteAndIndent) {
+ verifyFormat("let x = someVeryLongFunctionThatGoesOnAndOn(\n"
+ " 'double quoted string that needs wrapping');",
+ "let x = someVeryLongFunctionThatGoesOnAndOn("
+ "\"double quoted string that needs wrapping\");");
+
+ verifyFormat("let x =\n"
+ " 'foo\\'oo';\n"
+ "let x =\n"
+ " 'foo\\'oo';",
+ "let x=\"foo'oo\";\n"
+ "let x=\"foo'oo\";",
+ getGoogleJSStyleWithColumns(15));
+}
+
TEST_F(FormatTestJS, RequoteStringsDouble) {
FormatStyle DoubleQuotes = getGoogleStyle(FormatStyle::LK_JavaScript);
DoubleQuotes.JavaScriptQuotes = FormatStyle::JSQS_Double;
@@ -1346,6 +1500,7 @@ TEST_F(FormatTestJS, NonNullAssertionOperator) {
verifyFormat("let x = !foo;\n");
verifyFormat("let x = foo[0]!;\n");
verifyFormat("let x = (foo)!;\n");
+ verifyFormat("let x = foo! - 1;\n");
verifyFormat("let x = {foo: 1}!;\n");
}
@@ -1358,5 +1513,11 @@ TEST_F(FormatTestJS, Conditional) {
"}");
}
+TEST_F(FormatTestJS, ImportComments) {
+ verifyFormat("import {x} from 'x'; // from some location",
+ getGoogleJSStyleWithColumns(25));
+ verifyFormat("// taze: x from 'location'", getGoogleJSStyleWithColumns(10));
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Format/FormatTestObjC.cpp b/unittests/Format/FormatTestObjC.cpp
new file mode 100644
index 000000000000..6a530f921e6d
--- /dev/null
+++ b/unittests/Format/FormatTestObjC.cpp
@@ -0,0 +1,822 @@
+//===- unittest/Format/FormatTestObjC.cpp - Formatting unit tests----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Format/Format.h"
+
+#include "../Tooling/ReplacementTest.h"
+#include "FormatTestUtils.h"
+
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+
+#define DEBUG_TYPE "format-test"
+
+using clang::tooling::ReplacementTest;
+using clang::tooling::toReplacements;
+
+namespace clang {
+namespace format {
+namespace {
+
+class FormatTestObjC : public ::testing::Test {
+protected:
+ FormatTestObjC() {
+ Style = getLLVMStyle();
+ Style.Language = FormatStyle::LK_ObjC;
+ }
+
+ enum IncompleteCheck {
+ IC_ExpectComplete,
+ IC_ExpectIncomplete,
+ IC_DoNotCheck
+ };
+
+ std::string format(llvm::StringRef Code,
+ IncompleteCheck CheckIncomplete = IC_ExpectComplete) {
+ DEBUG(llvm::errs() << "---\n");
+ DEBUG(llvm::errs() << Code << "\n\n");
+ std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
+ bool IncompleteFormat = false;
+ tooling::Replacements Replaces =
+ reformat(Style, Code, Ranges, "<stdin>", &IncompleteFormat);
+ if (CheckIncomplete != IC_DoNotCheck) {
+ bool ExpectedIncompleteFormat = CheckIncomplete == IC_ExpectIncomplete;
+ EXPECT_EQ(ExpectedIncompleteFormat, IncompleteFormat) << Code << "\n\n";
+ }
+ auto Result = applyAllReplacements(Code, Replaces);
+ EXPECT_TRUE(static_cast<bool>(Result));
+ DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
+ return *Result;
+ }
+
+ void verifyFormat(StringRef Code) {
+ EXPECT_EQ(Code.str(), format(test::messUp(Code)));
+ }
+
+ void verifyIncompleteFormat(StringRef Code) {
+ EXPECT_EQ(Code.str(), format(test::messUp(Code), IC_ExpectIncomplete));
+ }
+
+ FormatStyle Style;
+};
+
+TEST_F(FormatTestObjC, DetectsObjCInHeaders) {
+ Style = getStyle("LLVM", "a.h", "none", "@interface\n"
+ "- (id)init;");
+ EXPECT_EQ(FormatStyle::LK_ObjC, Style.Language);
+ Style = getStyle("LLVM", "a.h", "none", "@interface\n"
+ "+ (id)init;");
+ EXPECT_EQ(FormatStyle::LK_ObjC, Style.Language);
+
+ // No recognizable ObjC.
+ Style = getStyle("LLVM", "a.h", "none", "void f() {}");
+ EXPECT_EQ(FormatStyle::LK_Cpp, Style.Language);
+}
+
+TEST_F(FormatTestObjC, FormatObjCTryCatch) {
+ verifyFormat("@try {\n"
+ " f();\n"
+ "} @catch (NSException e) {\n"
+ " @throw;\n"
+ "} @finally {\n"
+ " exit(42);\n"
+ "}");
+ verifyFormat("DEBUG({\n"
+ " @try {\n"
+ " } @finally {\n"
+ " }\n"
+ "});\n");
+}
+
+TEST_F(FormatTestObjC, FormatObjCAutoreleasepool) {
+ verifyFormat("@autoreleasepool {\n"
+ " f();\n"
+ "}\n"
+ "@autoreleasepool {\n"
+ " f();\n"
+ "}\n");
+ Style.BreakBeforeBraces = FormatStyle::BS_Allman;
+ verifyFormat("@autoreleasepool\n"
+ "{\n"
+ " f();\n"
+ "}\n"
+ "@autoreleasepool\n"
+ "{\n"
+ " f();\n"
+ "}\n");
+}
+
+TEST_F(FormatTestObjC, FormatObjCInterface) {
+ verifyFormat("@interface Foo : NSObject <NSSomeDelegate> {\n"
+ "@public\n"
+ " int field1;\n"
+ "@protected\n"
+ " int field2;\n"
+ "@private\n"
+ " int field3;\n"
+ "@package\n"
+ " int field4;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface /* wait for it */ Foo\n"
+ "+ (id)init;\n"
+ "// Look, a comment!\n"
+ "- (int)answerWith:(int)i;\n"
+ "@end");
+
+ verifyFormat("@interface Foo\n"
+ "@end\n"
+ "@interface Bar\n"
+ "@end");
+
+ verifyFormat("@interface Foo : Bar\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo : /**/ Bar /**/ <Baz, /**/ Quux>\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo (HackStuff)\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo ()\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo (HackStuff) <MyProtocol>\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo : Bar {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo : Bar <Baz, Quux> {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo (HackStuff) {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo () {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo (HackStuff) <MyProtocol> {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ Style = getGoogleStyle(FormatStyle::LK_ObjC);
+ verifyFormat("@interface Foo : NSObject<NSSomeDelegate> {\n"
+ " @public\n"
+ " int field1;\n"
+ " @protected\n"
+ " int field2;\n"
+ " @private\n"
+ " int field3;\n"
+ " @package\n"
+ " int field4;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+ verifyFormat("@interface Foo : Bar<Baz, Quux>\n"
+ "+ (id)init;\n"
+ "@end");
+ verifyFormat("@interface Foo (HackStuff)<MyProtocol>\n"
+ "+ (id)init;\n"
+ "@end");
+ Style.BinPackParameters = false;
+ Style.ColumnLimit = 80;
+ verifyFormat("@interface aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ()<\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> {\n"
+ "}");
+}
+
+TEST_F(FormatTestObjC, FormatObjCImplementation) {
+ verifyFormat("@implementation Foo : NSObject {\n"
+ "@public\n"
+ " int field1;\n"
+ "@protected\n"
+ " int field2;\n"
+ "@private\n"
+ " int field3;\n"
+ "@package\n"
+ " int field4;\n"
+ "}\n"
+ "+ (id)init {\n}\n"
+ "@end");
+
+ verifyFormat("@implementation Foo\n"
+ "+ (id)init {\n"
+ " if (true)\n"
+ " return nil;\n"
+ "}\n"
+ "// Look, a comment!\n"
+ "- (int)answerWith:(int)i {\n"
+ " return i;\n"
+ "}\n"
+ "+ (int)answerWith:(int)i {\n"
+ " return i;\n"
+ "}\n"
+ "@end");
+
+ verifyFormat("@implementation Foo\n"
+ "@end\n"
+ "@implementation Bar\n"
+ "@end");
+
+ EXPECT_EQ("@implementation Foo : Bar\n"
+ "+ (id)init {\n}\n"
+ "- (void)foo {\n}\n"
+ "@end",
+ format("@implementation Foo : Bar\n"
+ "+(id)init{}\n"
+ "-(void)foo{}\n"
+ "@end"));
+
+ verifyFormat("@implementation Foo {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init {\n}\n"
+ "@end");
+
+ verifyFormat("@implementation Foo : Bar {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init {\n}\n"
+ "@end");
+
+ verifyFormat("@implementation Foo (HackStuff)\n"
+ "+ (id)init {\n}\n"
+ "@end");
+ verifyFormat("@implementation ObjcClass\n"
+ "- (void)method;\n"
+ "{}\n"
+ "@end");
+
+ Style = getGoogleStyle(FormatStyle::LK_ObjC);
+ verifyFormat("@implementation Foo : NSObject {\n"
+ " @public\n"
+ " int field1;\n"
+ " @protected\n"
+ " int field2;\n"
+ " @private\n"
+ " int field3;\n"
+ " @package\n"
+ " int field4;\n"
+ "}\n"
+ "+ (id)init {\n}\n"
+ "@end");
+}
+
+TEST_F(FormatTestObjC, FormatObjCProtocol) {
+ verifyFormat("@protocol Foo\n"
+ "@property(weak) id delegate;\n"
+ "- (NSUInteger)numberOfThings;\n"
+ "@end");
+
+ verifyFormat("@protocol MyProtocol <NSObject>\n"
+ "- (NSUInteger)numberOfThings;\n"
+ "@end");
+
+ verifyFormat("@protocol Foo;\n"
+ "@protocol Bar;\n");
+
+ verifyFormat("@protocol Foo\n"
+ "@end\n"
+ "@protocol Bar\n"
+ "@end");
+
+ verifyFormat("@protocol myProtocol\n"
+ "- (void)mandatoryWithInt:(int)i;\n"
+ "@optional\n"
+ "- (void)optional;\n"
+ "@required\n"
+ "- (void)required;\n"
+ "@optional\n"
+ "@property(assign) int madProp;\n"
+ "@end\n");
+
+ verifyFormat("@property(nonatomic, assign, readonly)\n"
+ " int *looooooooooooooooooooooooooooongNumber;\n"
+ "@property(nonatomic, assign, readonly)\n"
+ " NSString *looooooooooooooooooooooooooooongName;");
+
+ verifyFormat("@implementation PR18406\n"
+ "}\n"
+ "@end");
+
+ Style = getGoogleStyle(FormatStyle::LK_ObjC);
+ verifyFormat("@protocol MyProtocol<NSObject>\n"
+ "- (NSUInteger)numberOfThings;\n"
+ "@end");
+}
+
+TEST_F(FormatTestObjC, FormatObjCMethodDeclarations) {
+ verifyFormat("- (void)doSomethingWith:(GTMFoo *)theFoo\n"
+ " rect:(NSRect)theRect\n"
+ " interval:(float)theInterval {\n"
+ "}");
+ verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n"
+ " longKeyword:(NSRect)theRect\n"
+ " longerKeyword:(float)theInterval\n"
+ " error:(NSError **)theError {\n"
+ "}");
+ verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n"
+ " longKeyword:(NSRect)theRect\n"
+ " evenLongerKeyword:(float)theInterval\n"
+ " error:(NSError **)theError {\n"
+ "}");
+ Style.ColumnLimit = 60;
+ verifyFormat("- (instancetype)initXxxxxx:(id<x>)x\n"
+ " y:(id<yyyyyyyyyyyyyyyyyyyy>)y\n"
+ " NS_DESIGNATED_INITIALIZER;");
+ verifyFormat("- (void)drawRectOn:(id)surface\n"
+ " ofSize:(size_t)height\n"
+ " :(size_t)width;");
+
+ // Continuation indent width should win over aligning colons if the function
+ // name is long.
+ Style = getGoogleStyle(FormatStyle::LK_ObjC);
+ Style.ColumnLimit = 40;
+ Style.IndentWrappedFunctionNames = true;
+ verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n"
+ " dontAlignNamef:(NSRect)theRect {\n"
+ "}");
+
+ // Make sure we don't break aligning for short parameter names.
+ verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n"
+ " aShortf:(NSRect)theRect {\n"
+ "}");
+
+ // Format pairs correctly.
+ Style.ColumnLimit = 80;
+ verifyFormat("- (void)drawRectOn:(id)surface\n"
+ " ofSize:(aaaaaaaa)height\n"
+ " :(size_t)width\n"
+ " atOrigin:(size_t)x\n"
+ " :(size_t)y\n"
+ " aaaaa:(a)yyy\n"
+ " bbb:(d)cccc;");
+ verifyFormat("- (void)drawRectOn:(id)surface ofSize:(aaa)height:(bbb)width;");
+}
+
+TEST_F(FormatTestObjC, FormatObjCMethodExpr) {
+ verifyFormat("[foo bar:baz];");
+ verifyFormat("return [foo bar:baz];");
+ verifyFormat("return (a)[foo bar:baz];");
+ verifyFormat("f([foo bar:baz]);");
+ verifyFormat("f(2, [foo bar:baz]);");
+ verifyFormat("f(2, a ? b : c);");
+ verifyFormat("[[self initWithInt:4] bar:[baz quux:arrrr]];");
+
+ // Unary operators.
+ verifyFormat("int a = +[foo bar:baz];");
+ verifyFormat("int a = -[foo bar:baz];");
+ verifyFormat("int a = ![foo bar:baz];");
+ verifyFormat("int a = ~[foo bar:baz];");
+ verifyFormat("int a = ++[foo bar:baz];");
+ verifyFormat("int a = --[foo bar:baz];");
+ verifyFormat("int a = sizeof [foo bar:baz];");
+ verifyFormat("int a = alignof [foo bar:baz];");
+ verifyFormat("int a = &[foo bar:baz];");
+ verifyFormat("int a = *[foo bar:baz];");
+ // FIXME: Make casts work, without breaking f()[4].
+ // verifyFormat("int a = (int)[foo bar:baz];");
+ // verifyFormat("return (int)[foo bar:baz];");
+ // verifyFormat("(void)[foo bar:baz];");
+ verifyFormat("return (MyType *)[self.tableView cellForRowAtIndexPath:cell];");
+
+ // Binary operators.
+ verifyFormat("[foo bar:baz], [foo bar:baz];");
+ verifyFormat("[foo bar:baz] = [foo bar:baz];");
+ verifyFormat("[foo bar:baz] *= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] /= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] %= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] += [foo bar:baz];");
+ verifyFormat("[foo bar:baz] -= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] <<= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] >>= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] &= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] ^= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] |= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] ? [foo bar:baz] : [foo bar:baz];");
+ verifyFormat("[foo bar:baz] || [foo bar:baz];");
+ verifyFormat("[foo bar:baz] && [foo bar:baz];");
+ verifyFormat("[foo bar:baz] | [foo bar:baz];");
+ verifyFormat("[foo bar:baz] ^ [foo bar:baz];");
+ verifyFormat("[foo bar:baz] & [foo bar:baz];");
+ verifyFormat("[foo bar:baz] == [foo bar:baz];");
+ verifyFormat("[foo bar:baz] != [foo bar:baz];");
+ verifyFormat("[foo bar:baz] >= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] <= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] > [foo bar:baz];");
+ verifyFormat("[foo bar:baz] < [foo bar:baz];");
+ verifyFormat("[foo bar:baz] >> [foo bar:baz];");
+ verifyFormat("[foo bar:baz] << [foo bar:baz];");
+ verifyFormat("[foo bar:baz] - [foo bar:baz];");
+ verifyFormat("[foo bar:baz] + [foo bar:baz];");
+ verifyFormat("[foo bar:baz] * [foo bar:baz];");
+ verifyFormat("[foo bar:baz] / [foo bar:baz];");
+ verifyFormat("[foo bar:baz] % [foo bar:baz];");
+ // Whew!
+
+ verifyFormat("return in[42];");
+ verifyFormat("for (auto v : in[1]) {\n}");
+ verifyFormat("for (int i = 0; i < in[a]; ++i) {\n}");
+ verifyFormat("for (int i = 0; in[a] < i; ++i) {\n}");
+ verifyFormat("for (int i = 0; i < n; ++i, ++in[a]) {\n}");
+ verifyFormat("for (int i = 0; i < n; ++i, in[a]++) {\n}");
+ verifyFormat("for (int i = 0; i < f(in[a]); ++i, in[a]++) {\n}");
+ verifyFormat("for (id foo in [self getStuffFor:bla]) {\n"
+ "}");
+ verifyFormat("[self aaaaa:MACRO(a, b:, c:)];");
+ verifyFormat("[self aaaaa:(1 + 2) bbbbb:3];");
+ verifyFormat("[self aaaaa:(Type)a bbbbb:3];");
+
+ verifyFormat("[self stuffWithInt:(4 + 2) float:4.5];");
+ verifyFormat("[self stuffWithInt:a ? b : c float:4.5];");
+ verifyFormat("[self stuffWithInt:a ? [self foo:bar] : c];");
+ verifyFormat("[self stuffWithInt:a ? (e ? f : g) : c];");
+ verifyFormat("[cond ? obj1 : obj2 methodWithParam:param]");
+ verifyFormat("[button setAction:@selector(zoomOut:)];");
+ verifyFormat("[color getRed:&r green:&g blue:&b alpha:&a];");
+
+ verifyFormat("arr[[self indexForFoo:a]];");
+ verifyFormat("throw [self errorFor:a];");
+ verifyFormat("@throw [self errorFor:a];");
+
+ verifyFormat("[(id)foo bar:(id)baz quux:(id)snorf];");
+ verifyFormat("[(id)foo bar:(id) ? baz : quux];");
+ verifyFormat("4 > 4 ? (id)a : (id)baz;");
+
+ // This tests that the formatter doesn't break after "backing" but before ":",
+ // which would be at 80 columns.
+ verifyFormat(
+ "void f() {\n"
+ " if ((self = [super initWithContentRect:contentRect\n"
+ " styleMask:styleMask ?: otherMask\n"
+ " backing:NSBackingStoreBuffered\n"
+ " defer:YES]))");
+
+ verifyFormat(
+ "[foo checkThatBreakingAfterColonWorksOk:\n"
+ " [bar ifItDoes:reduceOverallLineLengthLikeInThisCase]];");
+
+ verifyFormat("[myObj short:arg1 // Force line break\n"
+ " longKeyword:arg2 != nil ? arg2 : @\"longKeyword\"\n"
+ " evenLongerKeyword:arg3 ?: @\"evenLongerKeyword\"\n"
+ " error:arg4];");
+ verifyFormat(
+ "void f() {\n"
+ " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n"
+ " initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,\n"
+ " pos.width(), pos.height())\n"
+ " styleMask:NSBorderlessWindowMask\n"
+ " backing:NSBackingStoreBuffered\n"
+ " defer:NO]);\n"
+ "}");
+ verifyFormat("[contentsContainer replaceSubview:[subviews objectAtIndex:0]\n"
+ " with:contentsNativeView];");
+
+ verifyFormat(
+ "[pboard addTypes:[NSArray arrayWithObject:kBookmarkButtonDragType]\n"
+ " owner:nillllll];");
+
+ verifyFormat(
+ "[pboard setData:[NSData dataWithBytes:&button length:sizeof(button)]\n"
+ " forType:kBookmarkButtonDragType];");
+
+ verifyFormat("[defaultCenter addObserver:self\n"
+ " selector:@selector(willEnterFullscreen)\n"
+ " name:kWillEnterFullscreenNotification\n"
+ " object:nil];");
+ verifyFormat("[image_rep drawInRect:drawRect\n"
+ " fromRect:NSZeroRect\n"
+ " operation:NSCompositeCopy\n"
+ " fraction:1.0\n"
+ " respectFlipped:NO\n"
+ " hints:nil];");
+ verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];");
+ verifyFormat("[aaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaa)\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];");
+ verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaa[aaaaaaaaaaaaaaaaaaaaa]\n"
+ " aaaaaaaaaaaaaaaaaaaaaa];");
+
+ verifyFormat(
+ "scoped_nsobject<NSTextField> message(\n"
+ " // The frame will be fixed up when |-setMessageText:| is called.\n"
+ " [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]);");
+ verifyFormat("[self aaaaaa:bbbbbbbbbbbbb\n"
+ " aaaaaaaaaa:bbbbbbbbbbbbbbbbb\n"
+ " aaaaa:bbbbbbbbbbb + bbbbbbbbbbbb\n"
+ " aaaa:bbb];");
+ verifyFormat("[self param:function( //\n"
+ " parameter)]");
+ verifyFormat(
+ "[self aaaaaaaaaa:aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |\n"
+ " aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa |\n"
+ " aaaaaaaaaaaaaaa | aaaaaaaaaaaaaaa];");
+
+ // Variadic parameters.
+ verifyFormat(
+ "NSArray *myStrings = [NSArray stringarray:@\"a\", @\"b\", nil];");
+ verifyFormat(
+ "[self aaaaaaaaaaaaa:aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaa];");
+ verifyFormat("[self // break\n"
+ " a:a\n"
+ " aaa:aaa];");
+ verifyFormat("bool a = ([aaaaaaaa aaaaa] == aaaaaaaaaaaaaaaaa ||\n"
+ " [aaaaaaaa aaaaa] == aaaaaaaaaaaaaaaaaaaa);");
+
+ // Formats pair-parameters.
+ verifyFormat("[I drawRectOn:surface ofSize:aa:bbb atOrigin:cc:dd];");
+ verifyFormat("[I drawRectOn:surface //\n"
+ " ofSize:aa:bbb\n"
+ " atOrigin:cc:dd];");
+
+ Style.ColumnLimit = 70;
+ verifyFormat(
+ "void f() {\n"
+ " popup_wdow_.reset([[RenderWidgetPopupWindow alloc]\n"
+ " iniithContentRect:NSMakRet(origin_global.x, origin_global.y,\n"
+ " pos.width(), pos.height())\n"
+ " syeMask:NSBorderlessWindowMask\n"
+ " bking:NSBackingStoreBuffered\n"
+ " der:NO]);\n"
+ "}");
+
+ Style.ColumnLimit = 60;
+ verifyFormat("[call aaaaaaaa.aaaaaa.aaaaaaaa.aaaaaaaa.aaaaaaaa.aaaaaaaa\n"
+ " .aaaaaaaa];"); // FIXME: Indentation seems off.
+ // FIXME: This violates the column limit.
+ verifyFormat(
+ "[aaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " aaaaaaaaaaaaaaaaa:aaaaaaaa\n"
+ " aaa:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];");
+
+ Style = getChromiumStyle(FormatStyle::LK_ObjC);
+ Style.ColumnLimit = 80;
+ verifyFormat(
+ "void f() {\n"
+ " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n"
+ " initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,\n"
+ " pos.width(), pos.height())\n"
+ " styleMask:NSBorderlessWindowMask\n"
+ " backing:NSBackingStoreBuffered\n"
+ " defer:NO]);\n"
+ "}");
+}
+
+TEST_F(FormatTestObjC, ObjCAt) {
+ verifyFormat("@autoreleasepool");
+ verifyFormat("@catch");
+ verifyFormat("@class");
+ verifyFormat("@compatibility_alias");
+ verifyFormat("@defs");
+ verifyFormat("@dynamic");
+ verifyFormat("@encode");
+ verifyFormat("@end");
+ verifyFormat("@finally");
+ verifyFormat("@implementation");
+ verifyFormat("@import");
+ verifyFormat("@interface");
+ verifyFormat("@optional");
+ verifyFormat("@package");
+ verifyFormat("@private");
+ verifyFormat("@property");
+ verifyFormat("@protected");
+ verifyFormat("@protocol");
+ verifyFormat("@public");
+ verifyFormat("@required");
+ verifyFormat("@selector");
+ verifyFormat("@synchronized");
+ verifyFormat("@synthesize");
+ verifyFormat("@throw");
+ verifyFormat("@try");
+
+ EXPECT_EQ("@interface", format("@ interface"));
+
+ // The precise formatting of this doesn't matter, nobody writes code like
+ // this.
+ verifyFormat("@ /*foo*/ interface");
+}
+
+TEST_F(FormatTestObjC, ObjCSnippets) {
+ verifyFormat("@autoreleasepool {\n"
+ " foo();\n"
+ "}");
+ verifyFormat("@class Foo, Bar;");
+ verifyFormat("@compatibility_alias AliasName ExistingClass;");
+ verifyFormat("@dynamic textColor;");
+ verifyFormat("char *buf1 = @encode(int *);");
+ verifyFormat("char *buf1 = @encode(typeof(4 * 5));");
+ verifyFormat("char *buf1 = @encode(int **);");
+ verifyFormat("Protocol *proto = @protocol(p1);");
+ verifyFormat("SEL s = @selector(foo:);");
+ verifyFormat("@synchronized(self) {\n"
+ " f();\n"
+ "}");
+
+ verifyFormat("@import foo.bar;\n"
+ "@import baz;");
+
+ verifyFormat("@synthesize dropArrowPosition = dropArrowPosition_;");
+
+ verifyFormat("@property(assign, nonatomic) CGFloat hoverAlpha;");
+ verifyFormat("@property(assign, getter=isEditable) BOOL editable;");
+
+ Style = getMozillaStyle();
+ verifyFormat("@property (assign, getter=isEditable) BOOL editable;");
+ verifyFormat("@property BOOL editable;");
+
+ Style = getWebKitStyle();
+ verifyFormat("@property (assign, getter=isEditable) BOOL editable;");
+ verifyFormat("@property BOOL editable;");
+
+ Style = getGoogleStyle(FormatStyle::LK_ObjC);
+ verifyFormat("@synthesize dropArrowPosition = dropArrowPosition_;");
+ verifyFormat("@property(assign, getter=isEditable) BOOL editable;");
+}
+
+TEST_F(FormatTestObjC, ObjCForIn) {
+ verifyFormat("- (void)test {\n"
+ " for (NSString *n in arrayOfStrings) {\n"
+ " foo(n);\n"
+ " }\n"
+ "}");
+ verifyFormat("- (void)test {\n"
+ " for (NSString *n in (__bridge NSArray *)arrayOfStrings) {\n"
+ " foo(n);\n"
+ " }\n"
+ "}");
+}
+
+TEST_F(FormatTestObjC, ObjCLiterals) {
+ verifyFormat("@\"String\"");
+ verifyFormat("@1");
+ verifyFormat("@+4.8");
+ verifyFormat("@-4");
+ verifyFormat("@1LL");
+ verifyFormat("@.5");
+ verifyFormat("@'c'");
+ verifyFormat("@true");
+
+ verifyFormat("NSNumber *smallestInt = @(-INT_MAX - 1);");
+ verifyFormat("NSNumber *piOverTwo = @(M_PI / 2);");
+ verifyFormat("NSNumber *favoriteColor = @(Green);");
+ verifyFormat("NSString *path = @(getenv(\"PATH\"));");
+
+ verifyFormat("[dictionary setObject:@(1) forKey:@\"number\"];");
+}
+
+TEST_F(FormatTestObjC, ObjCDictLiterals) {
+ verifyFormat("@{");
+ verifyFormat("@{}");
+ verifyFormat("@{@\"one\" : @1}");
+ verifyFormat("return @{@\"one\" : @1;");
+ verifyFormat("@{@\"one\" : @1}");
+
+ verifyFormat("@{@\"one\" : @{@2 : @1}}");
+ verifyFormat("@{\n"
+ " @\"one\" : @{@2 : @1},\n"
+ "}");
+
+ verifyFormat("@{1 > 2 ? @\"one\" : @\"two\" : 1 > 2 ? @1 : @2}");
+ verifyIncompleteFormat("[self setDict:@{}");
+ verifyIncompleteFormat("[self setDict:@{@1 : @2}");
+ verifyFormat("NSLog(@\"%@\", @{@1 : @2, @2 : @3}[@1]);");
+ verifyFormat(
+ "NSDictionary *masses = @{@\"H\" : @1.0078, @\"He\" : @4.0026};");
+ verifyFormat(
+ "NSDictionary *settings = @{AVEncoderKey : @(AVAudioQualityMax)};");
+
+ verifyFormat("NSDictionary *d = @{\n"
+ " @\"nam\" : NSUserNam(),\n"
+ " @\"dte\" : [NSDate date],\n"
+ " @\"processInfo\" : [NSProcessInfo processInfo]\n"
+ "};");
+ verifyFormat(
+ "@{\n"
+ " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee : "
+ "regularFont,\n"
+ "};");
+ verifyFormat(
+ "@{\n"
+ " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee :\n"
+ " reeeeeeeeeeeeeeeeeeeeeeeegularFont,\n"
+ "};");
+
+ // We should try to be robust in case someone forgets the "@".
+ verifyFormat("NSDictionary *d = {\n"
+ " @\"nam\" : NSUserNam(),\n"
+ " @\"dte\" : [NSDate date],\n"
+ " @\"processInfo\" : [NSProcessInfo processInfo]\n"
+ "};");
+ verifyFormat("NSMutableDictionary *dictionary =\n"
+ " [NSMutableDictionary dictionaryWithDictionary:@{\n"
+ " aaaaaaaaaaaaaaaaaaaaa : aaaaaaaaaaaaa,\n"
+ " bbbbbbbbbbbbbbbbbb : bbbbb,\n"
+ " cccccccccccccccc : ccccccccccccccc\n"
+ " }];");
+
+ // Ensure that casts before the key are kept on the same line as the key.
+ verifyFormat(
+ "NSDictionary *d = @{\n"
+ " (aaaaaaaa id)aaaaaaaaa : (aaaaaaaa id)aaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " (aaaaaaaa id)aaaaaaaaaaaaaa : (aaaaaaaa id)aaaaaaaaaaaaaa,\n"
+ "};");
+
+ Style = getGoogleStyle(FormatStyle::LK_ObjC);
+ verifyFormat(
+ "@{\n"
+ " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee : "
+ "regularFont,\n"
+ "};");
+}
+
+TEST_F(FormatTestObjC, ObjCArrayLiterals) {
+ verifyIncompleteFormat("@[");
+ verifyFormat("@[]");
+ verifyFormat(
+ "NSArray *array = @[ @\" Hey \", NSApp, [NSNumber numberWithInt:42] ];");
+ verifyFormat("return @[ @3, @[], @[ @4, @5 ] ];");
+ verifyFormat("NSArray *array = @[ [foo description] ];");
+
+ verifyFormat(
+ "NSArray *some_variable = @[\n"
+ " aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ "];");
+ verifyFormat(
+ "NSArray *some_variable = @[\n"
+ " aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaa\", @\"aaaaaaaaaaaaaaaa\", @\"aaaaaaaaaaaaaaaa\"\n"
+ "];");
+ verifyFormat("NSArray *some_variable = @[\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ "];");
+ verifyFormat("NSArray *array = @[\n"
+ " @\"a\",\n"
+ " @\"a\",\n" // Trailing comma -> one per line.
+ "];");
+
+ // We should try to be robust in case someone forgets the "@".
+ verifyFormat("NSArray *some_variable = [\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ "];");
+ verifyFormat(
+ "- (NSAttributedString *)attributedStringForSegment:(NSUInteger)segment\n"
+ " index:(NSUInteger)index\n"
+ " nonDigitAttributes:\n"
+ " (NSDictionary *)noDigitAttributes;");
+ verifyFormat("[someFunction someLooooooooooooongParameter:@[\n"
+ " NSBundle.mainBundle.infoDictionary[@\"a\"]\n"
+ "]];");
+}
+} // end namespace
+} // end namespace format
+} // end namespace clang
diff --git a/unittests/Format/SortImportsTestJS.cpp b/unittests/Format/SortImportsTestJS.cpp
index 77c37e337ddf..7e766e1969e1 100644
--- a/unittests/Format/SortImportsTestJS.cpp
+++ b/unittests/Format/SortImportsTestJS.cpp
@@ -70,6 +70,26 @@ TEST_F(SortImportsTestJS, BasicSorting) {
"let x = 1;");
}
+TEST_F(SortImportsTestJS, DefaultBinding) {
+ verifySort("import A from 'a';\n"
+ "import B from 'b';\n"
+ "\n"
+ "let x = 1;",
+ "import B from 'b';\n"
+ "import A from 'a';\n"
+ "let x = 1;");
+}
+
+TEST_F(SortImportsTestJS, DefaultAndNamedBinding) {
+ verifySort("import A, {a} from 'a';\n"
+ "import B, {b} from 'b';\n"
+ "\n"
+ "let x = 1;",
+ "import B, {b} from 'b';\n"
+ "import A, {a} from 'a';\n"
+ "let x = 1;");
+}
+
TEST_F(SortImportsTestJS, WrappedImportStatements) {
verifySort("import {sym1, sym2} from 'a';\n"
"import {sym} from 'b';\n"
@@ -101,6 +121,16 @@ TEST_F(SortImportsTestJS, Comments) {
"import {sym} from 'b'; // from //foo:bar\n"
"// A very important import follows.\n"
"import {sym} from 'a'; /* more comments */\n");
+ verifySort("import {sym} from 'a';\n"
+ "import {sym} from 'b';\n"
+ "\n"
+ "/** Comment on variable. */\n"
+ "const x = 1;\n",
+ "import {sym} from 'b';\n"
+ "import {sym} from 'a';\n"
+ "\n"
+ "/** Comment on variable. */\n"
+ "const x = 1;\n");
}
TEST_F(SortImportsTestJS, SortStar) {
@@ -190,40 +220,29 @@ TEST_F(SortImportsTestJS, SideEffectImports) {
}
TEST_F(SortImportsTestJS, AffectedRange) {
- // Sort excluding a suffix.
- verifySort("import {sym} from 'b';\n"
+ // Affected range inside of import statements.
+ verifySort("import {sym} from 'a';\n"
+ "import {sym} from 'b';\n"
"import {sym} from 'c';\n"
- "import {sym} from 'a';\n"
+ "\n"
"let x = 1;",
"import {sym} from 'c';\n"
"import {sym} from 'b';\n"
"import {sym} from 'a';\n"
"let x = 1;",
0, 30);
- // Sort excluding a prefix.
+ // Affected range outside of import statements.
verifySort("import {sym} from 'c';\n"
- "import {sym} from 'a';\n"
- "import {sym} from 'b';\n"
- "\n"
- "let x = 1;",
- "import {sym} from 'c';\n"
"import {sym} from 'b';\n"
"import {sym} from 'a';\n"
"\n"
"let x = 1;",
- 30, 0);
- // Sort a range within imports.
- verifySort("import {sym} from 'c';\n"
- "import {sym} from 'a';\n"
- "import {sym} from 'b';\n"
- "import {sym} from 'c';\n"
- "let x = 1;",
"import {sym} from 'c';\n"
"import {sym} from 'b';\n"
"import {sym} from 'a';\n"
- "import {sym} from 'c';\n"
+ "\n"
"let x = 1;",
- 24, 30);
+ 70, 1);
}
TEST_F(SortImportsTestJS, SortingCanShrink) {
diff --git a/unittests/Format/SortIncludesTest.cpp b/unittests/Format/SortIncludesTest.cpp
index 13a1b9adeeec..c3c56a813041 100644
--- a/unittests/Format/SortIncludesTest.cpp
+++ b/unittests/Format/SortIncludesTest.cpp
@@ -24,10 +24,11 @@ protected:
return std::vector<tooling::Range>(1, tooling::Range(0, Code.size()));
}
- std::string sort(StringRef Code, StringRef FileName = "input.cpp") {
- auto Ranges = GetCodeRange(Code);
- auto Sorted =
- applyAllReplacements(Code, sortIncludes(Style, Code, Ranges, FileName));
+ std::string sort(StringRef Code, std::vector<tooling::Range> Ranges,
+ StringRef FileName = "input.cc") {
+ auto Replaces = sortIncludes(Style, Code, Ranges, FileName);
+ Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges);
+ auto Sorted = applyAllReplacements(Code, Replaces);
EXPECT_TRUE(static_cast<bool>(Sorted));
auto Result = applyAllReplacements(
*Sorted, reformat(Style, *Sorted, Ranges, FileName));
@@ -35,6 +36,10 @@ protected:
return *Result;
}
+ std::string sort(StringRef Code, StringRef FileName = "input.cpp") {
+ return sort(Code, GetCodeRange(Code), FileName);
+ }
+
unsigned newCursor(llvm::StringRef Code, unsigned Cursor) {
sortIncludes(Style, Code, GetCodeRange(Code), "input.cpp", &Cursor);
return Cursor;
@@ -51,16 +56,24 @@ TEST_F(SortIncludesTest, BasicSorting) {
sort("#include \"a.h\"\n"
"#include \"c.h\"\n"
"#include \"b.h\"\n"));
+
+ EXPECT_EQ("// comment\n"
+ "#include <a>\n"
+ "#include <b>\n",
+ sort("// comment\n"
+ "#include <b>\n"
+ "#include <a>\n",
+ {tooling::Range(25, 1)}));
}
TEST_F(SortIncludesTest, NoReplacementsForValidIncludes) {
// Identical #includes have led to a failure with an unstable sort.
std::string Code = "#include <a>\n"
"#include <b>\n"
- "#include <b>\n"
- "#include <b>\n"
- "#include <b>\n"
- "#include <c>\n";
+ "#include <c>\n"
+ "#include <d>\n"
+ "#include <e>\n"
+ "#include <f>\n";
EXPECT_TRUE(sortIncludes(Style, Code, GetCodeRange(Code), "a.cc").empty());
}
@@ -286,6 +299,82 @@ TEST_F(SortIncludesTest, CalculatesCorrectCursorPosition) {
EXPECT_EQ(10u, newCursor(Code, 43));
}
+TEST_F(SortIncludesTest, DeduplicateIncludes) {
+ EXPECT_EQ("#include <a>\n"
+ "#include <b>\n"
+ "#include <c>\n",
+ sort("#include <a>\n"
+ "#include <b>\n"
+ "#include <b>\n"
+ "#include <b>\n"
+ "#include <b>\n"
+ "#include <c>\n"));
+}
+
+TEST_F(SortIncludesTest, SortAndDeduplicateIncludes) {
+ EXPECT_EQ("#include <a>\n"
+ "#include <b>\n"
+ "#include <c>\n",
+ sort("#include <b>\n"
+ "#include <a>\n"
+ "#include <b>\n"
+ "#include <b>\n"
+ "#include <c>\n"
+ "#include <b>\n"));
+}
+
+TEST_F(SortIncludesTest, CalculatesCorrectCursorPositionAfterDeduplicate) {
+ std::string Code = "#include <b>\n" // Start of line: 0
+ "#include <a>\n" // Start of line: 13
+ "#include <b>\n" // Start of line: 26
+ "#include <b>\n" // Start of line: 39
+ "#include <c>\n" // Start of line: 52
+ "#include <b>\n"; // Start of line: 65
+ std::string Expected = "#include <a>\n" // Start of line: 0
+ "#include <b>\n" // Start of line: 13
+ "#include <c>\n"; // Start of line: 26
+ EXPECT_EQ(Expected, sort(Code));
+ // Cursor on 'i' in "#include <a>".
+ EXPECT_EQ(1u, newCursor(Code, 14));
+ // Cursor on 'b' in "#include <b>".
+ EXPECT_EQ(23u, newCursor(Code, 10));
+ EXPECT_EQ(23u, newCursor(Code, 36));
+ EXPECT_EQ(23u, newCursor(Code, 49));
+ EXPECT_EQ(23u, newCursor(Code, 36));
+ EXPECT_EQ(23u, newCursor(Code, 75));
+ // Cursor on '#' in "#include <c>".
+ EXPECT_EQ(26u, newCursor(Code, 52));
+}
+
+TEST_F(SortIncludesTest, DeduplicateLocallyInEachBlock) {
+ EXPECT_EQ("#include <a>\n"
+ "#include <b>\n"
+ "\n"
+ "#include <b>\n"
+ "#include <c>\n",
+ sort("#include <a>\n"
+ "#include <b>\n"
+ "\n"
+ "#include <c>\n"
+ "#include <b>\n"
+ "#include <b>\n"));
+}
+
+TEST_F(SortIncludesTest, ValidAffactedRangesAfterDeduplicatingIncludes) {
+ std::string Code = "#include <a>\n"
+ "#include <b>\n"
+ "#include <a>\n"
+ "#include <a>\n"
+ "\n"
+ " int x ;";
+ std::vector<tooling::Range> Ranges = {tooling::Range(0, 52)};
+ auto Replaces = sortIncludes(Style, Code, Ranges, "input.cpp");
+ Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges);
+ EXPECT_EQ(1u, Ranges.size());
+ EXPECT_EQ(0u, Ranges[0].getOffset());
+ EXPECT_EQ(26u, Ranges[0].getLength());
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
diff --git a/unittests/Frontend/CodeGenActionTest.cpp b/unittests/Frontend/CodeGenActionTest.cpp
index 71446fd4d79d..356b5130fcbe 100644
--- a/unittests/Frontend/CodeGenActionTest.cpp
+++ b/unittests/Frontend/CodeGenActionTest.cpp
@@ -11,9 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/CodeGen/CodeGenAction.h"
#include "clang/CodeGen/BackendUtil.h"
+#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "gtest/gtest.h"
using namespace llvm;
diff --git a/unittests/Frontend/FrontendActionTest.cpp b/unittests/Frontend/FrontendActionTest.cpp
index 90afd774f1ad..c3e6adb6324d 100644
--- a/unittests/Frontend/FrontendActionTest.cpp
+++ b/unittests/Frontend/FrontendActionTest.cpp
@@ -7,13 +7,15 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/FrontendAction.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/FrontendActions.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -191,4 +193,66 @@ TEST(PreprocessorFrontendAction, EndSourceFile) {
ASSERT_TRUE(TestAction.SeenEnd);
}
+class TypoExternalSemaSource : public ExternalSemaSource {
+ CompilerInstance &CI;
+
+public:
+ TypoExternalSemaSource(CompilerInstance &CI) : CI(CI) {}
+
+ TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, int LookupKind,
+ Scope *S, CXXScopeSpec *SS,
+ CorrectionCandidateCallback &CCC,
+ DeclContext *MemberContext, bool EnteringContext,
+ const ObjCObjectPointerType *OPT) override {
+ // Generate a fake typo correction with one attached note.
+ ASTContext &Ctx = CI.getASTContext();
+ TypoCorrection TC(DeclarationName(&Ctx.Idents.get("moo")));
+ unsigned DiagID = Ctx.getDiagnostics().getCustomDiagID(
+ DiagnosticsEngine::Note, "This is a note");
+ TC.addExtraDiagnostic(PartialDiagnostic(DiagID, Ctx.getDiagAllocator()));
+ return TC;
+ }
+};
+
+struct TypoDiagnosticConsumer : public DiagnosticConsumer {
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) override {
+ // Capture errors and notes. There should be one of each.
+ if (DiagLevel == DiagnosticsEngine::Error) {
+ assert(Error.empty());
+ Info.FormatDiagnostic(Error);
+ } else {
+ assert(Note.empty());
+ Info.FormatDiagnostic(Note);
+ }
+ }
+ SmallString<32> Error;
+ SmallString<32> Note;
+};
+
+TEST(ASTFrontendAction, ExternalSemaSource) {
+ auto *Invocation = new CompilerInvocation;
+ Invocation->getLangOpts()->CPlusPlus = true;
+ Invocation->getPreprocessorOpts().addRemappedFile(
+ "test.cc", MemoryBuffer::getMemBuffer("void fooo();\n"
+ "int main() { foo(); }")
+ .release());
+ Invocation->getFrontendOpts().Inputs.push_back(
+ FrontendInputFile("test.cc", IK_CXX));
+ Invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
+ Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
+ CompilerInstance Compiler;
+ Compiler.setInvocation(Invocation);
+ auto *TDC = new TypoDiagnosticConsumer;
+ Compiler.createDiagnostics(TDC, /*ShouldOwnClient=*/true);
+ Compiler.setExternalSemaSource(new TypoExternalSemaSource(Compiler));
+
+ SyntaxOnlyAction TestAction;
+ ASSERT_TRUE(Compiler.ExecuteAction(TestAction));
+ // There should be one error correcting to 'moo' and a note attached to it.
+ EXPECT_EQ("use of undeclared identifier 'foo'; did you mean 'moo'?",
+ TDC->Error.str().str());
+ EXPECT_EQ("This is a note", TDC->Note.str().str());
+}
+
} // anonymous namespace
diff --git a/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp b/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp
index 33f1740bea8a..891c88da302e 100644
--- a/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp
+++ b/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp
@@ -14,6 +14,23 @@
namespace clang {
namespace ento {
+TEST(StaticAnalyzerOptions, getRegisteredCheckers) {
+ auto IsDebugChecker = [](StringRef CheckerName) {
+ return CheckerName.startswith("debug");
+ };
+ auto IsAlphaChecker = [](StringRef CheckerName) {
+ return CheckerName.startswith("alpha");
+ };
+ const auto &AllCheckers =
+ AnalyzerOptions::getRegisteredCheckers(/*IncludeExperimental=*/true);
+ EXPECT_FALSE(llvm::any_of(AllCheckers, IsDebugChecker));
+ EXPECT_TRUE(llvm::any_of(AllCheckers, IsAlphaChecker));
+
+ const auto &StableCheckers = AnalyzerOptions::getRegisteredCheckers();
+ EXPECT_FALSE(llvm::any_of(StableCheckers, IsDebugChecker));
+ EXPECT_FALSE(llvm::any_of(StableCheckers, IsAlphaChecker));
+}
+
TEST(StaticAnalyzerOptions, SearchInParentPackageTests) {
AnalyzerOptions Opts;
Opts.Config["Outer.Inner.CheckerOne:Option"] = "true";
diff --git a/unittests/Tooling/CMakeLists.txt b/unittests/Tooling/CMakeLists.txt
index b4b3f404e270..185f43b6a8c5 100644
--- a/unittests/Tooling/CMakeLists.txt
+++ b/unittests/Tooling/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
# By default MSVC has a 2^16 limit on the number of sections in an object file,
# and this needs more than that.
if (MSVC)
+ set_source_files_properties(RecursiveASTVisitorTest.cpp PROPERTIES COMPILE_FLAGS /bigobj)
set_source_files_properties(RecursiveASTVisitorTestExprVisitor.cpp PROPERTIES COMPILE_FLAGS /bigobj)
endif()
diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp
index 380d86fc5660..1a6fffec9392 100644
--- a/unittests/Tooling/CompilationDatabaseTest.cpp
+++ b/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -7,7 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Frontend/FrontendAction.h"
@@ -22,9 +21,10 @@ namespace tooling {
static void expectFailure(StringRef JSONDatabase, StringRef Explanation) {
std::string ErrorMessage;
- EXPECT_EQ(nullptr, JSONCompilationDatabase::loadFromBuffer(JSONDatabase,
- ErrorMessage))
- << "Expected an error because of: " << Explanation.str();
+ EXPECT_EQ(nullptr,
+ JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
+ JSONCommandLineSyntax::Gnu))
+ << "Expected an error because of: " << Explanation.str();
}
TEST(JSONCompilationDatabase, ErrsOnInvalidFormat) {
@@ -44,12 +44,15 @@ TEST(JSONCompilationDatabase, ErrsOnInvalidFormat) {
expectFailure("[{\"directory\":\"\",\"command\":[],\"file\":\"\"}]", "Command not string");
expectFailure("[{\"directory\":\"\",\"arguments\":[[]],\"file\":\"\"}]",
"Arguments contain non-string");
+ expectFailure("[{\"output\":[]}]", "Expected strings as value.");
}
static std::vector<std::string> getAllFiles(StringRef JSONDatabase,
- std::string &ErrorMessage) {
+ std::string &ErrorMessage,
+ JSONCommandLineSyntax Syntax) {
std::unique_ptr<CompilationDatabase> Database(
- JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
+ JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
+ Syntax));
if (!Database) {
ADD_FAILURE() << ErrorMessage;
return std::vector<std::string>();
@@ -57,10 +60,12 @@ static std::vector<std::string> getAllFiles(StringRef JSONDatabase,
return Database->getAllFiles();
}
-static std::vector<CompileCommand> getAllCompileCommands(StringRef JSONDatabase,
- std::string &ErrorMessage) {
+static std::vector<CompileCommand>
+getAllCompileCommands(JSONCommandLineSyntax Syntax, StringRef JSONDatabase,
+ std::string &ErrorMessage) {
std::unique_ptr<CompilationDatabase> Database(
- JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
+ JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
+ Syntax));
if (!Database) {
ADD_FAILURE() << ErrorMessage;
return std::vector<CompileCommand>();
@@ -71,7 +76,8 @@ static std::vector<CompileCommand> getAllCompileCommands(StringRef JSONDatabase,
TEST(JSONCompilationDatabase, GetAllFiles) {
std::string ErrorMessage;
EXPECT_EQ(std::vector<std::string>(),
- getAllFiles("[]", ErrorMessage)) << ErrorMessage;
+ getAllFiles("[]", ErrorMessage, JSONCommandLineSyntax::Gnu))
+ << ErrorMessage;
std::vector<std::string> expected_files;
SmallString<16> PathStorage;
@@ -79,54 +85,70 @@ TEST(JSONCompilationDatabase, GetAllFiles) {
expected_files.push_back(PathStorage.str());
llvm::sys::path::native("//net/dir/file2", PathStorage);
expected_files.push_back(PathStorage.str());
- EXPECT_EQ(expected_files, getAllFiles(
- "[{\"directory\":\"//net/dir\","
- "\"command\":\"command\","
- "\"file\":\"file1\"},"
- " {\"directory\":\"//net/dir\","
- "\"command\":\"command\","
- "\"file\":\"file2\"}]",
- ErrorMessage)) << ErrorMessage;
+ EXPECT_EQ(expected_files,
+ getAllFiles("[{\"directory\":\"//net/dir\","
+ "\"command\":\"command\","
+ "\"file\":\"file1\"},"
+ " {\"directory\":\"//net/dir\","
+ "\"command\":\"command\","
+ "\"file\":\"file2\"}]",
+ ErrorMessage, JSONCommandLineSyntax::Gnu))
+ << ErrorMessage;
}
TEST(JSONCompilationDatabase, GetAllCompileCommands) {
std::string ErrorMessage;
- EXPECT_EQ(0u,
- getAllCompileCommands("[]", ErrorMessage).size()) << ErrorMessage;
+ EXPECT_EQ(
+ 0u, getAllCompileCommands(JSONCommandLineSyntax::Gnu, "[]", ErrorMessage)
+ .size())
+ << ErrorMessage;
StringRef Directory1("//net/dir1");
StringRef FileName1("file1");
StringRef Command1("command1");
+ StringRef Output1("file1.o");
StringRef Directory2("//net/dir2");
StringRef FileName2("file2");
StringRef Command2("command2");
+ StringRef Output2("");
std::vector<CompileCommand> Commands = getAllCompileCommands(
- ("[{\"directory\":\"" + Directory1 + "\"," +
- "\"command\":\"" + Command1 + "\","
- "\"file\":\"" + FileName1 + "\"},"
- " {\"directory\":\"" + Directory2 + "\"," +
- "\"command\":\"" + Command2 + "\","
- "\"file\":\"" + FileName2 + "\"}]").str(),
+ JSONCommandLineSyntax::Gnu,
+ ("[{\"directory\":\"" + Directory1 + "\"," + "\"command\":\"" + Command1 +
+ "\","
+ "\"file\":\"" +
+ FileName1 + "\", \"output\":\"" +
+ Output1 + "\"},"
+ " {\"directory\":\"" +
+ Directory2 + "\"," + "\"command\":\"" + Command2 + "\","
+ "\"file\":\"" +
+ FileName2 + "\"}]")
+ .str(),
ErrorMessage);
EXPECT_EQ(2U, Commands.size()) << ErrorMessage;
EXPECT_EQ(Directory1, Commands[0].Directory) << ErrorMessage;
EXPECT_EQ(FileName1, Commands[0].Filename) << ErrorMessage;
+ EXPECT_EQ(Output1, Commands[0].Output) << ErrorMessage;
ASSERT_EQ(1u, Commands[0].CommandLine.size());
EXPECT_EQ(Command1, Commands[0].CommandLine[0]) << ErrorMessage;
EXPECT_EQ(Directory2, Commands[1].Directory) << ErrorMessage;
EXPECT_EQ(FileName2, Commands[1].Filename) << ErrorMessage;
+ EXPECT_EQ(Output2, Commands[1].Output) << ErrorMessage;
ASSERT_EQ(1u, Commands[1].CommandLine.size());
EXPECT_EQ(Command2, Commands[1].CommandLine[0]) << ErrorMessage;
// Check that order is preserved.
Commands = getAllCompileCommands(
- ("[{\"directory\":\"" + Directory2 + "\"," +
- "\"command\":\"" + Command2 + "\","
- "\"file\":\"" + FileName2 + "\"},"
- " {\"directory\":\"" + Directory1 + "\"," +
- "\"command\":\"" + Command1 + "\","
- "\"file\":\"" + FileName1 + "\"}]").str(),
+ JSONCommandLineSyntax::Gnu,
+ ("[{\"directory\":\"" + Directory2 + "\"," + "\"command\":\"" + Command2 +
+ "\","
+ "\"file\":\"" +
+ FileName2 + "\"},"
+ " {\"directory\":\"" +
+ Directory1 + "\"," + "\"command\":\"" + Command1 + "\","
+ "\"file\":\"" +
+ FileName1 + "\"}]")
+ .str(),
ErrorMessage);
EXPECT_EQ(2U, Commands.size()) << ErrorMessage;
EXPECT_EQ(Directory2, Commands[0].Directory) << ErrorMessage;
@@ -143,7 +165,8 @@ static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName,
StringRef JSONDatabase,
std::string &ErrorMessage) {
std::unique_ptr<CompilationDatabase> Database(
- JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
+ JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
+ JSONCommandLineSyntax::Gnu));
if (!Database)
return CompileCommand();
std::vector<CompileCommand> Commands = Database->getCompileCommands(FileName);
diff --git a/unittests/Tooling/LookupTest.cpp b/unittests/Tooling/LookupTest.cpp
index d847a298fff2..cc3922d01b51 100644
--- a/unittests/Tooling/LookupTest.cpp
+++ b/unittests/Tooling/LookupTest.cpp
@@ -14,10 +14,18 @@ using namespace clang;
namespace {
struct GetDeclsVisitor : TestVisitor<GetDeclsVisitor> {
std::function<void(CallExpr *)> OnCall;
+ std::function<void(RecordTypeLoc)> OnRecordTypeLoc;
SmallVector<Decl *, 4> DeclStack;
bool VisitCallExpr(CallExpr *Expr) {
- OnCall(Expr);
+ if (OnCall)
+ OnCall(Expr);
+ return true;
+ }
+
+ bool VisitRecordTypeLoc(RecordTypeLoc Loc) {
+ if (OnRecordTypeLoc)
+ OnRecordTypeLoc(Loc);
return true;
}
@@ -29,7 +37,7 @@ struct GetDeclsVisitor : TestVisitor<GetDeclsVisitor> {
}
};
-TEST(LookupTest, replaceNestedName) {
+TEST(LookupTest, replaceNestedFunctionName) {
GetDeclsVisitor Visitor;
auto replaceCallExpr = [&](const CallExpr *Expr,
@@ -103,6 +111,55 @@ TEST(LookupTest, replaceNestedName) {
};
Visitor.runOver(
"namespace a { int foo(); }\nusing a::foo;\nauto f = foo();\n");
+
+ Visitor.OnCall = [&](CallExpr *Expr) {
+ EXPECT_EQ("c::bar", replaceCallExpr(Expr, "::a::c::bar"));
+ };
+ Visitor.runOver("namespace a { namespace b { void foo(); } }\n"
+ "namespace a { namespace b { namespace {"
+ "void f() { foo(); }"
+ "} } }\n");
+
+ Visitor.OnCall = [&](CallExpr *Expr) {
+ EXPECT_EQ("x::bar", replaceCallExpr(Expr, "::a::x::bar"));
+ };
+ Visitor.runOver("namespace a { namespace b { void foo(); } }\n"
+ "namespace a { namespace b { namespace c {"
+ "void f() { foo(); }"
+ "} } }\n");
+}
+
+TEST(LookupTest, replaceNestedClassName) {
+ GetDeclsVisitor Visitor;
+
+ auto replaceRecordTypeLoc = [&](RecordTypeLoc Loc,
+ StringRef ReplacementString) {
+ const auto *FD = cast<CXXRecordDecl>(Loc.getDecl());
+ return tooling::replaceNestedName(
+ nullptr, Visitor.DeclStack.back()->getDeclContext(), FD,
+ ReplacementString);
+ };
+
+ Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) {
+ // Filter Types by name since there are other `RecordTypeLoc` in the test
+ // file.
+ if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo")
+ EXPECT_EQ("x::Bar", replaceRecordTypeLoc(Type, "::a::x::Bar"));
+ };
+ Visitor.runOver("namespace a { namespace b {\n"
+ "class Foo;\n"
+ "namespace c { Foo f();; }\n"
+ "} }\n");
+
+ Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) {
+ // Filter Types by name since there are other `RecordTypeLoc` in the test
+ // file.
+ // `a::b::Foo` in using shadow decl is not `TypeLoc`.
+ if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo")
+ EXPECT_EQ("Bar", replaceRecordTypeLoc(Type, "::a::x::Bar"));
+ };
+ Visitor.runOver("namespace a { namespace b { class Foo {}; } }\n"
+ "namespace c { using a::b::Foo; Foo f();; }\n");
}
} // end anonymous namespace
diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp
index 991ae8bb7f3d..7e08f9619c1c 100644
--- a/unittests/Tooling/RecursiveASTVisitorTest.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp
@@ -133,23 +133,21 @@ TEST(RecursiveASTVisitor, AttributesAreVisited) {
"};\n"));
}
-// Check to ensure that VarDecls are visited.
-class VarDeclVisitor : public ExpectedLocationVisitor<VarDeclVisitor> {
+// Check to ensure that implicit default argument expressions are visited.
+class IntegerLiteralVisitor
+ : public ExpectedLocationVisitor<IntegerLiteralVisitor> {
public:
- bool VisitVarDecl(VarDecl *VD) {
- Match(VD->getNameAsString(), VD->getLocStart());
+ bool VisitIntegerLiteral(const IntegerLiteral *IL) {
+ Match("literal", IL->getLocation());
return true;
}
};
-TEST(RecursiveASTVisitor, ArrayInitializersAreVisited) {
- VarDeclVisitor Visitor;
- Visitor.ExpectMatch("__i0", 1, 8);
- EXPECT_TRUE(
- Visitor.runOver("struct MyClass {\n"
- " int c[1];\n"
- " static MyClass Create() { return MyClass(); }\n"
- "};\n"));
+TEST(RecursiveASTVisitor, DefaultArgumentsAreVisited) {
+ IntegerLiteralVisitor Visitor;
+ Visitor.ExpectMatch("literal", 1, 15, 2);
+ EXPECT_TRUE(Visitor.runOver("int f(int i = 1);\n"
+ "static int k = f();\n"));
}
} // end anonymous namespace
diff --git a/unittests/Tooling/RecursiveASTVisitorTestCallVisitor.cpp b/unittests/Tooling/RecursiveASTVisitorTestCallVisitor.cpp
index f8ff5bdc7879..b981585450e1 100644
--- a/unittests/Tooling/RecursiveASTVisitorTestCallVisitor.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTestCallVisitor.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "TestVisitor.h"
-#include <stack>
using namespace clang;
diff --git a/unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp b/unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp
index 02676a737ab1..63bfb8b2e6c1 100644
--- a/unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "TestVisitor.h"
-#include <stack>
using namespace clang;
diff --git a/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp b/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
index 6af5906c3fd4..5f1dd65222ba 100644
--- a/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "TestVisitor.h"
-#include <stack>
using namespace clang;
@@ -162,10 +161,21 @@ TEST(RecursiveASTVisitor, CanSkipImplicitMemberInitializations) {
class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> {
public:
+ DeclRefExprVisitor() : ShouldVisitImplicitCode(false) {}
+
+ bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
+
+ void setShouldVisitImplicitCode(bool NewValue) {
+ ShouldVisitImplicitCode = NewValue;
+ }
+
bool VisitDeclRefExpr(DeclRefExpr *Reference) {
Match(Reference->getNameInfo().getAsString(), Reference->getLocation());
return true;
}
+
+private:
+ bool ShouldVisitImplicitCode;
};
TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
@@ -192,6 +202,43 @@ TEST(RecursiveASTVisitor, VisitsCallExpr) {
"void x(); void y() { x(); }"));
}
+TEST(RecursiveASTVisitor, VisitsExplicitLambdaCaptureInit) {
+ DeclRefExprVisitor Visitor;
+ Visitor.ExpectMatch("i", 1, 20);
+ EXPECT_TRUE(Visitor.runOver(
+ "void f() { int i; [i]{}; }",
+ DeclRefExprVisitor::Lang_CXX11));
+}
+
+TEST(RecursiveASTVisitor, VisitsUseOfImplicitLambdaCapture) {
+ DeclRefExprVisitor Visitor;
+ Visitor.ExpectMatch("i", 1, 24);
+ EXPECT_TRUE(Visitor.runOver(
+ "void f() { int i; [=]{ i; }; }",
+ DeclRefExprVisitor::Lang_CXX11));
+}
+
+TEST(RecursiveASTVisitor, VisitsImplicitLambdaCaptureInit) {
+ DeclRefExprVisitor Visitor;
+ Visitor.setShouldVisitImplicitCode(true);
+ // We're expecting the "i" in the lambda to be visited twice:
+ // - Once for the DeclRefExpr in the lambda capture initialization (whose
+ // source code location is set to the first use of the variable).
+ // - Once for the DeclRefExpr for the use of "i" inside the lambda.
+ Visitor.ExpectMatch("i", 1, 24, /*Times=*/2);
+ EXPECT_TRUE(Visitor.runOver(
+ "void f() { int i; [=]{ i; }; }",
+ DeclRefExprVisitor::Lang_CXX11));
+}
+
+TEST(RecursiveASTVisitor, VisitsLambdaInitCaptureInit) {
+ DeclRefExprVisitor Visitor;
+ Visitor.ExpectMatch("i", 1, 24);
+ EXPECT_TRUE(Visitor.runOver(
+ "void f() { int i; [a = i + 1]{}; }",
+ DeclRefExprVisitor::Lang_CXX14));
+}
+
/* FIXME: According to Richard Smith this is a bug in the AST.
TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
DeclRefExprVisitor Visitor;
diff --git a/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp b/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp
index 63e2e8b6024c..dc2adaf4da0c 100644
--- a/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "TestVisitor.h"
-#include <stack>
using namespace clang;
diff --git a/unittests/Tooling/RefactoringTest.cpp b/unittests/Tooling/RefactoringTest.cpp
index df96bb159dea..c29f8d7d7123 100644
--- a/unittests/Tooling/RefactoringTest.cpp
+++ b/unittests/Tooling/RefactoringTest.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "ReplacementTest.h"
#include "RewriterTestContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -18,6 +19,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/VirtualFileSystem.h"
#include "clang/Format/Format.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
@@ -26,22 +28,11 @@
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/Path.h"
#include "gtest/gtest.h"
namespace clang {
namespace tooling {
-class ReplacementTest : public ::testing::Test {
- protected:
- Replacement createReplacement(SourceLocation Start, unsigned Length,
- llvm::StringRef ReplacementText) {
- return Replacement(Context.Sources, Start, Length, ReplacementText);
- }
-
- RewriterTestContext Context;
-};
-
TEST_F(ReplacementTest, CanDeleteAllText) {
FileID ID = Context.createInMemoryFile("input.cpp", "text");
SourceLocation Location = Context.getLocation(ID, 1, 1);
@@ -109,62 +100,412 @@ TEST_F(ReplacementTest, ReturnsInvalidPath) {
EXPECT_TRUE(Replace2.getFilePath().empty());
}
+// Checks that an llvm::Error instance contains a ReplacementError with expected
+// error code, expected new replacement, and expected existing replacement.
+static bool checkReplacementError(
+ llvm::Error&& Error, replacement_error ExpectedErr,
+ llvm::Optional<Replacement> ExpectedExisting,
+ llvm::Optional<Replacement> ExpectedNew) {
+ if (!Error) {
+ llvm::errs() << "Error is a success.";
+ return false;
+ }
+ std::string ErrorMessage;
+ llvm::raw_string_ostream OS(ErrorMessage);
+ llvm::handleAllErrors(std::move(Error), [&](const ReplacementError &RE) {
+ llvm::errs() << "Handling error...\n";
+ if (ExpectedErr != RE.get())
+ OS << "Unexpected error code: " << int(RE.get()) << "\n";
+ if (ExpectedExisting != RE.getExistingReplacement()) {
+ OS << "Expected Existing != Actual Existing.\n";
+ if (ExpectedExisting.hasValue())
+ OS << "Expected existing replacement: " << ExpectedExisting->toString()
+ << "\n";
+ if (RE.getExistingReplacement().hasValue())
+ OS << "Actual existing replacement: "
+ << RE.getExistingReplacement()->toString() << "\n";
+ }
+ if (ExpectedNew != RE.getNewReplacement()) {
+ OS << "Expected New != Actual New.\n";
+ if (ExpectedNew.hasValue())
+ OS << "Expected new replacement: " << ExpectedNew->toString() << "\n";
+ if (RE.getNewReplacement().hasValue())
+ OS << "Actual new replacement: " << RE.getNewReplacement()->toString()
+ << "\n";
+ }
+ });
+ OS.flush();
+ if (ErrorMessage.empty()) return true;
+ llvm::errs() << ErrorMessage;
+ return false;
+}
+
+TEST_F(ReplacementTest, FailAddReplacements) {
+ Replacements Replaces;
+ Replacement Deletion("x.cc", 0, 10, "3");
+ auto Err = Replaces.add(Deletion);
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ Replacement OverlappingReplacement("x.cc", 0, 2, "a");
+ Err = Replaces.add(OverlappingReplacement);
+ EXPECT_TRUE(checkReplacementError(std::move(Err),
+ replacement_error::overlap_conflict,
+ Deletion, OverlappingReplacement));
+
+ Replacement ContainedReplacement("x.cc", 2, 2, "a");
+ Err = Replaces.add(Replacement(ContainedReplacement));
+ EXPECT_TRUE(checkReplacementError(std::move(Err),
+ replacement_error::overlap_conflict,
+ Deletion, ContainedReplacement));
+
+ Replacement WrongPathReplacement("y.cc", 20, 2, "");
+ Err = Replaces.add(WrongPathReplacement);
+ EXPECT_TRUE(checkReplacementError(std::move(Err),
+ replacement_error::wrong_file_path,
+ Deletion, WrongPathReplacement));
+
+ EXPECT_EQ(1u, Replaces.size());
+ EXPECT_EQ(Deletion, *Replaces.begin());
+}
+
+TEST_F(ReplacementTest, DeletionInReplacements) {
+ Replacements Replaces;
+ Replacement R("x.cc", 0, 10, "3");
+ auto Err = Replaces.add(R);
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 2, 2, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ EXPECT_EQ(1u, Replaces.size());
+ EXPECT_EQ(R, *Replaces.begin());
+}
+
+TEST_F(ReplacementTest, OverlappingReplacements) {
+ Replacements Replaces;
+ auto Err = Replaces.add(Replacement("x.cc", 0, 3, "345"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 2, 3, "543"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ EXPECT_EQ(1u, Replaces.size());
+ EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin());
+
+ Err = Replaces.add(Replacement("x.cc", 2, 1, "5"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ EXPECT_EQ(1u, Replaces.size());
+ EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin());
+}
+
+TEST_F(ReplacementTest, AddAdjacentInsertionAndReplacement) {
+ Replacements Replaces;
+ // Test adding an insertion at the offset of an existing replacement.
+ auto Err = Replaces.add(Replacement("x.cc", 10, 3, "replace"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 10, 0, "insert"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ EXPECT_EQ(Replaces.size(), 2u);
+
+ Replaces.clear();
+ // Test overlap with an existing insertion.
+ Err = Replaces.add(Replacement("x.cc", 10, 0, "insert"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 10, 3, "replace"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ EXPECT_EQ(Replaces.size(), 2u);
+}
+
+TEST_F(ReplacementTest, MergeNewDeletions) {
+ Replacements Replaces;
+ Replacement ContainingReplacement("x.cc", 0, 10, "");
+ auto Err = Replaces.add(ContainingReplacement);
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ Err = Replaces.add(Replacement("x.cc", 5, 3, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ Err = Replaces.add(Replacement("x.cc", 0, 10, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ EXPECT_EQ(1u, Replaces.size());
+ EXPECT_EQ(*Replaces.begin(), ContainingReplacement);
+}
+
+TEST_F(ReplacementTest, MergeOverlappingButNotAdjacentReplacement) {
+ Replacements Replaces;
+ auto Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ Replacement After = Replacement("x.cc", 10, 5, "");
+ Err = Replaces.add(After);
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ Replacement ContainingReplacement("x.cc", 0, 10, "");
+ Err = Replaces.add(ContainingReplacement);
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ EXPECT_EQ(2u, Replaces.size());
+ EXPECT_EQ(*Replaces.begin(), ContainingReplacement);
+ EXPECT_EQ(*(++Replaces.begin()), After);
+}
+
+TEST_F(ReplacementTest, InsertionBeforeMergedDeletions) {
+ Replacements Replaces;
+
+ Replacement Insertion("x.cc", 0, 0, "123");
+ auto Err = Replaces.add(Insertion);
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ Replacement Deletion("x.cc", 0, 10, "");
+ Err = Replaces.add(Deletion);
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ EXPECT_EQ(2u, Replaces.size());
+ EXPECT_EQ(*Replaces.begin(), Insertion);
+ EXPECT_EQ(*(++Replaces.begin()), Deletion);
+}
+
+TEST_F(ReplacementTest, MergeOverlappingDeletions) {
+ Replacements Replaces;
+ auto Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ Err = Replaces.add(Replacement("x.cc", 0, 5, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ EXPECT_EQ(1u, Replaces.size());
+ EXPECT_EQ(Replacement("x.cc", 0, 5, ""), *Replaces.begin());
+
+ Err = Replaces.add(Replacement("x.cc", 1, 5, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ EXPECT_EQ(1u, Replaces.size());
+ EXPECT_EQ(Replacement("x.cc", 0, 6, ""), *Replaces.begin());
+}
+
+TEST_F(ReplacementTest, FailedMergeExistingDeletions) {
+ Replacements Replaces;
+ Replacement First("x.cc", 0, 2, "");
+ auto Err = Replaces.add(First);
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ Replacement Second("x.cc", 5, 5, "");
+ Err = Replaces.add(Second);
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ Err = Replaces.add(Replacement("x.cc", 1, 10, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ EXPECT_EQ(1u, Replaces.size());
+ EXPECT_EQ(Replacement("x.cc", 0, 11, ""), *Replaces.begin());
+}
+
+TEST_F(ReplacementTest, FailAddRegression) {
+ Replacements Replaces;
+ // Create two replacements, where the second one is an insertion of the empty
+ // string exactly at the end of the first one.
+ auto Err = Replaces.add(Replacement("x.cc", 0, 10, "1"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ // Make sure we find the overlap with the first entry when inserting a
+ // replacement that ends exactly at the seam of the existing replacements.
+ Replacement OverlappingReplacement("x.cc", 5, 5, "fail");
+ Err = Replaces.add(OverlappingReplacement);
+ EXPECT_TRUE(checkReplacementError(std::move(Err),
+ replacement_error::overlap_conflict,
+ *Replaces.begin(), OverlappingReplacement));
+
+ Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+}
+
+TEST_F(ReplacementTest, InsertAtOffsetOfReplacement) {
+ Replacements Replaces;
+ auto Err = Replaces.add(Replacement("x.cc", 10, 2, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ EXPECT_EQ(Replaces.size(), 2u);
+
+ Replaces.clear();
+ Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 10, 2, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ EXPECT_EQ(Replaces.size(), 2u);
+}
+
+TEST_F(ReplacementTest, AddInsertAtOtherInsertWhenOderIndependent) {
+ Replacements Replaces;
+ auto Err = Replaces.add(Replacement("x.cc", 10, 0, "a"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Replacement ConflictInsertion("x.cc", 10, 0, "b");
+ Err = Replaces.add(ConflictInsertion);
+ EXPECT_TRUE(checkReplacementError(std::move(Err),
+ replacement_error::insert_conflict,
+ *Replaces.begin(), ConflictInsertion));
+
+ Replaces.clear();
+ Err = Replaces.add(Replacement("x.cc", 10, 0, "a"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 10, 0, "aa"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ EXPECT_EQ(1u, Replaces.size());
+ EXPECT_EQ(Replacement("x.cc", 10, 0, "aaa"), *Replaces.begin());
+
+ Replaces.clear();
+ Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 10, 3, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ EXPECT_EQ(2u, Replaces.size());
+ EXPECT_EQ(Replacement("x.cc", 10, 0, ""), *Replaces.begin());
+ EXPECT_EQ(Replacement("x.cc", 10, 3, ""), *std::next(Replaces.begin()));
+}
+
+TEST_F(ReplacementTest, InsertBetweenAdjacentReplacements) {
+ Replacements Replaces;
+ auto Err = Replaces.add(Replacement("x.cc", 10, 5, "a"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 8, 2, "a"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 10, 0, "b"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+}
+
TEST_F(ReplacementTest, CanApplyReplacements) {
FileID ID = Context.createInMemoryFile("input.cpp",
"line1\nline2\nline3\nline4");
- Replacements Replaces;
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
- 5, "replaced"));
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 3, 1),
- 5, "other"));
+ Replacements Replaces =
+ toReplacements({Replacement(Context.Sources,
+ Context.getLocation(ID, 2, 1), 5, "replaced"),
+ Replacement(Context.Sources,
+ Context.getLocation(ID, 3, 1), 5, "other")});
EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));
}
-// FIXME: Remove this test case when Replacements is implemented as std::vector
-// instead of std::set. The other ReplacementTest tests will need to be updated
-// at that point as well.
-TEST_F(ReplacementTest, VectorCanApplyReplacements) {
+// Verifies that replacement/deletion is applied before insertion at the same
+// offset.
+TEST_F(ReplacementTest, InsertAndDelete) {
FileID ID = Context.createInMemoryFile("input.cpp",
"line1\nline2\nline3\nline4");
- std::vector<Replacement> Replaces;
- Replaces.push_back(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
- 5, "replaced"));
- Replaces.push_back(
- Replacement(Context.Sources, Context.getLocation(ID, 3, 1), 5, "other"));
+ Replacements Replaces = toReplacements(
+ {Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 6, ""),
+ Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 0,
+ "other\n")});
EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
- EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));
+ EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID));
+}
+
+TEST_F(ReplacementTest, AdjacentReplacements) {
+ FileID ID = Context.createInMemoryFile("input.cpp",
+ "ab");
+ Replacements Replaces = toReplacements(
+ {Replacement(Context.Sources, Context.getLocation(ID, 1, 1), 1, "x"),
+ Replacement(Context.Sources, Context.getLocation(ID, 1, 2), 1, "y")});
+ EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
+ EXPECT_EQ("xy", Context.getRewrittenText(ID));
}
-TEST_F(ReplacementTest, SkipsDuplicateReplacements) {
+TEST_F(ReplacementTest, AddDuplicateReplacements) {
FileID ID = Context.createInMemoryFile("input.cpp",
"line1\nline2\nline3\nline4");
- Replacements Replaces;
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
- 5, "replaced"));
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
- 5, "replaced"));
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
- 5, "replaced"));
+ auto Replaces = toReplacements({Replacement(
+ Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});
+
+ auto Err = Replaces.add(Replacement(
+ Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
+ Err = Replaces.add(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
+ 5, "replaced"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+
EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
EXPECT_EQ("line1\nreplaced\nline3\nline4", Context.getRewrittenText(ID));
}
-TEST_F(ReplacementTest, ApplyAllFailsIfOneApplyFails) {
- // This test depends on the value of the file name of an invalid source
- // location being in the range ]a, z[.
- FileID IDa = Context.createInMemoryFile("a.cpp", "text");
- FileID IDz = Context.createInMemoryFile("z.cpp", "text");
- Replacements Replaces;
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(IDa, 1, 1),
- 4, "a"));
- Replaces.insert(Replacement(Context.Sources, SourceLocation(),
- 5, "2"));
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(IDz, 1, 1),
- 4, "z"));
+TEST_F(ReplacementTest, FailOrderDependentReplacements) {
+ FileID ID = Context.createInMemoryFile("input.cpp",
+ "line1\nline2\nline3\nline4");
+ auto Replaces = toReplacements({Replacement(
+ Context.Sources, Context.getLocation(ID, 2, 1), 5, "other")});
+
+ Replacement ConflictReplacement(Context.Sources,
+ Context.getLocation(ID, 2, 1), 5, "rehto");
+ auto Err = Replaces.add(ConflictReplacement);
+ EXPECT_TRUE(checkReplacementError(std::move(Err),
+ replacement_error::overlap_conflict,
+ *Replaces.begin(), ConflictReplacement));
+
+ EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
+ EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID));
+}
+
+TEST_F(ReplacementTest, InvalidSourceLocationFailsApplyAll) {
+ Replacements Replaces =
+ toReplacements({Replacement(Context.Sources, SourceLocation(), 5, "2")});
+
EXPECT_FALSE(applyAllReplacements(Replaces, Context.Rewrite));
- EXPECT_EQ("a", Context.getRewrittenText(IDa));
- EXPECT_EQ("z", Context.getRewrittenText(IDz));
}
TEST_F(ReplacementTest, MultipleFilesReplaceAndFormat) {
@@ -180,76 +521,66 @@ TEST_F(ReplacementTest, MultipleFilesReplaceAndFormat) {
std::string Expected2 = "int x =\n"
" 1234567890123;\n"
"int y = 10;";
- FileID ID1 = Context.createInMemoryFile("format_1.cpp", Code1);
- FileID ID2 = Context.createInMemoryFile("format_2.cpp", Code2);
+ StringRef File1 = "format_1.cpp";
+ StringRef File2 = "format_2.cpp";
+ FileID ID1 = Context.createInMemoryFile(File1, Code1);
+ FileID ID2 = Context.createInMemoryFile(File2, Code2);
- tooling::Replacements Replaces;
// Scrambled the order of replacements.
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID2, 1, 12), 0, "4567890123"));
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID1, 1, 1), 6, "auto "));
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID2, 2, 9), 1, "10"));
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID1, 3, 10), 1, "12345678901"));
-
- EXPECT_TRUE(formatAndApplyAllReplacements(
- Replaces, Context.Rewrite, "{BasedOnStyle: LLVM, ColumnLimit: 20}"));
+ std::map<std::string, Replacements> FileToReplaces;
+ FileToReplaces[File1] = toReplacements(
+ {tooling::Replacement(Context.Sources, Context.getLocation(ID1, 1, 1), 6,
+ "auto "),
+ tooling::Replacement(Context.Sources, Context.getLocation(ID1, 3, 10), 1,
+ "12345678901")});
+ FileToReplaces[File2] = toReplacements(
+ {tooling::Replacement(Context.Sources, Context.getLocation(ID2, 1, 12), 0,
+ "4567890123"),
+ tooling::Replacement(Context.Sources, Context.getLocation(ID2, 2, 9), 1,
+ "10")});
+ EXPECT_TRUE(
+ formatAndApplyAllReplacements(FileToReplaces, Context.Rewrite,
+ "{BasedOnStyle: LLVM, ColumnLimit: 20}"));
EXPECT_EQ(Expected1, Context.getRewrittenText(ID1));
EXPECT_EQ(Expected2, Context.getRewrittenText(ID2));
}
TEST(ShiftedCodePositionTest, FindsNewCodePosition) {
- Replacements Replaces;
- Replaces.insert(Replacement("", 0, 1, ""));
- Replaces.insert(Replacement("", 4, 3, " "));
+ Replacements Replaces =
+ toReplacements({Replacement("", 0, 1, ""), Replacement("", 4, 3, " ")});
// Assume ' int i;' is turned into 'int i;' and cursor is located at '|'.
- EXPECT_EQ(0u, shiftedCodePosition(Replaces, 0)); // |int i;
- EXPECT_EQ(0u, shiftedCodePosition(Replaces, 1)); // |nt i;
- EXPECT_EQ(1u, shiftedCodePosition(Replaces, 2)); // i|t i;
- EXPECT_EQ(2u, shiftedCodePosition(Replaces, 3)); // in| i;
- EXPECT_EQ(3u, shiftedCodePosition(Replaces, 4)); // int| i;
- EXPECT_EQ(3u, shiftedCodePosition(Replaces, 5)); // int | i;
- EXPECT_EQ(3u, shiftedCodePosition(Replaces, 6)); // int |i;
- EXPECT_EQ(4u, shiftedCodePosition(Replaces, 7)); // int |;
- EXPECT_EQ(5u, shiftedCodePosition(Replaces, 8)); // int i|
-}
-
-// FIXME: Remove this test case when Replacements is implemented as std::vector
-// instead of std::set. The other ReplacementTest tests will need to be updated
-// at that point as well.
-TEST(ShiftedCodePositionTest, VectorFindsNewCodePositionWithInserts) {
- std::vector<Replacement> Replaces;
- Replaces.push_back(Replacement("", 0, 1, ""));
- Replaces.push_back(Replacement("", 4, 3, " "));
- // Assume ' int i;' is turned into 'int i;' and cursor is located at '|'.
- EXPECT_EQ(0u, shiftedCodePosition(Replaces, 0)); // |int i;
- EXPECT_EQ(0u, shiftedCodePosition(Replaces, 1)); // |nt i;
- EXPECT_EQ(1u, shiftedCodePosition(Replaces, 2)); // i|t i;
- EXPECT_EQ(2u, shiftedCodePosition(Replaces, 3)); // in| i;
- EXPECT_EQ(3u, shiftedCodePosition(Replaces, 4)); // int| i;
- EXPECT_EQ(3u, shiftedCodePosition(Replaces, 5)); // int | i;
- EXPECT_EQ(3u, shiftedCodePosition(Replaces, 6)); // int |i;
- EXPECT_EQ(4u, shiftedCodePosition(Replaces, 7)); // int |;
- EXPECT_EQ(5u, shiftedCodePosition(Replaces, 8)); // int i|
+ EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0)); // |int i;
+ EXPECT_EQ(0u, Replaces.getShiftedCodePosition(1)); // |nt i;
+ EXPECT_EQ(1u, Replaces.getShiftedCodePosition(2)); // i|t i;
+ EXPECT_EQ(2u, Replaces.getShiftedCodePosition(3)); // in| i;
+ EXPECT_EQ(3u, Replaces.getShiftedCodePosition(4)); // int| i;
+ EXPECT_EQ(3u, Replaces.getShiftedCodePosition(5)); // int | i;
+ EXPECT_EQ(3u, Replaces.getShiftedCodePosition(6)); // int |i;
+ EXPECT_EQ(4u, Replaces.getShiftedCodePosition(7)); // int |;
+ EXPECT_EQ(5u, Replaces.getShiftedCodePosition(8)); // int i|
}
TEST(ShiftedCodePositionTest, FindsNewCodePositionWithInserts) {
- Replacements Replaces;
- Replaces.insert(Replacement("", 4, 0, "\"\n\""));
+ Replacements Replaces = toReplacements({Replacement("", 4, 0, "\"\n\"")});
// Assume '"12345678"' is turned into '"1234"\n"5678"'.
- EXPECT_EQ(3u, shiftedCodePosition(Replaces, 3)); // "123|5678"
- EXPECT_EQ(7u, shiftedCodePosition(Replaces, 4)); // "1234|678"
- EXPECT_EQ(8u, shiftedCodePosition(Replaces, 5)); // "12345|78"
+ EXPECT_EQ(3u, Replaces.getShiftedCodePosition(3)); // "123|5678"
+ EXPECT_EQ(7u, Replaces.getShiftedCodePosition(4)); // "1234|678"
+ EXPECT_EQ(8u, Replaces.getShiftedCodePosition(5)); // "12345|78"
}
TEST(ShiftedCodePositionTest, FindsNewCodePositionInReplacedText) {
- Replacements Replaces;
// Replace the first four characters with "abcd".
- Replaces.insert(Replacement("", 0, 4, "abcd"));
+ auto Replaces = toReplacements({Replacement("", 0, 4, "abcd")});
for (unsigned i = 0; i < 3; ++i)
- EXPECT_EQ(i, shiftedCodePosition(Replaces, i));
+ EXPECT_EQ(i, Replaces.getShiftedCodePosition(i));
+}
+
+TEST(ShiftedCodePositionTest, NoReplacementText) {
+ Replacements Replaces = toReplacements({Replacement("", 0, 42, "")});
+ EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0));
+ EXPECT_EQ(0u, Replaces.getShiftedCodePosition(39));
+ EXPECT_EQ(3u, Replaces.getShiftedCodePosition(45));
+ EXPECT_EQ(0u, Replaces.getShiftedCodePosition(42));
}
class FlushRewrittenFilesTest : public ::testing::Test {
@@ -305,9 +636,8 @@ public:
TEST_F(FlushRewrittenFilesTest, StoresChangesOnDisk) {
FileID ID = createFile("input.cpp", "line1\nline2\nline3\nline4");
- Replacements Replaces;
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
- 5, "replaced"));
+ Replacements Replaces = toReplacements({Replacement(
+ Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});
EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
EXPECT_FALSE(Context.Rewrite.overwriteChangedFiles());
EXPECT_EQ("line1\nreplaced\nline3\nline4",
@@ -455,12 +785,11 @@ TEST(Range, contains) {
TEST(Range, CalculateRangesOfReplacements) {
// Before: aaaabbbbbbz
// After : bbbbbbzzzzzzoooooooooooooooo
- Replacements Replaces;
- Replaces.insert(Replacement("foo", 0, 4, ""));
- Replaces.insert(Replacement("foo", 10, 1, "zzzzzz"));
- Replaces.insert(Replacement("foo", 11, 0, "oooooooooooooooo"));
+ Replacements Replaces = toReplacements(
+ {Replacement("foo", 0, 4, ""), Replacement("foo", 10, 1, "zzzzzz"),
+ Replacement("foo", 11, 0, "oooooooooooooooo")});
- std::vector<Range> Ranges = calculateChangedRanges(Replaces);
+ std::vector<Range> Ranges = Replaces.getAffectedRanges();
EXPECT_EQ(2ul, Ranges.size());
EXPECT_TRUE(Ranges[0].getOffset() == 0);
@@ -469,25 +798,43 @@ TEST(Range, CalculateRangesOfReplacements) {
EXPECT_TRUE(Ranges[1].getLength() == 22);
}
+TEST(Range, CalculateRangesOfInsertionAroundReplacement) {
+ Replacements Replaces = toReplacements(
+ {Replacement("foo", 0, 2, ""), Replacement("foo", 0, 0, "ba")});
+
+ std::vector<Range> Ranges = Replaces.getAffectedRanges();
+
+ EXPECT_EQ(1ul, Ranges.size());
+ EXPECT_EQ(0u, Ranges[0].getOffset());
+ EXPECT_EQ(2u, Ranges[0].getLength());
+}
+
+TEST(Range, RangesAfterEmptyReplacements) {
+ std::vector<Range> Ranges = {Range(5, 6), Range(10, 5)};
+ Replacements Replaces;
+ std::vector<Range> Expected = {Range(5, 10)};
+ EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
+}
+
TEST(Range, RangesAfterReplacements) {
std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
- Replacements Replaces = {Replacement("foo", 0, 2, "1234")};
+ Replacements Replaces = toReplacements({Replacement("foo", 0, 2, "1234")});
std::vector<Range> Expected = {Range(0, 4), Range(7, 2), Range(12, 5)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
TEST(Range, RangesBeforeReplacements) {
std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
- Replacements Replaces = {Replacement("foo", 20, 2, "1234")};
+ Replacements Replaces = toReplacements({Replacement("foo", 20, 2, "1234")});
std::vector<Range> Expected = {Range(5, 2), Range(10, 5), Range(20, 4)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
TEST(Range, NotAffectedByReplacements) {
std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
- Replacements Replaces = {Replacement("foo", 3, 2, "12"),
- Replacement("foo", 12, 2, "12"),
- Replacement("foo", 20, 5, "")};
+ Replacements Replaces = toReplacements({Replacement("foo", 3, 2, "12"),
+ Replacement("foo", 12, 2, "12"),
+ Replacement("foo", 20, 5, "")});
std::vector<Range> Expected = {Range(0, 2), Range(3, 4), Range(10, 5),
Range(20, 0)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
@@ -495,9 +842,9 @@ TEST(Range, NotAffectedByReplacements) {
TEST(Range, RangesWithNonOverlappingReplacements) {
std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
- Replacements Replaces = {Replacement("foo", 3, 1, ""),
- Replacement("foo", 6, 1, "123"),
- Replacement("foo", 20, 2, "12345")};
+ Replacements Replaces = toReplacements({Replacement("foo", 3, 1, ""),
+ Replacement("foo", 6, 1, "123"),
+ Replacement("foo", 20, 2, "12345")});
std::vector<Range> Expected = {Range(0, 2), Range(3, 0), Range(4, 4),
Range(11, 5), Range(21, 5)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
@@ -506,9 +853,9 @@ TEST(Range, RangesWithNonOverlappingReplacements) {
TEST(Range, RangesWithOverlappingReplacements) {
std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5),
Range(30, 5)};
- Replacements Replaces = {
- Replacement("foo", 1, 3, ""), Replacement("foo", 6, 1, "123"),
- Replacement("foo", 13, 3, "1"), Replacement("foo", 25, 15, "")};
+ Replacements Replaces = toReplacements(
+ {Replacement("foo", 1, 3, ""), Replacement("foo", 6, 1, "123"),
+ Replacement("foo", 13, 3, "1"), Replacement("foo", 25, 15, "")});
std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(12, 5),
Range(22, 0)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
@@ -516,122 +863,52 @@ TEST(Range, RangesWithOverlappingReplacements) {
TEST(Range, MergeIntoOneRange) {
std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
- Replacements Replaces = {Replacement("foo", 1, 15, "1234567890")};
+ Replacements Replaces =
+ toReplacements({Replacement("foo", 1, 15, "1234567890")});
std::vector<Range> Expected = {Range(0, 15)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
TEST(Range, ReplacementsStartingAtRangeOffsets) {
std::vector<Range> Ranges = {Range(0, 2), Range(5, 5), Range(15, 5)};
- Replacements Replaces = {
- Replacement("foo", 0, 2, "12"), Replacement("foo", 5, 1, "123"),
- Replacement("foo", 7, 4, "12345"), Replacement("foo", 15, 10, "12")};
+ Replacements Replaces = toReplacements(
+ {Replacement("foo", 0, 2, "12"), Replacement("foo", 5, 1, "123"),
+ Replacement("foo", 7, 4, "12345"), Replacement("foo", 15, 10, "12")});
std::vector<Range> Expected = {Range(0, 2), Range(5, 9), Range(18, 2)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
TEST(Range, ReplacementsEndingAtRangeEnds) {
std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
- Replacements Replaces = {Replacement("foo", 6, 1, "123"),
- Replacement("foo", 17, 3, "12")};
+ Replacements Replaces = toReplacements(
+ {Replacement("foo", 6, 1, "123"), Replacement("foo", 17, 3, "12")});
std::vector<Range> Expected = {Range(0, 2), Range(5, 4), Range(17, 4)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
TEST(Range, AjacentReplacements) {
std::vector<Range> Ranges = {Range(0, 0), Range(15, 5)};
- Replacements Replaces = {Replacement("foo", 1, 2, "123"),
- Replacement("foo", 12, 3, "1234")};
+ Replacements Replaces = toReplacements(
+ {Replacement("foo", 1, 2, "123"), Replacement("foo", 12, 3, "1234")});
std::vector<Range> Expected = {Range(0, 0), Range(1, 3), Range(13, 9)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
TEST(Range, MergeRangesAfterReplacements) {
std::vector<Range> Ranges = {Range(8, 0), Range(5, 2), Range(9, 0), Range(0, 1)};
- Replacements Replaces = {Replacement("foo", 1, 3, ""),
- Replacement("foo", 7, 0, "12"), Replacement("foo", 9, 2, "")};
- std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(7, 0), Range(8, 0)};
+ Replacements Replaces = toReplacements({Replacement("foo", 1, 3, ""),
+ Replacement("foo", 7, 0, "12"),
+ Replacement("foo", 9, 2, "")});
+ std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(7, 0),
+ Range(8, 0)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
-TEST(DeduplicateTest, removesDuplicates) {
- std::vector<Replacement> Input;
- Input.push_back(Replacement("fileA", 50, 0, " foo "));
- Input.push_back(Replacement("fileA", 10, 3, " bar "));
- Input.push_back(Replacement("fileA", 10, 2, " bar ")); // Length differs
- Input.push_back(Replacement("fileA", 9, 3, " bar ")); // Offset differs
- Input.push_back(Replacement("fileA", 50, 0, " foo ")); // Duplicate
- Input.push_back(Replacement("fileA", 51, 3, " bar "));
- Input.push_back(Replacement("fileB", 51, 3, " bar ")); // Filename differs!
- Input.push_back(Replacement("fileB", 60, 1, " bar "));
- Input.push_back(Replacement("fileA", 60, 2, " bar "));
- Input.push_back(Replacement("fileA", 51, 3, " moo ")); // Replacement text
- // differs!
-
- std::vector<Replacement> Expected;
- Expected.push_back(Replacement("fileA", 9, 3, " bar "));
- Expected.push_back(Replacement("fileA", 10, 2, " bar "));
- Expected.push_back(Replacement("fileA", 10, 3, " bar "));
- Expected.push_back(Replacement("fileA", 50, 0, " foo "));
- Expected.push_back(Replacement("fileA", 51, 3, " bar "));
- Expected.push_back(Replacement("fileA", 51, 3, " moo "));
- Expected.push_back(Replacement("fileB", 60, 1, " bar "));
- Expected.push_back(Replacement("fileA", 60, 2, " bar "));
-
- std::vector<Range> Conflicts; // Ignored for this test
- deduplicate(Input, Conflicts);
-
- EXPECT_EQ(3U, Conflicts.size());
- EXPECT_EQ(Expected, Input);
-}
-
-TEST(DeduplicateTest, detectsConflicts) {
- {
- std::vector<Replacement> Input;
- Input.push_back(Replacement("fileA", 0, 5, " foo "));
- Input.push_back(Replacement("fileA", 0, 5, " foo ")); // Duplicate not a
- // conflict.
- Input.push_back(Replacement("fileA", 2, 6, " bar "));
- Input.push_back(Replacement("fileA", 7, 3, " moo "));
-
- std::vector<Range> Conflicts;
- deduplicate(Input, Conflicts);
-
- // One duplicate is removed and the remaining three items form one
- // conflicted range.
- ASSERT_EQ(3u, Input.size());
- ASSERT_EQ(1u, Conflicts.size());
- ASSERT_EQ(0u, Conflicts.front().getOffset());
- ASSERT_EQ(3u, Conflicts.front().getLength());
- }
- {
- std::vector<Replacement> Input;
-
- // Expected sorted order is shown. It is the sorted order to which the
- // returned conflict info refers to.
- Input.push_back(Replacement("fileA", 0, 5, " foo ")); // 0
- Input.push_back(Replacement("fileA", 5, 5, " bar ")); // 1
- Input.push_back(Replacement("fileA", 6, 0, " bar ")); // 3
- Input.push_back(Replacement("fileA", 5, 5, " moo ")); // 2
- Input.push_back(Replacement("fileA", 7, 2, " bar ")); // 4
- Input.push_back(Replacement("fileA", 15, 5, " golf ")); // 5
- Input.push_back(Replacement("fileA", 16, 5, " bag ")); // 6
- Input.push_back(Replacement("fileA", 10, 3, " club ")); // 7
-
- // #3 is special in that it is completely contained by another conflicting
- // Replacement. #4 ensures #3 hasn't messed up the conflicting range size.
-
- std::vector<Range> Conflicts;
- deduplicate(Input, Conflicts);
-
- // No duplicates
- ASSERT_EQ(8u, Input.size());
- ASSERT_EQ(2u, Conflicts.size());
- ASSERT_EQ(1u, Conflicts[0].getOffset());
- ASSERT_EQ(4u, Conflicts[0].getLength());
- ASSERT_EQ(6u, Conflicts[1].getOffset());
- ASSERT_EQ(2u, Conflicts[1].getLength());
- }
+TEST(Range, ConflictingRangesBeforeReplacements) {
+ std::vector<Range> Ranges = {Range(8, 3), Range(5, 4), Range(9, 1)};
+ Replacements Replaces = toReplacements({Replacement("foo", 1, 3, "")});
+ std::vector<Range> Expected = {Range(1, 0), Range(2, 6)};
+ EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
class MergeReplacementsTest : public ::testing::Test {
@@ -647,7 +924,7 @@ protected:
EXPECT_EQ(Intermediate, *AfterFirst);
EXPECT_EQ(Result, *InSequenceRewrite);
- tooling::Replacements Merged = mergeReplacements(First, Second);
+ tooling::Replacements Merged = First.merge(Second);
auto MergedRewrite = applyAllReplacements(Code, Merged);
EXPECT_TRUE(static_cast<bool>(MergedRewrite));
EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
@@ -661,7 +938,7 @@ protected:
auto AfterFirst = applyAllReplacements(Code, First);
EXPECT_TRUE(static_cast<bool>(AfterFirst));
auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);
- tooling::Replacements Merged = mergeReplacements(First, Second);
+ tooling::Replacements Merged = First.merge(Second);
auto MergedRewrite = applyAllReplacements(Code, Merged);
EXPECT_TRUE(static_cast<bool>(MergedRewrite));
EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
@@ -674,62 +951,142 @@ protected:
TEST_F(MergeReplacementsTest, Offsets) {
mergeAndTestRewrite("aaa", "aabab", "cacabab",
- {{"", 2, 0, "b"}, {"", 3, 0, "b"}},
- {{"", 0, 0, "c"}, {"", 1, 0, "c"}});
+ toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),
+ toReplacements({{"", 0, 0, "c"}, {"", 1, 0, "c"}}));
mergeAndTestRewrite("aaa", "babaa", "babacac",
- {{"", 0, 0, "b"}, {"", 1, 0, "b"}},
- {{"", 4, 0, "c"}, {"", 5, 0, "c"}});
- mergeAndTestRewrite("aaaa", "aaa", "aac", {{"", 1, 1, ""}},
- {{"", 2, 1, "c"}});
+ toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "b"}}),
+ toReplacements({{"", 4, 0, "c"}, {"", 5, 0, "c"}}));
+ mergeAndTestRewrite("aaaa", "aaa", "aac", toReplacements({{"", 1, 1, ""}}),
+ toReplacements({{"", 2, 1, "c"}}));
mergeAndTestRewrite("aa", "bbabba", "bbabcba",
- {{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}, {{"", 4, 0, "c"}});
+ toReplacements({{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}),
+ toReplacements({{"", 4, 0, "c"}}));
}
TEST_F(MergeReplacementsTest, Concatenations) {
// Basic concatenations. It is important to merge these into a single
// replacement to ensure the correct order.
- EXPECT_EQ((Replacements{{"", 0, 0, "ab"}}),
- mergeReplacements({{"", 0, 0, "a"}}, {{"", 1, 0, "b"}}));
- EXPECT_EQ((Replacements{{"", 0, 0, "ba"}}),
- mergeReplacements({{"", 0, 0, "a"}}, {{"", 0, 0, "b"}}));
- mergeAndTestRewrite("", "a", "ab", {{"", 0, 0, "a"}}, {{"", 1, 0, "b"}});
- mergeAndTestRewrite("", "a", "ba", {{"", 0, 0, "a"}}, {{"", 0, 0, "b"}});
+ {
+ auto First = toReplacements({{"", 0, 0, "a"}});
+ auto Second = toReplacements({{"", 1, 0, "b"}});
+ EXPECT_EQ(toReplacements({{"", 0, 0, "ab"}}), First.merge(Second));
+ }
+ {
+ auto First = toReplacements({{"", 0, 0, "a"}});
+ auto Second = toReplacements({{"", 0, 0, "b"}});
+ EXPECT_EQ(toReplacements({{"", 0, 0, "ba"}}), First.merge(Second));
+ }
+ mergeAndTestRewrite("", "a", "ab", toReplacements({{"", 0, 0, "a"}}),
+ toReplacements({{"", 1, 0, "b"}}));
+ mergeAndTestRewrite("", "a", "ba", toReplacements({{"", 0, 0, "a"}}),
+ toReplacements({{"", 0, 0, "b"}}));
}
TEST_F(MergeReplacementsTest, NotChangingLengths) {
- mergeAndTestRewrite("aaaa", "abba", "acca", {{"", 1, 2, "bb"}},
- {{"", 1, 2, "cc"}});
- mergeAndTestRewrite("aaaa", "abba", "abcc", {{"", 1, 2, "bb"}},
- {{"", 2, 2, "cc"}});
- mergeAndTestRewrite("aaaa", "abba", "ccba", {{"", 1, 2, "bb"}},
- {{"", 0, 2, "cc"}});
+ mergeAndTestRewrite("aaaa", "abba", "acca",
+ toReplacements({{"", 1, 2, "bb"}}),
+ toReplacements({{"", 1, 2, "cc"}}));
+ mergeAndTestRewrite("aaaa", "abba", "abcc",
+ toReplacements({{"", 1, 2, "bb"}}),
+ toReplacements({{"", 2, 2, "cc"}}));
+ mergeAndTestRewrite("aaaa", "abba", "ccba",
+ toReplacements({{"", 1, 2, "bb"}}),
+ toReplacements({{"", 0, 2, "cc"}}));
mergeAndTestRewrite("aaaaaa", "abbdda", "abccda",
- {{"", 1, 2, "bb"}, {"", 3, 2, "dd"}}, {{"", 2, 2, "cc"}});
+ toReplacements({{"", 1, 2, "bb"}, {"", 3, 2, "dd"}}),
+ toReplacements({{"", 2, 2, "cc"}}));
}
TEST_F(MergeReplacementsTest, OverlappingRanges) {
mergeAndTestRewrite("aaa", "bbd", "bcbcd",
- {{"", 0, 1, "bb"}, {"", 1, 2, "d"}},
- {{"", 1, 0, "c"}, {"", 2, 0, "c"}});
+ toReplacements({{"", 0, 1, "bb"}, {"", 1, 2, "d"}}),
+ toReplacements({{"", 1, 0, "c"}, {"", 2, 0, "c"}}));
- mergeAndTestRewrite("aaaa", "aabbaa", "acccca", {{"", 2, 0, "bb"}},
- {{"", 1, 4, "cccc"}});
+ mergeAndTestRewrite("aaaa", "aabbaa", "acccca",
+ toReplacements({{"", 2, 0, "bb"}}),
+ toReplacements({{"", 1, 4, "cccc"}}));
mergeAndTestRewrite("aaaa", "aababa", "acccca",
- {{"", 2, 0, "b"}, {"", 3, 0, "b"}}, {{"", 1, 4, "cccc"}});
- mergeAndTestRewrite("aaaaaa", "abbbba", "abba", {{"", 1, 4, "bbbb"}},
- {{"", 2, 2, ""}});
- mergeAndTestRewrite("aaaa", "aa", "cc", {{"", 1, 1, ""}, {"", 2, 1, ""}},
- {{"", 0, 2, "cc"}});
- mergeAndTestRewrite("aa", "abbba", "abcbcba", {{"", 1, 0, "bbb"}},
- {{"", 2, 0, "c"}, {"", 3, 0, "c"}});
-
- mergeAndTestRewrite("aaa", "abbab", "ccdd",
- {{"", 0, 1, ""}, {"", 2, 0, "bb"}, {"", 3, 0, "b"}},
- {{"", 0, 2, "cc"}, {"", 2, 3, "dd"}});
- mergeAndTestRewrite("aa", "babbab", "ccdd",
- {{"", 0, 0, "b"}, {"", 1, 0, "bb"}, {"", 2, 0, "b"}},
- {{"", 0, 3, "cc"}, {"", 3, 3, "dd"}});
+ toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),
+ toReplacements({{"", 1, 4, "cccc"}}));
+ mergeAndTestRewrite("aaaaaa", "abbbba", "abba",
+ toReplacements({{"", 1, 4, "bbbb"}}),
+ toReplacements({{"", 2, 2, ""}}));
+ mergeAndTestRewrite("aaaa", "aa", "cc",
+ toReplacements({{"", 1, 1, ""}, {"", 2, 1, ""}}),
+ toReplacements({{"", 0, 2, "cc"}}));
+ mergeAndTestRewrite("aa", "abbba", "abcbcba",
+ toReplacements({{"", 1, 0, "bbb"}}),
+ toReplacements({{"", 2, 0, "c"}, {"", 3, 0, "c"}}));
+
+ mergeAndTestRewrite(
+ "aaa", "abbab", "ccdd",
+ toReplacements({{"", 0, 1, ""}, {"", 2, 0, "bb"}, {"", 3, 0, "b"}}),
+ toReplacements({{"", 0, 2, "cc"}, {"", 2, 3, "dd"}}));
+ mergeAndTestRewrite(
+ "aa", "babbab", "ccdd",
+ toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "bb"}, {"", 2, 0, "b"}}),
+ toReplacements({{"", 0, 3, "cc"}, {"", 3, 3, "dd"}}));
+}
+
+TEST(DeduplicateByFileTest, PathsWithDots) {
+ std::map<std::string, Replacements> FileToReplaces;
+ llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> VFS(
+ new vfs::InMemoryFileSystem());
+ FileManager FileMgr(FileSystemOptions(), VFS);
+#if !defined(LLVM_ON_WIN32)
+ StringRef Path1 = "a/b/.././c.h";
+ StringRef Path2 = "a/c.h";
+#else
+ StringRef Path1 = "a\\b\\..\\.\\c.h";
+ StringRef Path2 = "a\\c.h";
+#endif
+ EXPECT_TRUE(VFS->addFile(Path1, 0, llvm::MemoryBuffer::getMemBuffer("")));
+ EXPECT_TRUE(VFS->addFile(Path2, 0, llvm::MemoryBuffer::getMemBuffer("")));
+ FileToReplaces[Path1] = Replacements();
+ FileToReplaces[Path2] = Replacements();
+ FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces);
+ EXPECT_EQ(1u, FileToReplaces.size());
+ EXPECT_EQ(Path1, FileToReplaces.begin()->first);
+}
+
+TEST(DeduplicateByFileTest, PathWithDotSlash) {
+ std::map<std::string, Replacements> FileToReplaces;
+ llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> VFS(
+ new vfs::InMemoryFileSystem());
+ FileManager FileMgr(FileSystemOptions(), VFS);
+#if !defined(LLVM_ON_WIN32)
+ StringRef Path1 = "./a/b/c.h";
+ StringRef Path2 = "a/b/c.h";
+#else
+ StringRef Path1 = ".\\a\\b\\c.h";
+ StringRef Path2 = "a\\b\\c.h";
+#endif
+ EXPECT_TRUE(VFS->addFile(Path1, 0, llvm::MemoryBuffer::getMemBuffer("")));
+ EXPECT_TRUE(VFS->addFile(Path2, 0, llvm::MemoryBuffer::getMemBuffer("")));
+ FileToReplaces[Path1] = Replacements();
+ FileToReplaces[Path2] = Replacements();
+ FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces);
+ EXPECT_EQ(1u, FileToReplaces.size());
+ EXPECT_EQ(Path1, FileToReplaces.begin()->first);
+}
+
+TEST(DeduplicateByFileTest, NonExistingFilePath) {
+ std::map<std::string, Replacements> FileToReplaces;
+ llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> VFS(
+ new vfs::InMemoryFileSystem());
+ FileManager FileMgr(FileSystemOptions(), VFS);
+#if !defined(LLVM_ON_WIN32)
+ StringRef Path1 = "./a/b/c.h";
+ StringRef Path2 = "a/b/c.h";
+#else
+ StringRef Path1 = ".\\a\\b\\c.h";
+ StringRef Path2 = "a\\b\\c.h";
+#endif
+ FileToReplaces[Path1] = Replacements();
+ FileToReplaces[Path2] = Replacements();
+ FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces);
+ EXPECT_TRUE(FileToReplaces.empty());
}
} // end namespace tooling
diff --git a/unittests/Tooling/ReplacementTest.h b/unittests/Tooling/ReplacementTest.h
new file mode 100644
index 000000000000..b6fe5c79b7be
--- /dev/null
+++ b/unittests/Tooling/ReplacementTest.h
@@ -0,0 +1,56 @@
+//===- unittest/Tooling/ReplacementTest.h - Replacements related test------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines utility class and function for Replacement related tests.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_UNITTESTS_TOOLING_REPLACEMENTTESTBASE_H
+#define LLVM_CLANG_UNITTESTS_TOOLING_REPLACEMENTTESTBASE_H
+
+#include "RewriterTestContext.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tooling {
+
+/// \brief Converts a set of replacements to Replacements class.
+/// \return A Replacements class containing \p Replaces on success; otherwise,
+/// an empty Replacements is returned.
+inline tooling::Replacements
+toReplacements(const std::set<tooling::Replacement> &Replaces) {
+ tooling::Replacements Result;
+ for (const auto &R : Replaces) {
+ auto Err = Result.add(R);
+ EXPECT_TRUE(!Err);
+ if (Err) {
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ return tooling::Replacements();
+ }
+ }
+ return Result;
+}
+
+/// \brief A utility class for replacement related tests.
+class ReplacementTest : public ::testing::Test {
+protected:
+ tooling::Replacement createReplacement(SourceLocation Start, unsigned Length,
+ llvm::StringRef ReplacementText) {
+ return tooling::Replacement(Context.Sources, Start, Length,
+ ReplacementText);
+ }
+
+ RewriterTestContext Context;
+};
+
+} // namespace tooling
+} // namespace clang
+
+#endif // LLVM_CLANG_UNITTESTS_TOOLING_REPLACEMENTTESTBASE_H
diff --git a/unittests/Tooling/RewriterTest.cpp b/unittests/Tooling/RewriterTest.cpp
index e8afedb01174..4305d421e1cb 100644
--- a/unittests/Tooling/RewriterTest.cpp
+++ b/unittests/Tooling/RewriterTest.cpp
@@ -39,8 +39,11 @@ TEST(Rewriter, ContinuesOverwritingFilesOnError) {
TEST(Rewriter, AdjacentInsertAndDelete) {
Replacements Replaces;
- Replaces.insert(Replacement("<file>", 6, 6, ""));
- Replaces.insert(Replacement("<file>", 6, 0, "replaced\n"));
+ auto Err = Replaces.add(Replacement("<file>", 6, 6, ""));
+ EXPECT_TRUE(!Err);
+ Replaces =
+ Replaces.merge(Replacements(Replacement("<file>", 6, 0, "replaced\n")));
+
auto Rewritten = applyAllReplacements("line1\nline2\nline3\nline4", Replaces);
EXPECT_TRUE(static_cast<bool>(Rewritten));
EXPECT_EQ("line1\nreplaced\nline3\nline4", *Rewritten);
diff --git a/unittests/Tooling/TestVisitor.h b/unittests/Tooling/TestVisitor.h
index f4a00394487b..a762ec8b1453 100644
--- a/unittests/Tooling/TestVisitor.h
+++ b/unittests/Tooling/TestVisitor.h
@@ -43,6 +43,7 @@ public:
Lang_C,
Lang_CXX98,
Lang_CXX11,
+ Lang_CXX14,
Lang_OBJC,
Lang_OBJCXX11,
Lang_CXX = Lang_CXX98
@@ -55,6 +56,7 @@ public:
case Lang_C: Args.push_back("-std=c99"); break;
case Lang_CXX98: Args.push_back("-std=c++98"); break;
case Lang_CXX11: Args.push_back("-std=c++11"); break;
+ case Lang_CXX14: Args.push_back("-std=c++14"); break;
case Lang_OBJC: Args.push_back("-ObjC"); break;
case Lang_OBJCXX11:
Args.push_back("-ObjC++");
@@ -127,9 +129,12 @@ public:
/// \brief Expect 'Match' to occur at the given 'Line' and 'Column'.
///
/// Any number of expected matches can be set by calling this repeatedly.
- /// Each is expected to be matched exactly once.
- void ExpectMatch(Twine Match, unsigned Line, unsigned Column) {
- ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column));
+ /// Each is expected to be matched 'Times' number of times. (This is useful in
+ /// cases in which different AST nodes can match at the same source code
+ /// location.)
+ void ExpectMatch(Twine Match, unsigned Line, unsigned Column,
+ unsigned Times = 1) {
+ ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column, Times));
}
/// \brief Checks that all expected matches have been found.
@@ -200,14 +205,17 @@ protected:
};
struct ExpectedMatch {
- ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber)
- : Candidate(Name, LineNumber, ColumnNumber), Found(false) {}
+ ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber,
+ unsigned Times)
+ : Candidate(Name, LineNumber, ColumnNumber), TimesExpected(Times),
+ TimesSeen(0) {}
void UpdateFor(StringRef Name, FullSourceLoc Location, SourceManager &SM) {
if (Candidate.Matches(Name, Location)) {
- EXPECT_TRUE(!Found);
- Found = true;
- } else if (!Found && Candidate.PartiallyMatches(Name, Location)) {
+ EXPECT_LT(TimesSeen, TimesExpected);
+ ++TimesSeen;
+ } else if (TimesSeen < TimesExpected &&
+ Candidate.PartiallyMatches(Name, Location)) {
llvm::raw_string_ostream Stream(PartialMatches);
Stream << ", partial match: \"" << Name << "\" at ";
Location.print(Stream, SM);
@@ -215,7 +223,7 @@ protected:
}
void ExpectFound() const {
- EXPECT_TRUE(Found)
+ EXPECT_EQ(TimesExpected, TimesSeen)
<< "Expected \"" << Candidate.ExpectedName
<< "\" at " << Candidate.LineNumber
<< ":" << Candidate.ColumnNumber << PartialMatches;
@@ -223,7 +231,8 @@ protected:
MatchCandidate Candidate;
std::string PartialMatches;
- bool Found;
+ unsigned TimesExpected;
+ unsigned TimesSeen;
};
std::vector<MatchCandidate> DisallowedMatches;
diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp
index 10ac0c33ed85..68b5ed21059b 100644
--- a/unittests/Tooling/ToolingTest.cpp
+++ b/unittests/Tooling/ToolingTest.cpp
@@ -18,8 +18,9 @@
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Config/llvm-config.h"
-#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
#include "gtest/gtest.h"
#include <algorithm>
#include <string>
@@ -331,6 +332,44 @@ TEST(runToolOnCodeWithArgs, TestNoDepFile) {
EXPECT_FALSE(llvm::sys::fs::remove(DepFilePath.str()));
}
+struct CheckColoredDiagnosticsAction : public clang::ASTFrontendAction {
+ CheckColoredDiagnosticsAction(bool ShouldShowColor)
+ : ShouldShowColor(ShouldShowColor) {}
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef) override {
+ if (Compiler.getDiagnosticOpts().ShowColors != ShouldShowColor)
+ Compiler.getDiagnostics().Report(
+ Compiler.getDiagnostics().getCustomDiagID(
+ DiagnosticsEngine::Fatal,
+ "getDiagnosticOpts().ShowColors != ShouldShowColor"));
+ return llvm::make_unique<ASTConsumer>();
+ }
+
+private:
+ bool ShouldShowColor = true;
+};
+
+TEST(runToolOnCodeWithArgs, DiagnosticsColor) {
+
+ EXPECT_TRUE(runToolOnCodeWithArgs(new CheckColoredDiagnosticsAction(true), "",
+ {"-fcolor-diagnostics"}));
+ EXPECT_TRUE(runToolOnCodeWithArgs(new CheckColoredDiagnosticsAction(false),
+ "", {"-fno-color-diagnostics"}));
+ EXPECT_TRUE(
+ runToolOnCodeWithArgs(new CheckColoredDiagnosticsAction(true), "",
+ {"-fno-color-diagnostics", "-fcolor-diagnostics"}));
+ EXPECT_TRUE(
+ runToolOnCodeWithArgs(new CheckColoredDiagnosticsAction(false), "",
+ {"-fcolor-diagnostics", "-fno-color-diagnostics"}));
+ EXPECT_TRUE(runToolOnCodeWithArgs(
+ new CheckColoredDiagnosticsAction(true), "",
+ {"-fno-color-diagnostics", "-fdiagnostics-color=always"}));
+
+ // Check that this test would fail if ShowColors is not what it should.
+ EXPECT_FALSE(runToolOnCodeWithArgs(new CheckColoredDiagnosticsAction(false),
+ "", {"-fcolor-diagnostics"}));
+}
+
TEST(ClangToolTest, ArgumentAdjusters) {
FixedCompilationDatabase Compilations("/", std::vector<std::string>());
diff --git a/unittests/libclang/LibclangTest.cpp b/unittests/libclang/LibclangTest.cpp
index d5c78272af54..f2a96d6be6c1 100644
--- a/unittests/libclang/LibclangTest.cpp
+++ b/unittests/libclang/LibclangTest.cpp
@@ -14,6 +14,9 @@
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
#include <fstream>
+#include <functional>
+#include <map>
+#include <memory>
#include <set>
#define DEBUG_TYPE "libclang-test"
@@ -349,21 +352,25 @@ TEST(libclang, ModuleMapDescriptor) {
clang_ModuleMapDescriptor_dispose(MMD);
}
-class LibclangReparseTest : public ::testing::Test {
+class LibclangParseTest : public ::testing::Test {
std::set<std::string> Files;
+ typedef std::unique_ptr<std::string> fixed_addr_string;
+ std::map<fixed_addr_string, fixed_addr_string> UnsavedFileContents;
public:
std::string TestDir;
CXIndex Index;
CXTranslationUnit ClangTU;
unsigned TUFlags;
+ std::vector<CXUnsavedFile> UnsavedFiles;
void SetUp() override {
llvm::SmallString<256> Dir;
ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory("libclang-test", Dir));
TestDir = Dir.str();
TUFlags = CXTranslationUnit_DetailedPreprocessingRecord |
- clang_defaultEditingTranslationUnitOptions();
+ clang_defaultEditingTranslationUnitOptions();
Index = clang_createIndex(0, 0);
+ ClangTU = nullptr;
}
void TearDown() override {
clang_disposeTranslationUnit(ClangTU);
@@ -384,6 +391,77 @@ public:
OS << Contents;
assert(OS.good());
}
+ void MapUnsavedFile(std::string Filename, const std::string &Contents) {
+ if (!llvm::sys::path::is_absolute(Filename)) {
+ llvm::SmallString<256> Path(TestDir);
+ llvm::sys::path::append(Path, Filename);
+ Filename = Path.str();
+ }
+ auto it = UnsavedFileContents.insert(std::make_pair(
+ fixed_addr_string(new std::string(Filename)),
+ fixed_addr_string(new std::string(Contents))));
+ UnsavedFiles.push_back({
+ it.first->first->c_str(), // filename
+ it.first->second->c_str(), // contents
+ it.first->second->size() // length
+ });
+ }
+ template<typename F>
+ void Traverse(const F &TraversalFunctor) {
+ CXCursor TuCursor = clang_getTranslationUnitCursor(ClangTU);
+ std::reference_wrapper<const F> FunctorRef = std::cref(TraversalFunctor);
+ clang_visitChildren(TuCursor,
+ &TraverseStateless<std::reference_wrapper<const F>>,
+ &FunctorRef);
+ }
+private:
+ template<typename TState>
+ static CXChildVisitResult TraverseStateless(CXCursor cx, CXCursor parent,
+ CXClientData data) {
+ TState *State = static_cast<TState*>(data);
+ return State->get()(cx, parent);
+ }
+};
+
+TEST_F(LibclangParseTest, AllSkippedRanges) {
+ std::string Header = "header.h", Main = "main.cpp";
+ WriteFile(Header,
+ "#ifdef MANGOS\n"
+ "printf(\"mmm\");\n"
+ "#endif");
+ WriteFile(Main,
+ "#include \"header.h\"\n"
+ "#ifdef KIWIS\n"
+ "printf(\"mmm!!\");\n"
+ "#endif");
+
+ ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0,
+ nullptr, 0, TUFlags);
+
+ CXSourceRangeList *Ranges = clang_getAllSkippedRanges(ClangTU);
+ EXPECT_EQ(2U, Ranges->count);
+
+ CXSourceLocation cxl;
+ unsigned line;
+ cxl = clang_getRangeStart(Ranges->ranges[0]);
+ clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
+ EXPECT_EQ(1U, line);
+ cxl = clang_getRangeEnd(Ranges->ranges[0]);
+ clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
+ EXPECT_EQ(3U, line);
+
+ cxl = clang_getRangeStart(Ranges->ranges[1]);
+ clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
+ EXPECT_EQ(2U, line);
+ cxl = clang_getRangeEnd(Ranges->ranges[1]);
+ clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
+ EXPECT_EQ(4U, line);
+
+ clang_disposeSourceRangeList(Ranges);
+}
+
+class LibclangReparseTest : public LibclangParseTest {
+public:
void DisplayDiagnostics() {
unsigned NumDiagnostics = clang_getNumDiagnostics(ClangTU);
for (unsigned i = 0; i < NumDiagnostics; ++i) {