Updated to Clang 3.5a.
Change-Id: I8127eb568f674c2e72635b639a3295381fe8af82
diff --git a/unittests/AST/ASTContextParentMapTest.cpp b/unittests/AST/ASTContextParentMapTest.cpp
index c1910a8..0dcb175 100644
--- a/unittests/AST/ASTContextParentMapTest.cpp
+++ b/unittests/AST/ASTContextParentMapTest.cpp
@@ -12,11 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
+#include "MatchVerifier.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
-#include "MatchVerifier.h"
namespace clang {
namespace ast_matchers {
diff --git a/unittests/AST/ASTTypeTraitsTest.cpp b/unittests/AST/ASTTypeTraitsTest.cpp
index dd73b52..0e73f76 100644
--- a/unittests/AST/ASTTypeTraitsTest.cpp
+++ b/unittests/AST/ASTTypeTraitsTest.cpp
@@ -9,8 +9,8 @@
#include "clang/AST/ASTTypeTraits.h"
-#include "gtest/gtest.h"
#include "MatchVerifier.h"
+#include "gtest/gtest.h"
using namespace clang::ast_matchers;
@@ -34,6 +34,19 @@
EXPECT_TRUE(DNT<Decl>().isSame(DNT<Decl>()));
}
+TEST(ASTNodeKind, BaseDistances) {
+ unsigned Distance = 1;
+ EXPECT_TRUE(DNT<Expr>().isBaseOf(DNT<Expr>(), &Distance));
+ EXPECT_EQ(0u, Distance);
+
+ EXPECT_TRUE(DNT<Stmt>().isBaseOf(DNT<IfStmt>(), &Distance));
+ EXPECT_EQ(1u, Distance);
+
+ Distance = 3;
+ EXPECT_TRUE(DNT<DeclaratorDecl>().isBaseOf(DNT<ParmVarDecl>(), &Distance));
+ EXPECT_EQ(2u, Distance);
+}
+
TEST(ASTNodeKind, SameBase) {
EXPECT_TRUE(DNT<Expr>().isBaseOf(DNT<CallExpr>()));
EXPECT_TRUE(DNT<Expr>().isBaseOf(DNT<BinaryOperator>()));
diff --git a/unittests/AST/CMakeLists.txt b/unittests/AST/CMakeLists.txt
index 70f86d3..9a55626 100644
--- a/unittests/AST/CMakeLists.txt
+++ b/unittests/AST/CMakeLists.txt
@@ -1,3 +1,7 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
add_clang_unittest(ASTTests
ASTContextParentMapTest.cpp
ASTTypeTraitsTest.cpp
@@ -6,10 +10,16 @@
CommentParser.cpp
DeclPrinterTest.cpp
DeclTest.cpp
+ EvaluateAsRValueTest.cpp
+ ExternalASTSourceTest.cpp
SourceLocationTest.cpp
StmtPrinterTest.cpp
)
target_link_libraries(ASTTests
- clangAST clangASTMatchers clangTooling
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFrontend
+ clangTooling
)
diff --git a/unittests/AST/CommentParser.cpp b/unittests/AST/CommentParser.cpp
index f75c636..c72aef1 100644
--- a/unittests/AST/CommentParser.cpp
+++ b/unittests/AST/CommentParser.cpp
@@ -1420,6 +1420,26 @@
}
}
+TEST_F(CommentParserTest, Deprecated) {
+ const char *Sources[] = {
+ "/** @deprecated*/",
+ "/// @deprecated\n"
+ };
+
+ for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
+ FullComment *FC = parseString(Sources[i]);
+ ASSERT_TRUE(HasChildCount(FC, 2));
+
+ ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
+ {
+ BlockCommandComment *BCC;
+ ParagraphComment *PC;
+ ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "deprecated", PC));
+ ASSERT_TRUE(HasChildCount(PC, 0));
+ }
+ }
+}
+
} // unnamed namespace
} // end namespace comments
diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp
index 44fa742..5340756 100644
--- a/unittests/AST/DeclPrinterTest.cpp
+++ b/unittests/AST/DeclPrinterTest.cpp
@@ -74,10 +74,12 @@
PrintMatch Printer;
MatchFinder Finder;
Finder.addMatcher(NodeMatch, &Printer);
- OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
- return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
+ return testing::AssertionFailure()
+ << "Parsing error in \"" << Code.str() << "\"";
if (Printer.getNumFoundDecls() == 0)
return testing::AssertionFailure()
@@ -90,8 +92,8 @@
if (Printer.getPrinted() != ExpectedPrinted)
return ::testing::AssertionFailure()
- << "Expected \"" << ExpectedPrinted << "\", "
- "got \"" << Printer.getPrinted() << "\"";
+ << "Expected \"" << ExpectedPrinted.str() << "\", "
+ "got \"" << Printer.getPrinted().str() << "\"";
return ::testing::AssertionSuccess();
}
@@ -142,6 +144,19 @@
"input.cc");
}
+::testing::AssertionResult PrintedDeclCXX11nonMSCMatches(
+ StringRef Code,
+ const DeclarationMatcher &NodeMatch,
+ StringRef ExpectedPrinted) {
+ std::vector<std::string> Args(1, "-std=c++11");
+ Args.push_back("-fno-delayed-template-parsing");
+ return PrintedDeclMatches(Code,
+ Args,
+ NodeMatch,
+ ExpectedPrinted,
+ "input.cc");
+}
+
::testing::AssertionResult PrintedDeclObjCMatches(
StringRef Code,
const DeclarationMatcher &NodeMatch,
@@ -156,6 +171,40 @@
} // unnamed namespace
+TEST(DeclPrinter, TestTypedef1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "typedef int A;",
+ "A",
+ "typedef int A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTypedef2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "typedef const char *A;",
+ "A",
+ "typedef const char *A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTypedef3) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template <typename Y> class X {};"
+ "typedef X<int> A;",
+ "A",
+ "typedef X<int> A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTypedef4) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "namespace X { class Y {}; }"
+ "typedef X::Y A;",
+ "A",
+ "typedef X::Y A"));
+ // Should be: with semicolon
+}
+
TEST(DeclPrinter, TestNamespace1) {
ASSERT_TRUE(PrintedDeclCXX98Matches(
"namespace A { int B; }",
@@ -340,8 +389,8 @@
ASSERT_TRUE(PrintedDeclCXX11Matches(
"constexpr int A(int a);",
"A",
- "int A(int a)"));
- // WRONG; Should be: "constexpr int A(int a);"
+ "constexpr int A(int a)"));
+ // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl8) {
@@ -370,11 +419,11 @@
TEST(DeclPrinter, TestFunctionDecl11) {
ASSERT_TRUE(PrintedDeclCXX98Matches(
- "typedef long size_t;"
+ "typedef long ssize_t;"
"typedef int *pInt;"
- "void A(int a, pInt b, size_t c);",
+ "void A(int a, pInt b, ssize_t c);",
"A",
- "void A(int a, pInt b, size_t c)"));
+ "void A(int a, pInt b, ssize_t c)"));
// Should be: with semicolon
}
@@ -466,8 +515,7 @@
" constexpr A();"
"};",
constructorDecl(ofClass(hasName("A"))).bind("id"),
- "A()"));
- // WRONG; Should be: "constexpr A();"
+ "constexpr A()"));
}
TEST(DeclPrinter, TestCXXConstructorDecl8) {
@@ -498,18 +546,16 @@
"A<T...>(const A<T...> &a)"));
}
-#if !defined(_MSC_VER)
TEST(DeclPrinter, TestCXXConstructorDecl11) {
- ASSERT_TRUE(PrintedDeclCXX11Matches(
+ ASSERT_TRUE(PrintedDeclCXX11nonMSCMatches(
"template<typename... T>"
"struct A : public T... {"
" A(T&&... ts) : T(ts)... {}"
"};",
constructorDecl(ofClass(hasName("A"))).bind("id"),
- "A<T...>(T &&ts...) : T(ts)"));
+ "A<T...>(T &&ts...) : T(ts)..."));
// WRONG; Should be: "A(T&&... ts) : T(ts)..."
}
-#endif
TEST(DeclPrinter, TestCXXDestructorDecl1) {
ASSERT_TRUE(PrintedDeclCXX98Matches(
@@ -517,8 +563,7 @@
" ~A();"
"};",
destructorDecl(ofClass(hasName("A"))).bind("id"),
- "void ~A()"));
- // WRONG; Should be: "~A();"
+ "~A()"));
}
TEST(DeclPrinter, TestCXXDestructorDecl2) {
@@ -527,8 +572,7 @@
" virtual ~A();"
"};",
destructorDecl(ofClass(hasName("A"))).bind("id"),
- "virtual void ~A()"));
- // WRONG; Should be: "virtual ~A();"
+ "virtual ~A()"));
}
TEST(DeclPrinter, TestCXXConversionDecl1) {
@@ -537,8 +581,7 @@
" operator int();"
"};",
methodDecl(ofClass(hasName("A"))).bind("id"),
- "int operator int()"));
- // WRONG; Should be: "operator int();"
+ "operator int()"));
}
TEST(DeclPrinter, TestCXXConversionDecl2) {
@@ -547,8 +590,7 @@
" operator bool();"
"};",
methodDecl(ofClass(hasName("A"))).bind("id"),
- "bool operator _Bool()"));
- // WRONG; Should be: "operator bool();"
+ "operator bool()"));
}
TEST(DeclPrinter, TestCXXConversionDecl3) {
@@ -558,8 +600,7 @@
" operator Z();"
"};",
methodDecl(ofClass(hasName("A"))).bind("id"),
- "Z operator struct Z()"));
- // WRONG; Should be: "operator Z();"
+ "operator Z()"));
}
TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction1) {
@@ -756,8 +797,8 @@
" void A(int a) &;"
"};",
"A",
- "void A(int a)"));
- // WRONG; Should be: "void A(int a) &;"
+ "void A(int a) &"));
+ // Should be: with semicolon
}
TEST(DeclPrinter, TestCXXMethodDecl_RefQualifier2) {
@@ -766,8 +807,8 @@
" void A(int a) &&;"
"};",
"A",
- "void A(int a)"));
- // WRONG; Should be: "void A(int a) &&;"
+ "void A(int a) &&"));
+ // Should be: with semicolon
}
TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification1) {
diff --git a/unittests/AST/DeclTest.cpp b/unittests/AST/DeclTest.cpp
index c845da2..87aeef4 100644
--- a/unittests/AST/DeclTest.cpp
+++ b/unittests/AST/DeclTest.cpp
@@ -20,7 +20,7 @@
TEST(Decl, CleansUpAPValues) {
MatchFinder Finder;
- llvm::OwningPtr<FrontendActionFactory> Factory(
+ std::unique_ptr<FrontendActionFactory> Factory(
newFrontendActionFactory(&Finder));
// This is a regression test for a memory leak in APValues for structs that
diff --git a/unittests/AST/EvaluateAsRValueTest.cpp b/unittests/AST/EvaluateAsRValueTest.cpp
new file mode 100644
index 0000000..9120c93
--- /dev/null
+++ b/unittests/AST/EvaluateAsRValueTest.cpp
@@ -0,0 +1,112 @@
+//===- unittests/AST/EvaluateAsRValueTest.cpp -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// \file
+// \brief Unit tests for evaluation of constant initializers.
+//
+//===----------------------------------------------------------------------===//
+
+#include <map>
+#include <string>
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+#include "clang/AST/ASTConsumer.h"
+
+using namespace clang::tooling;
+
+namespace {
+// For each variable name encountered, whether its initializer was a
+// constant.
+typedef std::map<std::string, bool> VarInfoMap;
+
+/// \brief Records information on variable initializers to a map.
+class EvaluateConstantInitializersVisitor
+ : public clang::RecursiveASTVisitor<EvaluateConstantInitializersVisitor> {
+ public:
+ explicit EvaluateConstantInitializersVisitor(VarInfoMap &VarInfo)
+ : VarInfo(VarInfo) {}
+
+ /// \brief Checks that isConstantInitializer and EvaluateAsRValue agree
+ /// and don't crash.
+ ///
+ /// For each VarDecl with an initializer this also records in VarInfo
+ /// whether the initializer could be evaluated as a constant.
+ bool VisitVarDecl(const clang::VarDecl *VD) {
+ if (const clang::Expr *Init = VD->getInit()) {
+ clang::Expr::EvalResult Result;
+ bool WasEvaluated = Init->EvaluateAsRValue(Result, VD->getASTContext());
+ VarInfo[VD->getNameAsString()] = WasEvaluated;
+ EXPECT_EQ(WasEvaluated, Init->isConstantInitializer(VD->getASTContext(),
+ false /*ForRef*/));
+ }
+ return true;
+ }
+
+ private:
+ VarInfoMap &VarInfo;
+};
+
+class EvaluateConstantInitializersAction : public clang::ASTFrontendAction {
+ public:
+ clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &Compiler,
+ llvm::StringRef FilePath) override {
+ return new Consumer;
+ }
+
+ private:
+ class Consumer : public clang::ASTConsumer {
+ public:
+ ~Consumer() override {}
+
+ void HandleTranslationUnit(clang::ASTContext &Ctx) override {
+ VarInfoMap VarInfo;
+ EvaluateConstantInitializersVisitor Evaluator(VarInfo);
+ Evaluator.TraverseDecl(Ctx.getTranslationUnitDecl());
+ EXPECT_EQ(2u, VarInfo.size());
+ EXPECT_FALSE(VarInfo["Dependent"]);
+ EXPECT_TRUE(VarInfo["Constant"]);
+ EXPECT_EQ(2u, VarInfo.size());
+ }
+ };
+};
+}
+
+TEST(EvaluateAsRValue, FailsGracefullyForUnknownTypes) {
+ // This is a regression test; the AST library used to trigger assertion
+ // failures because it assumed that the type of initializers was always
+ // known (which is true only after template instantiation).
+ std::string ModesToTest[] = {"-std=c++03", "-std=c++11", "-std=c++1y"};
+ for (std::string const &Mode : ModesToTest) {
+ std::vector<std::string> Args(1, Mode);
+ Args.push_back("-fno-delayed-template-parsing");
+ ASSERT_TRUE(runToolOnCodeWithArgs(
+ new EvaluateConstantInitializersAction(),
+ "template <typename T>"
+ "struct vector {"
+ " explicit vector(int size);"
+ "};"
+ "template <typename R>"
+ "struct S {"
+ " vector<R> intervals() const {"
+ " vector<R> Dependent(2);"
+ " return Dependent;"
+ " }"
+ "};"
+ "void doSomething() {"
+ " int Constant = 2 + 2;"
+ " (void) Constant;"
+ "}",
+ Args));
+ }
+}
diff --git a/unittests/AST/ExternalASTSourceTest.cpp b/unittests/AST/ExternalASTSourceTest.cpp
new file mode 100644
index 0000000..5cc2def
--- /dev/null
+++ b/unittests/AST/ExternalASTSourceTest.cpp
@@ -0,0 +1,83 @@
+//===- unittest/AST/ExternalASTSourceTest.cpp -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains tests for Clang's ExternalASTSource.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ExternalASTSource.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace llvm;
+
+
+class TestFrontendAction : public ASTFrontendAction {
+public:
+ TestFrontendAction(ExternalASTSource *Source) : Source(Source) {}
+
+private:
+ virtual void ExecuteAction() {
+ getCompilerInstance().getASTContext().setExternalSource(Source);
+ getCompilerInstance().getASTContext().getTranslationUnitDecl()
+ ->setHasExternalVisibleStorage();
+ return ASTFrontendAction::ExecuteAction();
+ }
+
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ return new ASTConsumer;
+ }
+
+ IntrusiveRefCntPtr<ExternalASTSource> Source;
+};
+
+bool testExternalASTSource(ExternalASTSource *Source,
+ StringRef FileContents) {
+ CompilerInstance Compiler;
+ Compiler.createDiagnostics();
+
+ CompilerInvocation *Invocation = new CompilerInvocation;
+ Invocation->getPreprocessorOpts().addRemappedFile(
+ "test.cc", MemoryBuffer::getMemBuffer(FileContents));
+ const char *Args[] = { "test.cc" };
+ CompilerInvocation::CreateFromArgs(*Invocation, Args,
+ Args + array_lengthof(Args),
+ Compiler.getDiagnostics());
+ Compiler.setInvocation(Invocation);
+
+ TestFrontendAction Action(Source);
+ return Compiler.ExecuteAction(Action);
+}
+
+
+// Ensure that a failed name lookup into an external source only occurs once.
+TEST(ExternalASTSourceTest, FailedLookupOccursOnce) {
+ struct TestSource : ExternalASTSource {
+ TestSource(unsigned &Calls) : Calls(Calls) {}
+
+ bool FindExternalVisibleDeclsByName(const DeclContext*,
+ DeclarationName Name) {
+ if (Name.getAsString() == "j")
+ ++Calls;
+ return false;
+ }
+
+ unsigned &Calls;
+ };
+
+ unsigned Calls = 0;
+ ASSERT_TRUE(testExternalASTSource(new TestSource(Calls), "int j, k = j;"));
+ EXPECT_EQ(1u, Calls);
+}
diff --git a/unittests/AST/MatchVerifier.h b/unittests/AST/MatchVerifier.h
index 5a29cde..0265f4a 100644
--- a/unittests/AST/MatchVerifier.h
+++ b/unittests/AST/MatchVerifier.h
@@ -79,7 +79,7 @@
std::vector<std::string>& Args, Language L) {
MatchFinder Finder;
Finder.addMatcher(AMatcher.bind(""), this);
- OwningPtr<tooling::FrontendActionFactory> Factory(
+ std::unique_ptr<tooling::FrontendActionFactory> Factory(
tooling::newFrontendActionFactory(&Finder));
StringRef FileName;
diff --git a/unittests/AST/SourceLocationTest.cpp b/unittests/AST/SourceLocationTest.cpp
index 29156bc..6e94442 100644
--- a/unittests/AST/SourceLocationTest.cpp
+++ b/unittests/AST/SourceLocationTest.cpp
@@ -17,11 +17,11 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
+#include "MatchVerifier.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
-#include "MatchVerifier.h"
namespace clang {
namespace ast_matchers {
@@ -211,6 +211,16 @@
functionalCastExpr(), Lang_CXX11));
}
+TEST(CXXConstructExpr, SourceRange) {
+ RangeVerifier<CXXConstructExpr> Verifier;
+ Verifier.expectRange(3, 14, 3, 19);
+ EXPECT_TRUE(Verifier.match(
+ "struct A { A(int, int); };\n"
+ "void f(A a);\n"
+ "void g() { f({0, 0}); }",
+ constructExpr(), Lang_CXX11));
+}
+
TEST(CXXTemporaryObjectExpr, SourceRange) {
RangeVerifier<CXXTemporaryObjectExpr> Verifier;
Verifier.expectRange(2, 6, 2, 12);
diff --git a/unittests/AST/StmtPrinterTest.cpp b/unittests/AST/StmtPrinterTest.cpp
index 473ee13..d726517 100644
--- a/unittests/AST/StmtPrinterTest.cpp
+++ b/unittests/AST/StmtPrinterTest.cpp
@@ -64,19 +64,20 @@
}
};
-::testing::AssertionResult PrintedStmtMatches(
- StringRef Code,
- const std::vector<std::string> &Args,
- const DeclarationMatcher &NodeMatch,
- StringRef ExpectedPrinted) {
+template <typename T>
+::testing::AssertionResult
+PrintedStmtMatches(StringRef Code, const std::vector<std::string> &Args,
+ const T &NodeMatch, StringRef ExpectedPrinted) {
PrintMatch Printer;
MatchFinder Finder;
Finder.addMatcher(NodeMatch, &Printer);
- OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
if (!runToolOnCodeWithArgs(Factory->create(), Code, Args))
- return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
+ return testing::AssertionFailure()
+ << "Parsing error in \"" << Code.str() << "\"";
if (Printer.getNumFoundStmts() == 0)
return testing::AssertionFailure()
@@ -89,12 +90,21 @@
if (Printer.getPrinted() != ExpectedPrinted)
return ::testing::AssertionFailure()
- << "Expected \"" << ExpectedPrinted << "\", "
- "got \"" << Printer.getPrinted() << "\"";
+ << "Expected \"" << ExpectedPrinted.str() << "\", "
+ "got \"" << Printer.getPrinted().str() << "\"";
return ::testing::AssertionSuccess();
}
+::testing::AssertionResult
+PrintedStmtCXX98Matches(StringRef Code, const StatementMatcher &NodeMatch,
+ StringRef ExpectedPrinted) {
+ std::vector<std::string> Args;
+ Args.push_back("-std=c++98");
+ Args.push_back("-Wno-unused-value");
+ return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted);
+}
+
::testing::AssertionResult PrintedStmtCXX98Matches(
StringRef Code,
StringRef ContainingFunction,
@@ -109,6 +119,15 @@
ExpectedPrinted);
}
+::testing::AssertionResult
+PrintedStmtCXX11Matches(StringRef Code, const StatementMatcher &NodeMatch,
+ StringRef ExpectedPrinted) {
+ std::vector<std::string> Args;
+ Args.push_back("-std=c++11");
+ Args.push_back("-Wno-unused-value");
+ return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted);
+}
+
::testing::AssertionResult PrintedStmtMSMatches(
StringRef Code,
StringRef ContainingFunction,
@@ -163,3 +182,32 @@
"1.F , -1.F , 1. , -1. , 1.L , -1.L"));
// Should be: with semicolon
}
+
+TEST(StmtPrinter, TestCXXConversionDeclImplicit) {
+ ASSERT_TRUE(PrintedStmtCXX98Matches(
+ "struct A {"
+ "operator void *();"
+ "A operator&(A);"
+ "};"
+ "void bar(void *);"
+ "void foo(A a, A b) {"
+ " bar(a & b);"
+ "}",
+ memberCallExpr(anything()).bind("id"),
+ "a & b"));
+}
+
+TEST(StmtPrinter, TestCXXConversionDeclExplicit) {
+ ASSERT_TRUE(PrintedStmtCXX11Matches(
+ "struct A {"
+ "operator void *();"
+ "A operator&(A);"
+ "};"
+ "void bar(void *);"
+ "void foo(A a, A b) {"
+ " auto x = (a & b).operator void *();"
+ "}",
+ memberCallExpr(anything()).bind("id"),
+ "(a & b)"));
+ // WRONG; Should be: (a & b).operator void *()
+}
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index cc13c01..5d09700 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -12,6 +12,8 @@
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Host.h"
#include "gtest/gtest.h"
namespace clang {
@@ -103,12 +105,13 @@
TEST(DeclarationMatcher, MatchClass) {
DeclarationMatcher ClassMatcher(recordDecl());
-#if !defined(_MSC_VER)
- EXPECT_FALSE(matches("", ClassMatcher));
-#else
- // Matches class type_info.
- EXPECT_TRUE(matches("", ClassMatcher));
-#endif
+ llvm::Triple Triple(llvm::sys::getDefaultTargetTriple());
+ if (Triple.getOS() != llvm::Triple::Win32 ||
+ Triple.getEnvironment() != llvm::Triple::MSVC)
+ EXPECT_FALSE(matches("", ClassMatcher));
+ else
+ // Matches class type_info.
+ EXPECT_TRUE(matches("", ClassMatcher));
DeclarationMatcher ClassX = recordDecl(recordDecl(hasName("X")));
EXPECT_TRUE(matches("class X;", ClassX));
@@ -663,7 +666,7 @@
: Id(Id), ExpectedCount(ExpectedCount), Count(0),
ExpectedName(ExpectedName) {}
- void onEndOfTranslationUnit() LLVM_OVERRIDE {
+ void onEndOfTranslationUnit() override {
if (ExpectedCount != -1)
EXPECT_EQ(ExpectedCount, Count);
if (!ExpectedName.empty())
@@ -1000,7 +1003,7 @@
}
TEST(Matcher, Lambda) {
- EXPECT_TRUE(matches("auto f = [&] (int i) { return i; };",
+ EXPECT_TRUE(matches("auto f = [] (int i) { return i; };",
lambdaExpr()));
}
@@ -1038,7 +1041,7 @@
EXPECT_TRUE(matches("namespace ns { struct A {}; } struct B { ns::A a; };",
fieldDecl(hasType(asString("ns::A")))));
EXPECT_TRUE(matches("namespace { struct A {}; } struct B { A a; };",
- fieldDecl(hasType(asString("struct <anonymous>::A")))));
+ fieldDecl(hasType(asString("struct (anonymous namespace)::A")))));
}
TEST(Matcher, OverloadedOperatorCall) {
@@ -1300,15 +1303,16 @@
EXPECT_TRUE(matches("void f() { f(); }", CallFunctionF));
EXPECT_TRUE(notMatches("void f() { }", CallFunctionF));
-#if !defined(_MSC_VER)
- // FIXME: Make this work for MSVC.
- // Dependent contexts, but a non-dependent call.
- EXPECT_TRUE(matches("void f(); template <int N> void g() { f(); }",
- CallFunctionF));
- EXPECT_TRUE(
- matches("void f(); template <int N> struct S { void g() { f(); } };",
- CallFunctionF));
-#endif
+ if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getOS() !=
+ llvm::Triple::Win32) {
+ // FIXME: Make this work for MSVC.
+ // Dependent contexts, but a non-dependent call.
+ EXPECT_TRUE(matches("void f(); template <int N> void g() { f(); }",
+ CallFunctionF));
+ EXPECT_TRUE(
+ matches("void f(); template <int N> struct S { void g() { f(); } };",
+ CallFunctionF));
+ }
// Depedent calls don't match.
EXPECT_TRUE(
@@ -1479,7 +1483,7 @@
recordDecl(hasName("X"))))))));
}
-TEST(HasName, MatchesParameterVariableDeclartions) {
+TEST(HasName, MatchesParameterVariableDeclarations) {
EXPECT_TRUE(matches("class Y {}; class X { void x(int x) {} };",
methodDecl(hasAnyParameter(hasName("x")))));
EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };",
@@ -1527,6 +1531,19 @@
"A<int> a;",
classTemplateSpecializationDecl(hasAnyTemplateArgument(
refersToDeclaration(decl())))));
+
+ EXPECT_TRUE(matches(
+ "struct B { int next; };"
+ "template<int(B::*next_ptr)> struct A {};"
+ "A<&B::next> a;",
+ templateSpecializationType(hasAnyTemplateArgument(isExpr(
+ hasDescendant(declRefExpr(to(fieldDecl(hasName("next"))))))))));
+
+ EXPECT_TRUE(notMatches(
+ "template <typename T> struct A {};"
+ "A<int> a;",
+ templateSpecializationType(hasAnyTemplateArgument(
+ refersToDeclaration(decl())))));
}
TEST(Matcher, MatchesSpecificArgument) {
@@ -1540,6 +1557,17 @@
"A<int, bool> a;",
classTemplateSpecializationDecl(hasTemplateArgument(
1, refersToType(asString("int"))))));
+
+ EXPECT_TRUE(matches(
+ "template<typename T, typename U> class A {};"
+ "A<bool, int> a;",
+ templateSpecializationType(hasTemplateArgument(
+ 1, refersToType(asString("int"))))));
+ EXPECT_TRUE(notMatches(
+ "template<typename T, typename U> class A {};"
+ "A<int, bool> a;",
+ templateSpecializationType(hasTemplateArgument(
+ 1, refersToType(asString("int"))))));
}
TEST(Matcher, MatchesAccessSpecDecls) {
@@ -1561,6 +1589,13 @@
methodDecl(isVirtual())));
}
+TEST(Matcher, MatchesPureMethod) {
+ EXPECT_TRUE(matches("class X { virtual int f() = 0; };",
+ methodDecl(isPure(), hasName("::X::f"))));
+ EXPECT_TRUE(notMatches("class X { int f(); };",
+ methodDecl(isPure())));
+}
+
TEST(Matcher, MatchesConstMethod) {
EXPECT_TRUE(matches("struct A { void foo() const; };",
methodDecl(isConst())));
@@ -1637,6 +1672,17 @@
Constructor1Arg));
}
+TEST(Matcher, ConstructorListInitialization) {
+ StatementMatcher ConstructorListInit = constructExpr(isListInitialization());
+
+ EXPECT_TRUE(
+ matches("class X { public: X(int); }; void x() { X x{0}; }",
+ ConstructorListInit));
+ EXPECT_FALSE(
+ matches("class X { public: X(int); }; void x() { X x(0); }",
+ ConstructorListInit));
+}
+
TEST(Matcher,ThisExpr) {
EXPECT_TRUE(
matches("struct X { int a; int f () { return a; } };", thisExpr()));
@@ -2339,6 +2385,11 @@
forStmt(hasLoopInit(anything()))));
}
+TEST(For, ForRangeLoopInternals) {
+ EXPECT_TRUE(matches("void f(){ int a[] {1, 2}; for (int i : a); }",
+ forRangeStmt(hasLoopVariable(anything()))));
+}
+
TEST(For, NegativeForLoopInternals) {
EXPECT_TRUE(notMatches("void f(){ for (int i = 0; ; ++i); }",
forStmt(hasCondition(expr()))));
@@ -2608,13 +2659,13 @@
}
TEST(FunctionalCast, MatchesSimpleCase) {
- std::string foo_class = "class Foo { public: Foo(char*); };";
+ std::string foo_class = "class Foo { public: Foo(const char*); };";
EXPECT_TRUE(matches(foo_class + "void r() { Foo f = Foo(\"hello world\"); }",
functionalCastExpr()));
}
TEST(FunctionalCast, DoesNotMatchOtherCasts) {
- std::string FooClass = "class Foo { public: Foo(char*); };";
+ std::string FooClass = "class Foo { public: Foo(const char*); };";
EXPECT_TRUE(
notMatches(FooClass + "void r() { Foo f = (Foo) \"hello world\"; }",
functionalCastExpr()));
@@ -2892,6 +2943,15 @@
EXPECT_TRUE(matches("void x() { int a; }", declStmt()));
}
+TEST(ExprWithCleanups, MatchesExprWithCleanups) {
+ EXPECT_TRUE(matches("struct Foo { ~Foo(); };"
+ "const Foo f = Foo();",
+ varDecl(hasInitializer(exprWithCleanups()))));
+ EXPECT_FALSE(matches("struct Foo { };"
+ "const Foo f = Foo();",
+ varDecl(hasInitializer(exprWithCleanups()))));
+}
+
TEST(InitListExpression, MatchesInitListExpression) {
EXPECT_TRUE(matches("int a[] = { 1, 2 };",
initListExpr(hasType(asString("int [2]")))));
@@ -3617,12 +3677,16 @@
}
TEST(TypeMatching, MatchesAtomicTypes) {
- EXPECT_TRUE(matches("_Atomic(int) i;", atomicType()));
+ if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getOS() !=
+ llvm::Triple::Win32) {
+ // FIXME: Make this work for MSVC.
+ EXPECT_TRUE(matches("_Atomic(int) i;", atomicType()));
- EXPECT_TRUE(matches("_Atomic(int) i;",
- atomicType(hasValueType(isInteger()))));
- EXPECT_TRUE(notMatches("_Atomic(float) f;",
- atomicType(hasValueType(isInteger()))));
+ EXPECT_TRUE(matches("_Atomic(int) i;",
+ atomicType(hasValueType(isInteger()))));
+ EXPECT_TRUE(notMatches("_Atomic(float) f;",
+ atomicType(hasValueType(isInteger()))));
+ }
}
TEST(TypeMatching, MatchesAutoTypes) {
@@ -4111,12 +4175,13 @@
MatchFinder Finder;
VerifyStartOfTranslationUnit VerifyCallback;
Finder.addMatcher(decl(), &VerifyCallback);
- OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
EXPECT_TRUE(VerifyCallback.Called);
VerifyCallback.Called = false;
- OwningPtr<ASTUnit> AST(tooling::buildASTFromCode("int x;"));
+ std::unique_ptr<ASTUnit> AST(tooling::buildASTFromCode("int x;"));
ASSERT_TRUE(AST.get());
Finder.matchAST(AST->getASTContext());
EXPECT_TRUE(VerifyCallback.Called);
@@ -4138,12 +4203,13 @@
MatchFinder Finder;
VerifyEndOfTranslationUnit VerifyCallback;
Finder.addMatcher(decl(), &VerifyCallback);
- OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
EXPECT_TRUE(VerifyCallback.Called);
VerifyCallback.Called = false;
- OwningPtr<ASTUnit> AST(tooling::buildASTFromCode("int x;"));
+ std::unique_ptr<ASTUnit> AST(tooling::buildASTFromCode("int x;"));
ASSERT_TRUE(AST.get());
Finder.matchAST(AST->getASTContext());
EXPECT_TRUE(VerifyCallback.Called);
@@ -4204,7 +4270,6 @@
}
TEST(EqualsBoundNodeMatcher, UsingForEachDescendant) {
-
EXPECT_TRUE(matchAndVerifyResultTrue(
"int f() {"
" if (1) {"
@@ -4238,5 +4303,37 @@
new VerifyIdIsBoundTo<VarDecl>("d", 5)));
}
+TEST(EqualsBoundNodeMatcher, UnlessDescendantsOfAncestorsMatch) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "struct StringRef { int size() const; const char* data() const; };"
+ "void f(StringRef v) {"
+ " v.data();"
+ "}",
+ memberCallExpr(
+ callee(methodDecl(hasName("data"))),
+ on(declRefExpr(to(varDecl(hasType(recordDecl(hasName("StringRef"))))
+ .bind("var")))),
+ unless(hasAncestor(stmt(hasDescendant(memberCallExpr(
+ callee(methodDecl(anyOf(hasName("size"), hasName("length")))),
+ on(declRefExpr(to(varDecl(equalsBoundNode("var")))))))))))
+ .bind("data"),
+ new VerifyIdIsBoundTo<Expr>("data", 1)));
+
+ EXPECT_FALSE(matches(
+ "struct StringRef { int size() const; const char* data() const; };"
+ "void f(StringRef v) {"
+ " v.data();"
+ " v.size();"
+ "}",
+ memberCallExpr(
+ callee(methodDecl(hasName("data"))),
+ on(declRefExpr(to(varDecl(hasType(recordDecl(hasName("StringRef"))))
+ .bind("var")))),
+ unless(hasAncestor(stmt(hasDescendant(memberCallExpr(
+ callee(methodDecl(anyOf(hasName("size"), hasName("length")))),
+ on(declRefExpr(to(varDecl(equalsBoundNode("var")))))))))))
+ .bind("data")));
+}
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index f5bcd37..e224722 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -47,7 +47,7 @@
}
}
- void onEndOfTranslationUnit() LLVM_OVERRIDE {
+ void onEndOfTranslationUnit() override {
if (FindResultReviewer)
FindResultReviewer->onEndOfTranslationUnit();
}
@@ -67,7 +67,8 @@
Finder.addMatcher(AMatcher, new VerifyMatch(0, &Found));
if (!Finder.addDynamicMatcher(AMatcher, new VerifyMatch(0, &DynamicFound)))
return testing::AssertionFailure() << "Could not add dynamic matcher";
- OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
// Some tests use typeof, which is a gnu extension.
std::vector<std::string> Args(1, CompileArg);
if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
@@ -105,12 +106,13 @@
matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
BoundNodesCallback *FindResultVerifier,
bool ExpectResult) {
- OwningPtr<BoundNodesCallback> ScopedVerifier(FindResultVerifier);
+ std::unique_ptr<BoundNodesCallback> ScopedVerifier(FindResultVerifier);
bool VerifiedResult = false;
MatchFinder Finder;
Finder.addMatcher(
AMatcher, new VerifyMatch(FindResultVerifier, &VerifiedResult));
- OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
// Some tests use typeof, which is a gnu extension.
std::vector<std::string> Args(1, "-std=gnu++98");
if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
@@ -125,7 +127,7 @@
}
VerifiedResult = false;
- OwningPtr<ASTUnit> AST(buildASTFromCodeWithArgs(Code, Args));
+ std::unique_ptr<ASTUnit> AST(buildASTFromCodeWithArgs(Code, Args));
if (!AST.get())
return testing::AssertionFailure() << "Parsing error in \"" << Code
<< "\" while building AST";
diff --git a/unittests/ASTMatchers/CMakeLists.txt b/unittests/ASTMatchers/CMakeLists.txt
index 862c6a0..3ace9fe 100644
--- a/unittests/ASTMatchers/CMakeLists.txt
+++ b/unittests/ASTMatchers/CMakeLists.txt
@@ -1,15 +1,16 @@
set(LLVM_LINK_COMPONENTS
- ${LLVM_TARGETS_TO_BUILD}
- asmparser
- bitreader
- support
- mc
+ Support
)
add_clang_unittest(ASTMatchersTests
ASTMatchersTest.cpp)
target_link_libraries(ASTMatchersTests
- gtest gtest_main clangASTMatchers clangTooling)
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFrontend
+ clangTooling
+ )
add_subdirectory(Dynamic)
diff --git a/unittests/ASTMatchers/Dynamic/CMakeLists.txt b/unittests/ASTMatchers/Dynamic/CMakeLists.txt
index eb9fa54..8b95a7b 100644
--- a/unittests/ASTMatchers/Dynamic/CMakeLists.txt
+++ b/unittests/ASTMatchers/Dynamic/CMakeLists.txt
@@ -1,7 +1,16 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
add_clang_unittest(DynamicASTMatchersTests
VariantValueTest.cpp
ParserTest.cpp
RegistryTest.cpp)
target_link_libraries(DynamicASTMatchersTests
- gtest gtest_main clangASTMatchers clangDynamicASTMatchers clangTooling)
+ clangAST
+ clangASTMatchers
+ clangDynamicASTMatchers
+ clangFrontend
+ clangTooling
+ )
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index f19ec51..cdf4f92 100644
--- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -7,14 +7,14 @@
//
//===-------------------------------------------------------------------===//
-#include <string>
-#include <vector>
-
#include "../ASTMatchersTest.h"
#include "clang/ASTMatchers/Dynamic/Parser.h"
#include "clang/ASTMatchers/Dynamic/Registry.h"
-#include "gtest/gtest.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringMap.h"
+#include "gtest/gtest.h"
+#include <string>
+#include <vector>
namespace clang {
namespace ast_matchers {
@@ -39,15 +39,24 @@
Errors.push_back(Error.toStringFull());
}
- VariantMatcher actOnMatcherExpression(StringRef MatcherName,
+ llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName,
+ const SourceRange &NameRange,
+ Diagnostics *Error) {
+ const ExpectedMatchersTy::value_type *Matcher =
+ &*ExpectedMatchers.find(MatcherName);
+ return reinterpret_cast<MatcherCtor>(Matcher);
+ }
+
+ VariantMatcher actOnMatcherExpression(MatcherCtor Ctor,
const SourceRange &NameRange,
StringRef BindID,
ArrayRef<ParserValue> Args,
Diagnostics *Error) {
- MatcherInfo ToStore = { MatcherName, NameRange, Args, BindID };
+ const ExpectedMatchersTy::value_type *Matcher =
+ reinterpret_cast<const ExpectedMatchersTy::value_type *>(Ctor);
+ MatcherInfo ToStore = { Matcher->first, NameRange, Args, BindID };
Matchers.push_back(ToStore);
- return VariantMatcher::SingleMatcher(
- ExpectedMatchers.find(MatcherName)->second);
+ return VariantMatcher::SingleMatcher(Matcher->second);
}
struct MatcherInfo {
@@ -60,8 +69,9 @@
std::vector<std::string> Errors;
std::vector<VariantValue> Values;
std::vector<MatcherInfo> Matchers;
- std::map<std::string, ast_matchers::internal::Matcher<Stmt> >
- ExpectedMatchers;
+ typedef std::map<std::string, ast_matchers::internal::Matcher<Stmt> >
+ ExpectedMatchersTy;
+ ExpectedMatchersTy ExpectedMatchers;
};
TEST(ParserTest, ParseUnsigned) {
@@ -194,16 +204,19 @@
"1:5: Error parsing matcher. Found token <123> while looking for '('.",
ParseWithError("Foo 123"));
EXPECT_EQ(
+ "1:1: Matcher not found: Foo\n"
"1:9: Error parsing matcher. Found token <123> while looking for ','.",
ParseWithError("Foo(\"A\" 123)"));
EXPECT_EQ(
+ "1:1: Matcher not found: Foo\n"
"1:4: Error parsing matcher. Found end-of-code while looking for ')'.",
ParseWithError("Foo("));
EXPECT_EQ("1:1: End of code found while looking for token.",
ParseWithError(""));
EXPECT_EQ("Input value is not a matcher expression.",
ParseMatcherWithError("\"A\""));
- EXPECT_EQ("1:1: Error parsing argument 1 for matcher Foo.\n"
+ EXPECT_EQ("1:1: Matcher not found: Foo\n"
+ "1:1: Error parsing argument 1 for matcher Foo.\n"
"1:5: Invalid token <(> found when looking for a value.",
ParseWithError("Foo(("));
EXPECT_EQ("1:7: Expected end of code.", ParseWithError("expr()a"));
@@ -232,6 +245,20 @@
ParseWithError("callee(\"A\")"));
}
+TEST(ParserTest, Completion) {
+ std::vector<MatcherCompletion> Comps =
+ Parser::completeExpression("while", 5);
+ ASSERT_EQ(1u, Comps.size());
+ EXPECT_EQ("Stmt(", Comps[0].TypedText);
+ EXPECT_EQ("Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)",
+ Comps[0].MatcherDecl);
+
+ Comps = Parser::completeExpression("whileStmt().", 12);
+ ASSERT_EQ(1u, Comps.size());
+ EXPECT_EQ("bind(\"", Comps[0].TypedText);
+ EXPECT_EQ("bind", Comps[0].MatcherDecl);
+}
+
} // end anonymous namespace
} // end namespace dynamic
} // end namespace ast_matchers
diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index e716484..150f8c9 100644
--- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -7,11 +7,10 @@
//
//===-----------------------------------------------------------------------===//
-#include <vector>
-
#include "../ASTMatchersTest.h"
#include "clang/ASTMatchers/Dynamic/Registry.h"
#include "gtest/gtest.h"
+#include <vector>
namespace clang {
namespace ast_matchers {
@@ -36,12 +35,24 @@
return Out;
}
+ llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName,
+ Diagnostics *Error = 0) {
+ Diagnostics DummyError;
+ if (!Error) Error = &DummyError;
+ llvm::Optional<MatcherCtor> Ctor =
+ Registry::lookupMatcherCtor(MatcherName, SourceRange(), Error);
+ EXPECT_EQ("", DummyError.toStringFull());
+ return Ctor;
+ }
+
VariantMatcher constructMatcher(StringRef MatcherName,
Diagnostics *Error = NULL) {
Diagnostics DummyError;
if (!Error) Error = &DummyError;
- const VariantMatcher Out =
- Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error);
+ llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error);
+ VariantMatcher Out;
+ if (Ctor)
+ Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(), Error);
EXPECT_EQ("", DummyError.toStringFull());
return Out;
}
@@ -51,9 +62,11 @@
Diagnostics *Error = NULL) {
Diagnostics DummyError;
if (!Error) Error = &DummyError;
- const VariantMatcher Out = Registry::constructMatcher(
- MatcherName, SourceRange(), Args(Arg1), Error);
- EXPECT_EQ("", DummyError.toStringFull());
+ llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error);
+ VariantMatcher Out;
+ if (Ctor)
+ Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1), Error);
+ EXPECT_EQ("", DummyError.toStringFull()) << MatcherName;
return Out;
}
@@ -63,11 +76,58 @@
Diagnostics *Error = NULL) {
Diagnostics DummyError;
if (!Error) Error = &DummyError;
- const VariantMatcher Out = Registry::constructMatcher(
- MatcherName, SourceRange(), Args(Arg1, Arg2), Error);
+ llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error);
+ VariantMatcher Out;
+ if (Ctor)
+ Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1, Arg2),
+ Error);
EXPECT_EQ("", DummyError.toStringFull());
return Out;
}
+
+ typedef std::vector<MatcherCompletion> CompVector;
+
+ CompVector getCompletions() {
+ return Registry::getCompletions(
+ llvm::ArrayRef<std::pair<MatcherCtor, unsigned> >());
+ }
+
+ CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1) {
+ std::vector<std::pair<MatcherCtor, unsigned> > Context;
+ llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1);
+ if (!Ctor)
+ return CompVector();
+ Context.push_back(std::make_pair(*Ctor, ArgNo1));
+ return Registry::getCompletions(Context);
+ }
+
+ CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1,
+ StringRef MatcherName2, unsigned ArgNo2) {
+ std::vector<std::pair<MatcherCtor, unsigned> > Context;
+ llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1);
+ if (!Ctor)
+ return CompVector();
+ Context.push_back(std::make_pair(*Ctor, ArgNo1));
+ Ctor = lookupMatcherCtor(MatcherName2);
+ if (!Ctor)
+ return CompVector();
+ Context.push_back(std::make_pair(*Ctor, ArgNo2));
+ return Registry::getCompletions(Context);
+ }
+
+ bool hasCompletion(const CompVector &Comps, StringRef TypedText,
+ StringRef MatcherDecl = StringRef(), unsigned *Index = 0) {
+ for (CompVector::const_iterator I = Comps.begin(), E = Comps.end(); I != E;
+ ++I) {
+ if (I->TypedText == TypedText &&
+ (MatcherDecl.empty() || I->MatcherDecl == MatcherDecl)) {
+ if (Index)
+ *Index = I - Comps.begin();
+ return true;
+ }
+ }
+ return false;
+ }
};
TEST_F(RegistryTest, CanConstructNoArgs) {
@@ -151,6 +211,25 @@
Code = "class Z { public: void z() { this->z(); } };";
EXPECT_TRUE(matches(Code, CallExpr0));
EXPECT_FALSE(matches(Code, CallExpr1));
+
+ Matcher<Decl> DeclDecl = declaratorDecl(hasTypeLoc(
+ constructMatcher(
+ "loc", constructMatcher("asString", std::string("const double *")))
+ .getTypedMatcher<TypeLoc>()));
+
+ Matcher<NestedNameSpecifierLoc> NNSL =
+ constructMatcher(
+ "loc", VariantMatcher::SingleMatcher(nestedNameSpecifier(
+ specifiesType(hasDeclaration(recordDecl(hasName("A")))))))
+ .getTypedMatcher<NestedNameSpecifierLoc>();
+
+ Code = "const double * x = 0;";
+ EXPECT_TRUE(matches(Code, DeclDecl));
+ EXPECT_FALSE(matches(Code, NNSL));
+
+ Code = "struct A { struct B {}; }; A::B a_b;";
+ EXPECT_FALSE(matches(Code, DeclDecl));
+ EXPECT_TRUE(matches(Code, NNSL));
}
TEST_F(RegistryTest, PolymorphicMatchers) {
@@ -295,11 +374,22 @@
EXPECT_FALSE(matches("int i = 0;", D));
EXPECT_TRUE(matches("class Bar{};", D));
EXPECT_FALSE(matches("class OtherBar{};", D));
+
+ D = recordDecl(
+ has(fieldDecl(hasName("Foo"))),
+ constructMatcher(
+ "unless",
+ constructMatcher("namedDecl",
+ constructMatcher("hasName", std::string("Bar"))))
+ .getTypedMatcher<Decl>());
+
+ EXPECT_FALSE(matches("class Bar{ int Foo; };", D));
+ EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D));
}
TEST_F(RegistryTest, Errors) {
// Incorrect argument count.
- OwningPtr<Diagnostics> Error(new Diagnostics());
+ std::unique_ptr<Diagnostics> Error(new Diagnostics());
EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull());
EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
Error->toString());
@@ -307,6 +397,15 @@
EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).isNull());
EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
Error->toString());
+ Error.reset(new Diagnostics());
+ EXPECT_TRUE(constructMatcher("anyOf", Error.get()).isNull());
+ EXPECT_EQ("Incorrect argument count. (Expected = (2, )) != (Actual = 0)",
+ Error->toString());
+ Error.reset(new Diagnostics());
+ EXPECT_TRUE(constructMatcher("unless", std::string(), std::string(),
+ Error.get()).isNull());
+ EXPECT_EQ("Incorrect argument count. (Expected = (1, 1)) != (Actual = 2)",
+ Error->toString());
// Bad argument type
Error.reset(new Diagnostics());
@@ -324,7 +423,8 @@
// Bad argument type with variadic.
Error.reset(new Diagnostics());
- EXPECT_TRUE(constructMatcher("anyOf", std::string(), Error.get()).isNull());
+ EXPECT_TRUE(constructMatcher("anyOf", std::string(), std::string(),
+ Error.get()).isNull());
EXPECT_EQ(
"Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)",
Error->toString());
@@ -341,6 +441,47 @@
Error->toString());
}
+TEST_F(RegistryTest, Completion) {
+ CompVector Comps = getCompletions();
+ EXPECT_TRUE(hasCompletion(
+ Comps, "hasParent(", "Matcher<Decl|Stmt> hasParent(Matcher<Decl|Stmt>)"));
+ EXPECT_TRUE(hasCompletion(Comps, "whileStmt(",
+ "Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)"));
+
+ CompVector WhileComps = getCompletions("whileStmt", 0);
+
+ unsigned HasBodyIndex, HasParentIndex, AllOfIndex;
+ EXPECT_TRUE(hasCompletion(WhileComps, "hasBody(",
+ "Matcher<WhileStmt> hasBody(Matcher<Stmt>)",
+ &HasBodyIndex));
+ EXPECT_TRUE(hasCompletion(WhileComps, "hasParent(",
+ "Matcher<Stmt> hasParent(Matcher<Decl|Stmt>)",
+ &HasParentIndex));
+ EXPECT_TRUE(hasCompletion(WhileComps, "allOf(",
+ "Matcher<T> allOf(Matcher<T>...)", &AllOfIndex));
+ EXPECT_GT(HasParentIndex, HasBodyIndex);
+ EXPECT_GT(AllOfIndex, HasParentIndex);
+
+ EXPECT_FALSE(hasCompletion(WhileComps, "whileStmt("));
+ EXPECT_FALSE(hasCompletion(WhileComps, "ifStmt("));
+
+ CompVector AllOfWhileComps =
+ getCompletions("allOf", 0, "whileStmt", 0);
+ ASSERT_EQ(AllOfWhileComps.size(), WhileComps.size());
+ EXPECT_TRUE(std::equal(WhileComps.begin(), WhileComps.end(),
+ AllOfWhileComps.begin()));
+
+ CompVector DeclWhileComps =
+ getCompletions("decl", 0, "whileStmt", 0);
+ EXPECT_EQ(0u, DeclWhileComps.size());
+
+ CompVector NamedDeclComps = getCompletions("namedDecl", 0);
+ EXPECT_TRUE(
+ hasCompletion(NamedDeclComps, "isPublic()", "Matcher<Decl> isPublic()"));
+ EXPECT_TRUE(hasCompletion(NamedDeclComps, "hasName(\"",
+ "Matcher<NamedDecl> hasName(string)"));
+}
+
} // end anonymous namespace
} // end namespace dynamic
} // end namespace ast_matchers
diff --git a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
index d2b8a58..e62a464 100644
--- a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
@@ -117,7 +117,7 @@
EXPECT_FALSE(VariantValue(VariantMatcher::SingleMatcher(varDecl()))
.getMatcher()
.hasTypedMatcher<Stmt>());
-#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST && !defined(_MSC_VER)
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
// Trying to get the wrong matcher fails an assertion in Matcher<T>. We don't
// do this test when building with MSVC because its debug C runtime prints the
// assertion failure message as a wide string, which gtest doesn't understand.
diff --git a/unittests/Basic/CMakeLists.txt b/unittests/Basic/CMakeLists.txt
index 51db6ce..b8f69bf 100644
--- a/unittests/Basic/CMakeLists.txt
+++ b/unittests/Basic/CMakeLists.txt
@@ -1,7 +1,12 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
add_clang_unittest(BasicTests
CharInfoTest.cpp
FileManagerTest.cpp
SourceManagerTest.cpp
+ VirtualFileSystemTest.cpp
)
target_link_libraries(BasicTests
diff --git a/unittests/Basic/FileManagerTest.cpp b/unittests/Basic/FileManagerTest.cpp
index f8ce50d..9df8532 100644
--- a/unittests/Basic/FileManagerTest.cpp
+++ b/unittests/Basic/FileManagerTest.cpp
@@ -11,6 +11,7 @@
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "gtest/gtest.h"
+#include "llvm/Config/config.h"
using namespace llvm;
using namespace clang;
@@ -28,10 +29,13 @@
void InjectFileOrDirectory(const char *Path, ino_t INode, bool IsFile) {
FileData Data;
- memset(&Data, 0, sizeof(FileData));
- llvm::sys::fs::UniqueID ID(1, INode);
- Data.UniqueID = ID;
+ Data.Name = Path;
+ Data.Size = 0;
+ Data.ModTime = 0;
+ Data.UniqueID = llvm::sys::fs::UniqueID(1, INode);
Data.IsDirectory = !IsFile;
+ Data.IsNamedPipe = false;
+ Data.InPCH = false;
StatCalls[Path] = Data;
}
@@ -48,7 +52,7 @@
// Implement FileSystemStatCache::getStat().
virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile,
- int *FileDescriptor) {
+ vfs::File **F, vfs::FileSystem &FS) {
if (StatCalls.count(Path) != 0) {
Data = StatCalls[Path];
return CacheExists;
@@ -123,7 +127,7 @@
statCache->InjectDirectory("/tmp", 42);
statCache->InjectFile("/tmp/test", 43);
-#ifdef _WIN32
+#ifdef LLVM_ON_WIN32
const char *DirName = "C:.";
const char *FileName = "C:test";
statCache->InjectDirectory(DirName, 44);
@@ -140,7 +144,7 @@
ASSERT_TRUE(dir != NULL);
EXPECT_STREQ("/tmp", dir->getName());
-#ifdef _WIN32
+#ifdef LLVM_ON_WIN32
file = manager.getFile(FileName);
ASSERT_TRUE(file != NULL);
@@ -201,7 +205,7 @@
// The following tests apply to Unix-like system only.
-#ifndef _WIN32
+#ifndef LLVM_ON_WIN32
// getFile() returns the same FileEntry for real files that are aliases.
TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedRealFiles) {
@@ -231,6 +235,6 @@
EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
}
-#endif // !_WIN32
+#endif // !LLVM_ON_WIN32
} // anonymous namespace
diff --git a/unittests/Basic/VirtualFileSystemTest.cpp b/unittests/Basic/VirtualFileSystemTest.cpp
new file mode 100644
index 0000000..40d2f16
--- /dev/null
+++ b/unittests/Basic/VirtualFileSystemTest.cpp
@@ -0,0 +1,582 @@
+//===- unittests/Basic/VirtualFileSystem.cpp ---------------- VFS tests ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/VirtualFileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/SourceMgr.h"
+#include "gtest/gtest.h"
+#include <map>
+using namespace clang;
+using namespace llvm;
+using llvm::sys::fs::UniqueID;
+
+namespace {
+class DummyFileSystem : public vfs::FileSystem {
+ int FSID; // used to produce UniqueIDs
+ int FileID; // used to produce UniqueIDs
+ std::map<std::string, vfs::Status> FilesAndDirs;
+
+ static int getNextFSID() {
+ static int Count = 0;
+ return Count++;
+ }
+
+public:
+ DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
+
+ ErrorOr<vfs::Status> status(const Twine &Path) {
+ std::map<std::string, vfs::Status>::iterator I =
+ FilesAndDirs.find(Path.str());
+ if (I == FilesAndDirs.end())
+ return error_code(errc::no_such_file_or_directory, posix_category());
+ return I->second;
+ }
+ error_code openFileForRead(const Twine &Path,
+ std::unique_ptr<vfs::File> &Result) {
+ llvm_unreachable("unimplemented");
+ }
+ error_code getBufferForFile(const Twine &Name,
+ std::unique_ptr<MemoryBuffer> &Result,
+ int64_t FileSize = -1,
+ bool RequiresNullTerminator = true) {
+ llvm_unreachable("unimplemented");
+ }
+
+ void addEntry(StringRef Path, const vfs::Status &Status) {
+ FilesAndDirs[Path] = Status;
+ }
+
+ void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
+ vfs::Status S(Path, Path, UniqueID(FSID, FileID++), sys::TimeValue::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, Path, UniqueID(FSID, FileID++), sys::TimeValue::now(),
+ 0, 0, 0, sys::fs::file_type::directory_file, Perms);
+ addEntry(Path, S);
+ }
+
+ void addSymlink(StringRef Path) {
+ vfs::Status S(Path, Path, UniqueID(FSID, FileID++), sys::TimeValue::now(),
+ 0, 0, 0, sys::fs::file_type::symlink_file, sys::fs::all_all);
+ addEntry(Path, S);
+ }
+};
+} // end anonymous namespace
+
+TEST(VirtualFileSystemTest, StatusQueries) {
+ IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
+ ErrorOr<vfs::Status> Status((error_code()));
+
+ D->addRegularFile("/foo");
+ Status = D->status("/foo");
+ ASSERT_EQ(errc::success, Status.getError());
+ EXPECT_TRUE(Status->isStatusKnown());
+ EXPECT_FALSE(Status->isDirectory());
+ EXPECT_TRUE(Status->isRegularFile());
+ EXPECT_FALSE(Status->isSymlink());
+ EXPECT_FALSE(Status->isOther());
+ EXPECT_TRUE(Status->exists());
+
+ D->addDirectory("/bar");
+ Status = D->status("/bar");
+ ASSERT_EQ(errc::success, Status.getError());
+ EXPECT_TRUE(Status->isStatusKnown());
+ EXPECT_TRUE(Status->isDirectory());
+ EXPECT_FALSE(Status->isRegularFile());
+ EXPECT_FALSE(Status->isSymlink());
+ EXPECT_FALSE(Status->isOther());
+ EXPECT_TRUE(Status->exists());
+
+ D->addSymlink("/baz");
+ Status = D->status("/baz");
+ ASSERT_EQ(errc::success, Status.getError());
+ EXPECT_TRUE(Status->isStatusKnown());
+ EXPECT_FALSE(Status->isDirectory());
+ EXPECT_FALSE(Status->isRegularFile());
+ EXPECT_TRUE(Status->isSymlink());
+ EXPECT_FALSE(Status->isOther());
+ EXPECT_TRUE(Status->exists());
+
+ EXPECT_TRUE(Status->equivalent(*Status));
+ ErrorOr<vfs::Status> Status2 = D->status("/foo");
+ ASSERT_EQ(errc::success, Status2.getError());
+ EXPECT_FALSE(Status->equivalent(*Status2));
+}
+
+TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
+ IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
+ ErrorOr<vfs::Status> Status((error_code()));
+ EXPECT_FALSE(Status = D->status("/foo"));
+
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
+ EXPECT_FALSE(Status = O->status("/foo"));
+
+ D->addRegularFile("/foo");
+ Status = D->status("/foo");
+ EXPECT_EQ(errc::success, Status.getError());
+
+ ErrorOr<vfs::Status> Status2((error_code()));
+ Status2 = O->status("/foo");
+ EXPECT_EQ(errc::success, Status2.getError());
+ EXPECT_TRUE(Status->equivalent(*Status2));
+}
+
+TEST(VirtualFileSystemTest, OverlayFiles) {
+ IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Base));
+ O->pushOverlay(Middle);
+ O->pushOverlay(Top);
+
+ ErrorOr<vfs::Status> Status1((error_code())), Status2((error_code())),
+ Status3((error_code())), StatusB((error_code())), StatusM((error_code())),
+ StatusT((error_code()));
+
+ Base->addRegularFile("/foo");
+ StatusB = Base->status("/foo");
+ ASSERT_EQ(errc::success, StatusB.getError());
+ Status1 = O->status("/foo");
+ ASSERT_EQ(errc::success, Status1.getError());
+ Middle->addRegularFile("/foo");
+ StatusM = Middle->status("/foo");
+ ASSERT_EQ(errc::success, StatusM.getError());
+ Status2 = O->status("/foo");
+ ASSERT_EQ(errc::success, Status2.getError());
+ Top->addRegularFile("/foo");
+ StatusT = Top->status("/foo");
+ ASSERT_EQ(errc::success, StatusT.getError());
+ Status3 = O->status("/foo");
+ ASSERT_EQ(errc::success, Status3.getError());
+
+ EXPECT_TRUE(Status1->equivalent(*StatusB));
+ EXPECT_TRUE(Status2->equivalent(*StatusM));
+ EXPECT_TRUE(Status3->equivalent(*StatusT));
+
+ EXPECT_FALSE(Status1->equivalent(*Status2));
+ EXPECT_FALSE(Status2->equivalent(*Status3));
+ EXPECT_FALSE(Status1->equivalent(*Status3));
+}
+
+TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(Upper);
+
+ Lower->addDirectory("/lower-only");
+ Upper->addDirectory("/upper-only");
+
+ // non-merged paths should be the same
+ ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
+ ASSERT_EQ(errc::success, Status1.getError());
+ ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
+ ASSERT_EQ(errc::success, Status2.getError());
+ EXPECT_TRUE(Status1->equivalent(*Status2));
+
+ Status1 = Upper->status("/upper-only");
+ ASSERT_EQ(errc::success, Status1.getError());
+ Status2 = O->status("/upper-only");
+ ASSERT_EQ(errc::success, Status2.getError());
+ EXPECT_TRUE(Status1->equivalent(*Status2));
+}
+
+TEST(VirtualFileSystemTest, MergedDirPermissions) {
+ // merged directories get the permissions of the upper dir
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(Upper);
+
+ ErrorOr<vfs::Status> Status((error_code()));
+ Lower->addDirectory("/both", sys::fs::owner_read);
+ Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
+ Status = O->status("/both");
+ ASSERT_EQ(errc::success, Status.getError());
+ EXPECT_EQ(0740, Status->getPermissions());
+
+ // permissions (as usual) are not recursively applied
+ Lower->addRegularFile("/both/foo", sys::fs::owner_read);
+ Upper->addRegularFile("/both/bar", sys::fs::owner_write);
+ Status = O->status("/both/foo");
+ ASSERT_EQ(errc::success, Status.getError());
+ EXPECT_EQ(0400, Status->getPermissions());
+ Status = O->status("/both/bar");
+ ASSERT_EQ(errc::success, Status.getError());
+ EXPECT_EQ(0200, Status->getPermissions());
+}
+
+// NOTE: in the tests below, we use '//root/' as our root directory, since it is
+// a legal *absolute* path on Windows as well as *nix.
+class VFSFromYAMLTest : public ::testing::Test {
+public:
+ int NumDiagnostics;
+
+ void SetUp() {
+ NumDiagnostics = 0;
+ }
+
+ static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
+ VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
+ ++Test->NumDiagnostics;
+ }
+
+ IntrusiveRefCntPtr<vfs::FileSystem>
+ getFromYAMLRawString(StringRef Content,
+ IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
+ MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(Content);
+ return getVFSFromYAML(Buffer, CountingDiagHandler, this, ExternalFS);
+ }
+
+ IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
+ StringRef Content,
+ IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
+ std::string VersionPlusContent("{\n 'version':0,\n");
+ VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
+ return getFromYAMLRawString(VersionPlusContent, ExternalFS);
+ }
+};
+
+TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
+ IntrusiveRefCntPtr<vfs::FileSystem> FS;
+ FS = getFromYAMLString("");
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLString("[]");
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLString("'string'");
+ EXPECT_EQ(NULL, FS.getPtr());
+ EXPECT_EQ(3, NumDiagnostics);
+}
+
+TEST_F(VFSFromYAMLTest, MappedFiles) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addRegularFile("//root/foo/bar/a");
+ IntrusiveRefCntPtr<vfs::FileSystem> FS =
+ getFromYAMLString("{ 'roots': [\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//root/',\n"
+ " 'contents': [ {\n"
+ " 'type': 'file',\n"
+ " 'name': 'file1',\n"
+ " 'external-contents': '//root/foo/bar/a'\n"
+ " },\n"
+ " {\n"
+ " 'type': 'file',\n"
+ " 'name': 'file2',\n"
+ " 'external-contents': '//root/foo/b'\n"
+ " }\n"
+ " ]\n"
+ "}\n"
+ "]\n"
+ "}",
+ Lower);
+ ASSERT_TRUE(FS.getPtr() != NULL);
+
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(FS);
+
+ // file
+ ErrorOr<vfs::Status> S = O->status("//root/file1");
+ ASSERT_EQ(errc::success, S.getError());
+ EXPECT_EQ("//root/foo/bar/a", S->getName());
+
+ ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
+ EXPECT_EQ("//root/foo/bar/a", SLower->getName());
+ EXPECT_TRUE(S->equivalent(*SLower));
+
+ // directory
+ S = O->status("//root/");
+ ASSERT_EQ(errc::success, S.getError());
+ EXPECT_TRUE(S->isDirectory());
+ EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
+
+ // broken mapping
+ EXPECT_EQ(errc::no_such_file_or_directory, O->status("//root/file2").getError());
+ EXPECT_EQ(0, NumDiagnostics);
+}
+
+TEST_F(VFSFromYAMLTest, CaseInsensitive) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addRegularFile("//root/foo/bar/a");
+ IntrusiveRefCntPtr<vfs::FileSystem> FS =
+ getFromYAMLString("{ 'case-sensitive': 'false',\n"
+ " 'roots': [\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//root/',\n"
+ " 'contents': [ {\n"
+ " 'type': 'file',\n"
+ " 'name': 'XX',\n"
+ " 'external-contents': '//root/foo/bar/a'\n"
+ " }\n"
+ " ]\n"
+ "}]}",
+ Lower);
+ ASSERT_TRUE(FS.getPtr() != NULL);
+
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(FS);
+
+ ErrorOr<vfs::Status> S = O->status("//root/XX");
+ ASSERT_EQ(errc::success, S.getError());
+
+ ErrorOr<vfs::Status> SS = O->status("//root/xx");
+ ASSERT_EQ(errc::success, SS.getError());
+ EXPECT_TRUE(S->equivalent(*SS));
+ SS = O->status("//root/xX");
+ EXPECT_TRUE(S->equivalent(*SS));
+ SS = O->status("//root/Xx");
+ EXPECT_TRUE(S->equivalent(*SS));
+ EXPECT_EQ(0, NumDiagnostics);
+}
+
+TEST_F(VFSFromYAMLTest, CaseSensitive) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addRegularFile("//root/foo/bar/a");
+ IntrusiveRefCntPtr<vfs::FileSystem> FS =
+ getFromYAMLString("{ 'case-sensitive': 'true',\n"
+ " 'roots': [\n"
+ "{\n"
+ " 'type': 'directory',\n"
+ " 'name': '//root/',\n"
+ " 'contents': [ {\n"
+ " 'type': 'file',\n"
+ " 'name': 'XX',\n"
+ " 'external-contents': '//root/foo/bar/a'\n"
+ " }\n"
+ " ]\n"
+ "}]}",
+ Lower);
+ ASSERT_TRUE(FS.getPtr() != NULL);
+
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
+ new vfs::OverlayFileSystem(Lower));
+ O->pushOverlay(FS);
+
+ ErrorOr<vfs::Status> SS = O->status("//root/xx");
+ EXPECT_EQ(errc::no_such_file_or_directory, SS.getError());
+ SS = O->status("//root/xX");
+ EXPECT_EQ(errc::no_such_file_or_directory, SS.getError());
+ SS = O->status("//root/Xx");
+ EXPECT_EQ(errc::no_such_file_or_directory, SS.getError());
+ EXPECT_EQ(0, NumDiagnostics);
+}
+
+TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+
+ // invalid YAML at top-level
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ // invalid YAML in roots
+ FS = getFromYAMLString("{ 'roots':[}", Lower);
+ // invalid YAML in directory
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
+ Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+
+ // invalid configuration
+ FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+
+ // invalid roots
+ FS = getFromYAMLString("{ 'roots':'' }", Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLString("{ 'roots':{} }", Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+
+ // invalid entries
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
+ "'external-contents': 'other' }",
+ Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
+ Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
+ Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
+ Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
+ Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
+ Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+
+ // missing mandatory fields
+ FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLString(
+ "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+
+ // duplicate keys
+ FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLString(
+ "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
+ Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS =
+ getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
+ "'external-contents':'blah' } ] }",
+ Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+
+ // missing version
+ FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+
+ // bad version number
+ FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
+ EXPECT_EQ(NULL, FS.getPtr());
+ EXPECT_EQ(24, NumDiagnostics);
+}
+
+TEST_F(VFSFromYAMLTest, UseExternalName) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addRegularFile("//root/external/file");
+
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'roots': [\n"
+ " { 'type': 'file', 'name': '//root/A',\n"
+ " 'external-contents': '//root/external/file'\n"
+ " },\n"
+ " { 'type': 'file', 'name': '//root/B',\n"
+ " 'use-external-name': true,\n"
+ " 'external-contents': '//root/external/file'\n"
+ " },\n"
+ " { 'type': 'file', 'name': '//root/C',\n"
+ " 'use-external-name': false,\n"
+ " 'external-contents': '//root/external/file'\n"
+ " }\n"
+ "] }", Lower);
+ ASSERT_TRUE(NULL != FS.getPtr());
+
+ // default true
+ EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
+ // explicit
+ EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
+ EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
+
+ // global configuration
+ FS = getFromYAMLString(
+ "{ 'use-external-names': false,\n"
+ " 'roots': [\n"
+ " { 'type': 'file', 'name': '//root/A',\n"
+ " 'external-contents': '//root/external/file'\n"
+ " },\n"
+ " { 'type': 'file', 'name': '//root/B',\n"
+ " 'use-external-name': true,\n"
+ " 'external-contents': '//root/external/file'\n"
+ " },\n"
+ " { 'type': 'file', 'name': '//root/C',\n"
+ " 'use-external-name': false,\n"
+ " 'external-contents': '//root/external/file'\n"
+ " }\n"
+ "] }", Lower);
+ ASSERT_TRUE(NULL != FS.getPtr());
+
+ // default
+ EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
+ // explicit
+ EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
+ EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
+}
+
+TEST_F(VFSFromYAMLTest, MultiComponentPath) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addRegularFile("//root/other");
+
+ // file in roots
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'roots': [\n"
+ " { 'type': 'file', 'name': '//root/path/to/file',\n"
+ " 'external-contents': '//root/other' }]\n"
+ "}", Lower);
+ ASSERT_TRUE(NULL != FS.getPtr());
+ EXPECT_EQ(errc::success, FS->status("//root/path/to/file").getError());
+ EXPECT_EQ(errc::success, FS->status("//root/path/to").getError());
+ EXPECT_EQ(errc::success, FS->status("//root/path").getError());
+ EXPECT_EQ(errc::success, FS->status("//root/").getError());
+
+ // at the start
+ FS = getFromYAMLString(
+ "{ 'roots': [\n"
+ " { 'type': 'directory', 'name': '//root/path/to',\n"
+ " 'contents': [ { 'type': 'file', 'name': 'file',\n"
+ " 'external-contents': '//root/other' }]}]\n"
+ "}", Lower);
+ ASSERT_TRUE(NULL != FS.getPtr());
+ EXPECT_EQ(errc::success, FS->status("//root/path/to/file").getError());
+ EXPECT_EQ(errc::success, FS->status("//root/path/to").getError());
+ EXPECT_EQ(errc::success, FS->status("//root/path").getError());
+ EXPECT_EQ(errc::success, FS->status("//root/").getError());
+
+ // at the end
+ FS = getFromYAMLString(
+ "{ 'roots': [\n"
+ " { 'type': 'directory', 'name': '//root/',\n"
+ " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
+ " 'external-contents': '//root/other' }]}]\n"
+ "}", Lower);
+ ASSERT_TRUE(NULL != FS.getPtr());
+ EXPECT_EQ(errc::success, FS->status("//root/path/to/file").getError());
+ EXPECT_EQ(errc::success, FS->status("//root/path/to").getError());
+ EXPECT_EQ(errc::success, FS->status("//root/path").getError());
+ EXPECT_EQ(errc::success, FS->status("//root/").getError());
+}
+
+TEST_F(VFSFromYAMLTest, TrailingSlashes) {
+ IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ Lower->addRegularFile("//root/other");
+
+ // file in roots
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
+ "{ 'roots': [\n"
+ " { 'type': 'directory', 'name': '//root/path/to////',\n"
+ " 'contents': [ { 'type': 'file', 'name': 'file',\n"
+ " 'external-contents': '//root/other' }]}]\n"
+ "}", Lower);
+ ASSERT_TRUE(NULL != FS.getPtr());
+ EXPECT_EQ(errc::success, FS->status("//root/path/to/file").getError());
+ EXPECT_EQ(errc::success, FS->status("//root/path/to").getError());
+ EXPECT_EQ(errc::success, FS->status("//root/path").getError());
+ EXPECT_EQ(errc::success, FS->status("//root/").getError());
+}
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index 479b36f..cc13226 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -11,6 +11,7 @@
add_subdirectory(Basic)
add_subdirectory(Lex)
+add_subdirectory(Driver)
if(CLANG_ENABLE_STATIC_ANALYZER)
add_subdirectory(Frontend)
endif()
@@ -21,3 +22,6 @@
add_subdirectory(Format)
add_subdirectory(Sema)
endif()
+if(NOT WIN32) # FIXME:Investigating.
+ add_subdirectory(libclang)
+endif()
diff --git a/unittests/Driver/CMakeLists.txt b/unittests/Driver/CMakeLists.txt
new file mode 100644
index 0000000..8cc963b
--- /dev/null
+++ b/unittests/Driver/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_unittest(ClangDriverTests
+ MultilibTest.cpp
+ )
+
+target_link_libraries(ClangDriverTests
+ clangDriver
+ )
diff --git a/unittests/Driver/Makefile b/unittests/Driver/Makefile
new file mode 100644
index 0000000..21d19f3
--- /dev/null
+++ b/unittests/Driver/Makefile
@@ -0,0 +1,16 @@
+##===- unittests/Driver/Makefile ---------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL = ../..
+TESTNAME = Multilib
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) support option
+USEDLIBS = clangDriver.a clangBasic.a
+
+include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Driver/MultilibTest.cpp b/unittests/Driver/MultilibTest.cpp
new file mode 100644
index 0000000..dceace5
--- /dev/null
+++ b/unittests/Driver/MultilibTest.cpp
@@ -0,0 +1,356 @@
+//===- unittests/Driver/MultilibTest.cpp --- Multilib 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 Multilib and MultilibSet
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Multilib.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "gtest/gtest.h"
+
+using namespace clang::driver;
+using namespace clang;
+
+TEST(MultilibTest, MultilibValidity) {
+
+ ASSERT_TRUE(Multilib().isValid()) << "Empty multilib is not valid";
+
+ ASSERT_TRUE(Multilib().flag("+foo").isValid())
+ << "Single indicative flag is not valid";
+
+ ASSERT_TRUE(Multilib().flag("-foo").isValid())
+ << "Single contraindicative flag is not valid";
+
+ ASSERT_FALSE(Multilib().flag("+foo").flag("-foo").isValid())
+ << "Conflicting flags should invalidate the Multilib";
+
+ ASSERT_TRUE(Multilib().flag("+foo").flag("+foo").isValid())
+ << "Multilib should be valid even if it has the same flag twice";
+
+ ASSERT_TRUE(Multilib().flag("+foo").flag("-foobar").isValid())
+ << "Seemingly conflicting prefixes shouldn't actually conflict";
+}
+
+TEST(MultilibTest, OpEqReflexivity1) {
+ Multilib M;
+ ASSERT_TRUE(M == M) << "Multilib::operator==() is not reflexive";
+}
+
+TEST(MultilibTest, OpEqReflexivity2) {
+ ASSERT_TRUE(Multilib() == Multilib())
+ << "Separately constructed default multilibs are not equal";
+}
+
+TEST(MultilibTest, OpEqReflexivity3) {
+ Multilib M1, M2;
+ M1.flag("+foo");
+ M2.flag("+foo");
+ ASSERT_TRUE(M1 == M2) << "Multilibs with the same flag should be the same";
+}
+
+TEST(MultilibTest, OpEqInequivalence1) {
+ Multilib M1, M2;
+ M1.flag("+foo");
+ M2.flag("-foo");
+ ASSERT_FALSE(M1 == M2) << "Multilibs with conflicting flags are not the same";
+ ASSERT_FALSE(M2 == M1)
+ << "Multilibs with conflicting flags are not the same (commuted)";
+}
+
+TEST(MultilibTest, OpEqInequivalence2) {
+ Multilib M1, M2;
+ M2.flag("+foo");
+ ASSERT_FALSE(M1 == M2) << "Flags make Multilibs different";
+}
+
+TEST(MultilibTest, OpEqEquivalence1) {
+ Multilib M1, M2;
+ M1.flag("+foo");
+ M2.flag("+foo").flag("+foo");
+ ASSERT_TRUE(M1 == M2) << "Flag duplication shouldn't affect equivalence";
+ ASSERT_TRUE(M2 == M1)
+ << "Flag duplication shouldn't affect equivalence (commuted)";
+}
+
+TEST(MultilibTest, OpEqEquivalence2) {
+ Multilib M1("64");
+ Multilib M2;
+ M2.gccSuffix("/64");
+ ASSERT_TRUE(M1 == M2)
+ << "Constructor argument must match Multilib::gccSuffix()";
+ ASSERT_TRUE(M2 == M1)
+ << "Constructor argument must match Multilib::gccSuffix() (commuted)";
+}
+
+TEST(MultilibTest, OpEqEquivalence3) {
+ Multilib M1("", "32");
+ Multilib M2;
+ M2.osSuffix("/32");
+ ASSERT_TRUE(M1 == M2)
+ << "Constructor argument must match Multilib::osSuffix()";
+ ASSERT_TRUE(M2 == M1)
+ << "Constructor argument must match Multilib::osSuffix() (commuted)";
+}
+
+TEST(MultilibTest, OpEqEquivalence4) {
+ Multilib M1("", "", "16");
+ Multilib M2;
+ M2.includeSuffix("/16");
+ ASSERT_TRUE(M1 == M2)
+ << "Constructor argument must match Multilib::includeSuffix()";
+ ASSERT_TRUE(M2 == M1)
+ << "Constructor argument must match Multilib::includeSuffix() (commuted)";
+}
+
+TEST(MultilibTest, OpEqInequivalence3) {
+ Multilib M1("foo");
+ Multilib M2("bar");
+ ASSERT_FALSE(M1 == M2) << "Differing gccSuffixes should be different";
+ ASSERT_FALSE(M2 == M1)
+ << "Differing gccSuffixes should be different (commuted)";
+}
+
+TEST(MultilibTest, OpEqInequivalence4) {
+ Multilib M1("", "foo");
+ Multilib M2("", "bar");
+ ASSERT_FALSE(M1 == M2) << "Differing osSuffixes should be different";
+ ASSERT_FALSE(M2 == M1)
+ << "Differing osSuffixes should be different (commuted)";
+}
+
+TEST(MultilibTest, OpEqInequivalence5) {
+ Multilib M1("", "", "foo");
+ Multilib M2("", "", "bar");
+ ASSERT_FALSE(M1 == M2) << "Differing includeSuffixes should be different";
+ ASSERT_FALSE(M2 == M1)
+ << "Differing includeSuffixes should be different (commuted)";
+}
+
+TEST(MultilibTest, Construction1) {
+ Multilib M("gcc64", "os64", "inc64");
+ ASSERT_TRUE(M.gccSuffix() == "/gcc64");
+ ASSERT_TRUE(M.osSuffix() == "/os64");
+ ASSERT_TRUE(M.includeSuffix() == "/inc64");
+}
+
+TEST(MultilibTest, Construction2) {
+ Multilib M1;
+ Multilib M2("");
+ Multilib M3("", "");
+ Multilib M4("", "", "");
+ ASSERT_TRUE(M1 == M2)
+ << "Default arguments to Multilib constructor broken (first argument)";
+ ASSERT_TRUE(M1 == M3)
+ << "Default arguments to Multilib constructor broken (second argument)";
+ ASSERT_TRUE(M1 == M4)
+ << "Default arguments to Multilib constructor broken (third argument)";
+}
+
+TEST(MultilibTest, Construction3) {
+ Multilib M = Multilib().flag("+f1").flag("+f2").flag("-f3");
+ for (Multilib::flags_list::const_iterator I = M.flags().begin(),
+ E = M.flags().end();
+ I != E; ++I) {
+ ASSERT_TRUE(llvm::StringSwitch<bool>(*I)
+ .Cases("+f1", "+f2", "-f3", true)
+ .Default(false));
+ }
+}
+
+static bool hasFlag(const Multilib &M, StringRef Flag) {
+ for (Multilib::flags_list::const_iterator I = M.flags().begin(),
+ E = M.flags().end();
+ I != E; ++I) {
+ if (*I == Flag)
+ return true;
+ else if (StringRef(*I).substr(1) == Flag.substr(1))
+ return false;
+ }
+ return false;
+}
+
+TEST(MultilibTest, SetConstruction1) {
+ // Single maybe
+ MultilibSet MS;
+ ASSERT_TRUE(MS.size() == 0);
+ MS.Maybe(Multilib("64").flag("+m64"));
+ ASSERT_TRUE(MS.size() == 2);
+ for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
+ if (I->gccSuffix() == "/64")
+ ASSERT_TRUE(I->flags()[0] == "+m64");
+ else if (I->gccSuffix() == "")
+ ASSERT_TRUE(I->flags()[0] == "-m64");
+ else
+ FAIL() << "Unrecognized gccSufix: " << I->gccSuffix();
+ }
+}
+
+TEST(MultilibTest, SetConstruction2) {
+ // Double maybe
+ MultilibSet MS;
+ MS.Maybe(Multilib("sof").flag("+sof"));
+ MS.Maybe(Multilib("el").flag("+EL"));
+ ASSERT_TRUE(MS.size() == 4);
+ for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
+ ASSERT_TRUE(I->isValid()) << "Multilb " << *I << " should be valid";
+ ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
+ .Cases("", "/sof", "/el", "/sof/el", true)
+ .Default(false))
+ << "Multilib " << *I << " wasn't expected";
+ ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
+ .Case("", hasFlag(*I, "-sof"))
+ .Case("/sof", hasFlag(*I, "+sof"))
+ .Case("/el", hasFlag(*I, "-sof"))
+ .Case("/sof/el", hasFlag(*I, "+sof"))
+ .Default(false))
+ << "Multilib " << *I << " didn't have the appropriate {+,-}sof flag";
+ ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
+ .Case("", hasFlag(*I, "-EL"))
+ .Case("/sof", hasFlag(*I, "-EL"))
+ .Case("/el", hasFlag(*I, "+EL"))
+ .Case("/sof/el", hasFlag(*I, "+EL"))
+ .Default(false))
+ << "Multilib " << *I << " didn't have the appropriate {+,-}EL flag";
+ }
+}
+
+TEST(MultilibTest, SetPushback) {
+ MultilibSet MS;
+ MS.push_back(Multilib("one"));
+ MS.push_back(Multilib("two"));
+ ASSERT_TRUE(MS.size() == 2);
+ for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
+ ASSERT_TRUE(llvm::StringSwitch<bool>(I->gccSuffix())
+ .Cases("/one", "/two", true)
+ .Default(false));
+ }
+ MS.clear();
+ ASSERT_TRUE(MS.size() == 0);
+}
+
+TEST(MultilibTest, SetRegexFilter) {
+ MultilibSet MS;
+ MS.Maybe(Multilib("one"));
+ MS.Maybe(Multilib("two"));
+ MS.Maybe(Multilib("three"));
+ ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2)
+ << "Size before filter was incorrect. Contents:\n" << MS;
+ MS.FilterOut("/one/two/three");
+ ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2 - 1)
+ << "Size after filter was incorrect. Contents:\n" << MS;
+ for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
+ ASSERT_TRUE(I->gccSuffix() != "/one/two/three")
+ << "The filter should have removed " << *I;
+ }
+}
+
+TEST(MultilibTest, SetFilterObject) {
+ // Filter object
+ struct StartsWithP : public MultilibSet::FilterCallback {
+ bool operator()(const Multilib &M) const override {
+ return StringRef(M.gccSuffix()).startswith("/p");
+ }
+ };
+ MultilibSet MS;
+ MS.Maybe(Multilib("orange"));
+ MS.Maybe(Multilib("pear"));
+ MS.Maybe(Multilib("plum"));
+ ASSERT_EQ((int)MS.size(), 1 /* Default */ +
+ 1 /* pear */ +
+ 1 /* plum */ +
+ 1 /* pear/plum */ +
+ 1 /* orange */ +
+ 1 /* orange/pear */ +
+ 1 /* orange/plum */ +
+ 1 /* orange/pear/plum */ )
+ << "Size before filter was incorrect. Contents:\n" << MS;
+ MS.FilterOut(StartsWithP());
+ ASSERT_EQ((int)MS.size(), 1 /* Default */ +
+ 1 /* orange */ +
+ 1 /* orange/pear */ +
+ 1 /* orange/plum */ +
+ 1 /* orange/pear/plum */ )
+ << "Size after filter was incorrect. Contents:\n" << MS;
+ for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) {
+ ASSERT_FALSE(StringRef(I->gccSuffix()).startswith("/p"))
+ << "The filter should have removed " << *I;
+ }
+}
+
+TEST(MultilibTest, SetSelection1) {
+ MultilibSet MS1 = MultilibSet()
+ .Maybe(Multilib("64").flag("+m64"));
+
+ Multilib::flags_list FlagM64;
+ FlagM64.push_back("+m64");
+ Multilib SelectionM64;
+ ASSERT_TRUE(MS1.select(FlagM64, SelectionM64))
+ << "Flag set was {\"+m64\"}, but selection not found";
+ ASSERT_TRUE(SelectionM64.gccSuffix() == "/64")
+ << "Selection picked " << SelectionM64 << " which was not expected";
+
+ Multilib::flags_list FlagNoM64;
+ FlagNoM64.push_back("-m64");
+ Multilib SelectionNoM64;
+ ASSERT_TRUE(MS1.select(FlagNoM64, SelectionNoM64))
+ << "Flag set was {\"-m64\"}, but selection not found";
+ ASSERT_TRUE(SelectionNoM64.gccSuffix() == "")
+ << "Selection picked " << SelectionNoM64 << " which was not expected";
+}
+
+TEST(MultilibTest, SetSelection2) {
+ MultilibSet MS2 = MultilibSet()
+ .Maybe(Multilib("el").flag("+EL"))
+ .Maybe(Multilib("sf").flag("+SF"));
+
+ for (unsigned I = 0; I < 4; ++I) {
+ bool IsEL = I & 0x1;
+ bool IsSF = I & 0x2;
+ Multilib::flags_list Flags;
+ if (IsEL)
+ Flags.push_back("+EL");
+ else
+ Flags.push_back("-EL");
+
+ if (IsSF)
+ Flags.push_back("+SF");
+ else
+ Flags.push_back("-SF");
+
+ Multilib Selection;
+ ASSERT_TRUE(MS2.select(Flags, Selection)) << "Selection failed for "
+ << (IsEL ? "+EL" : "-EL") << " "
+ << (IsSF ? "+SF" : "-SF");
+
+ std::string Suffix;
+ if (IsEL)
+ Suffix += "/el";
+ if (IsSF)
+ Suffix += "/sf";
+
+ ASSERT_EQ(Selection.gccSuffix(), Suffix) << "Selection picked " << Selection
+ << " which was not expected ";
+ }
+}
+
+TEST(MultilibTest, SetCombineWith) {
+ MultilibSet Coffee;
+ Coffee.push_back(Multilib("coffee"));
+ MultilibSet Milk;
+ Milk.push_back(Multilib("milk"));
+ MultilibSet Latte;
+ ASSERT_EQ(Latte.size(), (unsigned)0);
+ Latte.combineWith(Coffee);
+ ASSERT_EQ(Latte.size(), (unsigned)1);
+ Latte.combineWith(Milk);
+ ASSERT_EQ(Latte.size(), (unsigned)2);
+}
diff --git a/unittests/Format/CMakeLists.txt b/unittests/Format/CMakeLists.txt
index 16d5764..14fc22d 100644
--- a/unittests/Format/CMakeLists.txt
+++ b/unittests/Format/CMakeLists.txt
@@ -1,18 +1,14 @@
set(LLVM_LINK_COMPONENTS
- ${LLVM_TARGETS_TO_BUILD}
- asmparser
- bitreader
- support
- mc
+ Support
)
add_clang_unittest(FormatTests
FormatTest.cpp
+ FormatTestJS.cpp
+ FormatTestProto.cpp
)
target_link_libraries(FormatTests
- clangAST
clangFormat
clangTooling
- clangRewriteCore
)
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index b6574c7..7606260 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -9,14 +9,18 @@
#define DEBUG_TYPE "format-test"
+#include "FormatTestUtils.h"
#include "clang/Format/Format.h"
-#include "clang/Lex/Lexer.h"
#include "llvm/Support/Debug.h"
#include "gtest/gtest.h"
namespace clang {
namespace format {
+FormatStyle getGoogleStyle() {
+ return getGoogleStyle(FormatStyle::LK_Cpp);
+}
+
class FormatTest : public ::testing::Test {
protected:
std::string format(llvm::StringRef Code, unsigned Offset, unsigned Length,
@@ -37,46 +41,6 @@
return format(Code, 0, Code.size(), Style);
}
- std::string messUp(llvm::StringRef Code) {
- std::string MessedUp(Code.str());
- bool InComment = false;
- bool InPreprocessorDirective = false;
- bool JustReplacedNewline = false;
- for (unsigned i = 0, e = MessedUp.size() - 1; i != e; ++i) {
- if (MessedUp[i] == '/' && MessedUp[i + 1] == '/') {
- if (JustReplacedNewline)
- MessedUp[i - 1] = '\n';
- InComment = true;
- } else if (MessedUp[i] == '#' && (JustReplacedNewline || i == 0)) {
- if (i != 0)
- MessedUp[i - 1] = '\n';
- InPreprocessorDirective = true;
- } else if (MessedUp[i] == '\\' && MessedUp[i + 1] == '\n') {
- MessedUp[i] = ' ';
- MessedUp[i + 1] = ' ';
- } else if (MessedUp[i] == '\n') {
- if (InComment) {
- InComment = false;
- } else if (InPreprocessorDirective) {
- InPreprocessorDirective = false;
- } else {
- JustReplacedNewline = true;
- MessedUp[i] = ' ';
- }
- } else if (MessedUp[i] != ' ') {
- JustReplacedNewline = false;
- }
- }
- std::string WithoutWhitespace;
- if (MessedUp[0] != ' ')
- WithoutWhitespace.push_back(MessedUp[0]);
- for (unsigned i = 1, e = MessedUp.size(); i != e; ++i) {
- if (MessedUp[i] != ' ' || MessedUp[i - 1] != ' ')
- WithoutWhitespace.push_back(MessedUp[i]);
- }
- return WithoutWhitespace;
- }
-
FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) {
FormatStyle Style = getLLVMStyle();
Style.ColumnLimit = ColumnLimit;
@@ -91,7 +55,7 @@
void verifyFormat(llvm::StringRef Code,
const FormatStyle &Style = getLLVMStyle()) {
- EXPECT_EQ(Code.str(), format(messUp(Code), Style));
+ EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
}
void verifyGoogleFormat(llvm::StringRef Code) {
@@ -107,11 +71,11 @@
};
TEST_F(FormatTest, MessUp) {
- EXPECT_EQ("1 2 3", messUp("1 2 3"));
- EXPECT_EQ("1 2 3\n", messUp("1\n2\n3\n"));
- EXPECT_EQ("a\n//b\nc", messUp("a\n//b\nc"));
- EXPECT_EQ("a\n#b\nc", messUp("a\n#b\nc"));
- EXPECT_EQ("a\n#b c d\ne", messUp("a\n#b\\\nc\\\nd\ne"));
+ EXPECT_EQ("1 2 3", test::messUp("1 2 3"));
+ EXPECT_EQ("1 2 3\n", test::messUp("1\n2\n3\n"));
+ EXPECT_EQ("a\n//b\nc", test::messUp("a\n//b\nc"));
+ EXPECT_EQ("a\n#b\nc", test::messUp("a\n#b\nc"));
+ EXPECT_EQ("a\n#b c d\ne", test::messUp("a\n#b\\\nc\\\nd\ne"));
}
//===----------------------------------------------------------------------===//
@@ -144,7 +108,7 @@
}
TEST_F(FormatTest, NestedNameSpecifiers) {
- verifyFormat("vector< ::Type> v;");
+ verifyFormat("vector<::Type> v;");
verifyFormat("::ns::SomeFunction(::ns::SomeOtherFunction())");
verifyFormat("static constexpr bool Bar = decltype(bar())::value;");
}
@@ -187,10 +151,10 @@
26, 0, getLLVMStyleWithColumns(12)));
EXPECT_EQ("#define A \\\n"
" int a; \\\n"
- " int b;",
+ " int b;",
format("#define A \\\n"
" int a; \\\n"
- " int b;",
+ " int b;",
25, 0, getLLVMStyleWithColumns(12)));
}
@@ -210,6 +174,51 @@
"\n"
"};"));
+ // Don't remove empty lines at the start of namespaces.
+ EXPECT_EQ("namespace N {\n"
+ "\n"
+ "int i;\n"
+ "}",
+ format("namespace N {\n"
+ "\n"
+ "int i;\n"
+ "}",
+ getGoogleStyle()));
+
+ // Remove empty lines at the beginning and end of blocks.
+ EXPECT_EQ("void f() {\n"
+ "\n"
+ " if (a) {\n"
+ "\n"
+ " f();\n"
+ " }\n"
+ "}",
+ format("void f() {\n"
+ "\n"
+ " if (a) {\n"
+ "\n"
+ " f();\n"
+ "\n"
+ " }\n"
+ "\n"
+ "}",
+ getLLVMStyle()));
+ EXPECT_EQ("void f() {\n"
+ " if (a) {\n"
+ " f();\n"
+ " }\n"
+ "}",
+ format("void f() {\n"
+ "\n"
+ " if (a) {\n"
+ "\n"
+ " f();\n"
+ "\n"
+ " }\n"
+ "\n"
+ "}",
+ getGoogleStyle()));
+
// Don't remove empty lines in more complex control statements.
EXPECT_EQ("void f() {\n"
" if (a) {\n"
@@ -293,7 +302,7 @@
" f();\n"
"}",
AllowsMergedIf);
- verifyFormat("if (a) { /* Never merge this */\n"
+ verifyFormat("if (a) {/* Never merge this */\n"
" f();\n"
"}",
AllowsMergedIf);
@@ -452,6 +461,17 @@
" aaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaa, aaaaaaaaaaaaa)) {\n}");
verifyFormat("for (const aaaaaaaaaaaaaaaaaaaaa &aaaaaaaaa :\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n}");
+ verifyFormat("for (aaaaaaaaa aaaaaaaaaaaaaaaaaaaaa :\n"
+ " aaaaaaaaaaaa.aaaaaaaaaaaa().aaaaaaaaa().a()) {\n}");
+}
+
+TEST_F(FormatTest, ForEachLoops) {
+ verifyFormat("void f() {\n"
+ " foreach (Item *item, itemlist) {}\n"
+ " Q_FOREACH (Item *item, itemlist) {}\n"
+ " BOOST_FOREACH (Item *item, itemlist) {}\n"
+ " UNKNOWN_FORACH(Item * item, itemlist) {}\n"
+ "}");
}
TEST_F(FormatTest, FormatsWhileLoop) {
@@ -637,6 +657,9 @@
verifyFormat("SomeObject\n"
" // Calling someFunction on SomeObject\n"
" .someFunction();");
+ verifyFormat("auto result = SomeObject\n"
+ " // Calling someFunction on SomeObject\n"
+ " .someFunction();");
verifyFormat("void f(int i, // some comment (probably for i)\n"
" int j, // some comment (probably for j)\n"
" int k); // some comment (probably for k)");
@@ -731,11 +754,10 @@
verifyGoogleFormat("#endif // HEADER_GUARD");
verifyFormat("const char *test[] = {\n"
- " // A\n"
- " \"aaaa\",\n"
- " // B\n"
- " \"aaaaa\",\n"
- "};");
+ " // A\n"
+ " \"aaaa\",\n"
+ " // B\n"
+ " \"aaaaa\"};");
verifyGoogleFormat(
"aaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaa); // 81_cols_with_this_comment");
@@ -809,6 +831,32 @@
"otherLine();"));
}
+TEST_F(FormatTest, KeepsParameterWithTrailingCommentsOnTheirOwnLine) {
+ EXPECT_EQ("SomeFunction(a,\n"
+ " b, // comment\n"
+ " c);",
+ format("SomeFunction(a,\n"
+ " b, // comment\n"
+ " c);"));
+ EXPECT_EQ("SomeFunction(a, b,\n"
+ " // comment\n"
+ " c);",
+ format("SomeFunction(a,\n"
+ " b,\n"
+ " // comment\n"
+ " c);"));
+ EXPECT_EQ("SomeFunction(a, b, // comment (unclear relation)\n"
+ " c);",
+ format("SomeFunction(a, b, // comment (unclear relation)\n"
+ " c);"));
+ EXPECT_EQ("SomeFunction(a, // comment\n"
+ " b,\n"
+ " c); // comment",
+ format("SomeFunction(a, // comment\n"
+ " b,\n"
+ " c); // comment"));
+}
+
TEST_F(FormatTest, CanFormatCommentsLocally) {
EXPECT_EQ("int a; // comment\n"
"int b; // comment",
@@ -829,6 +877,43 @@
"int b;\n"
"int c; // unrelated comment",
31, 0, getLLVMStyle()));
+
+ EXPECT_EQ("int a; // This\n"
+ " // is\n"
+ " // a",
+ format("int a; // This\n"
+ " // is\n"
+ " // a",
+ 0, 0, getLLVMStyle()));
+ EXPECT_EQ("int a; // This\n"
+ " // is\n"
+ " // a\n"
+ "// This is b\n"
+ "int b;",
+ format("int a; // This\n"
+ " // is\n"
+ " // a\n"
+ "// This is b\n"
+ "int b;",
+ 0, 0, getLLVMStyle()));
+ EXPECT_EQ("int a; // This\n"
+ " // is\n"
+ " // a\n"
+ "\n"
+ " // This is unrelated",
+ format("int a; // This\n"
+ " // is\n"
+ " // a\n"
+ "\n"
+ " // This is unrelated",
+ 0, 0, getLLVMStyle()));
+ EXPECT_EQ("int a;\n"
+ "// This is\n"
+ "// not formatted. ",
+ format("int a;\n"
+ "// This is\n"
+ "// not formatted. ",
+ 0, 0, getLLVMStyle()));
}
TEST_F(FormatTest, RemovesTrailingWhitespaceOfComments) {
@@ -842,11 +927,12 @@
TEST_F(FormatTest, UnderstandsBlockComments) {
verifyFormat("f(/*noSpaceAfterParameterNamingComment=*/true);");
- EXPECT_EQ(
- "f(aaaaaaaaaaaaaaaaaaaaaaaaa, /* Trailing comment for aa... */\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbb);",
- format("f(aaaaaaaaaaaaaaaaaaaaaaaaa , \\\n/* Trailing comment for aa... */\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbb);"));
+ verifyFormat("void f() { g(/*aaa=*/x, /*bbb=*/!y); }");
+ EXPECT_EQ("f(aaaaaaaaaaaaaaaaaaaaaaaaa, /* Trailing comment for aa... */\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbb);",
+ format("f(aaaaaaaaaaaaaaaaaaaaaaaaa , \\\n"
+ "/* Trailing comment for aa... */\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbb);"));
EXPECT_EQ(
"f(aaaaaaaaaaaaaaaaaaaaaaaaa,\n"
" /* Leading comment for bb... */ bbbbbbbbbbbbbbbbbbbbbbbbb);",
@@ -869,6 +955,11 @@
" /* parameter 3 */ aaaaaa,\n"
" /* parameter 4 */ aaaaaa);",
NoBinPacking);
+
+ // Aligning block comments in macros.
+ verifyGoogleFormat("#define A \\\n"
+ " int i; /*a*/ \\\n"
+ " int jjj; /*b*/");
}
TEST_F(FormatTest, AlignsBlockComments) {
@@ -997,14 +1088,14 @@
format("// A comment before a macro definition\n"
"#define a b",
getLLVMStyleWithColumns(20)));
- EXPECT_EQ("void ffffff(int aaaaaaaaa, // wwww\n"
- " int a, int bbb, // xxxxxxx\n"
- " // yyyyyyyyy\n"
- " int c, int d, int e) {}",
+ EXPECT_EQ("void\n"
+ "ffffff(int aaaaaaaaa, // wwww\n"
+ " int bbbbbbbbbb, // xxxxxxx\n"
+ " // yyyyyyyyyy\n"
+ " int c, int d, int e) {}",
format("void ffffff(\n"
" int aaaaaaaaa, // wwww\n"
- " int a,\n"
- " int bbb, // xxxxxxx yyyyyyyyy\n"
+ " int bbbbbbbbbb, // xxxxxxx yyyyyyyyyy\n"
" int c, int d, int e) {}",
getLLVMStyleWithColumns(40)));
EXPECT_EQ("//\t aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
@@ -1020,6 +1111,21 @@
format("#define XXX //q w e r t y u i", getLLVMStyleWithColumns(22)));
}
+TEST_F(FormatTest, PreservesHangingIndentInCxxComments) {
+ EXPECT_EQ("// A comment\n"
+ "// that doesn't\n"
+ "// fit on one\n"
+ "// line",
+ format("// A comment that doesn't fit on one line",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/// A comment\n"
+ "/// that doesn't\n"
+ "/// fit on one\n"
+ "/// line",
+ format("/// A comment that doesn't fit on one line",
+ getLLVMStyleWithColumns(20)));
+}
+
TEST_F(FormatTest, DontSplitLineCommentsWithEscapedNewlines) {
EXPECT_EQ("// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
"// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n"
@@ -1046,6 +1152,17 @@
getLLVMStyleWithColumns(49)));
}
+TEST_F(FormatTest, DontSplitLineCommentsWithPragmas) {
+ FormatStyle Pragmas = getLLVMStyleWithColumns(30);
+ Pragmas.CommentPragmas = "^ IWYU pragma:";
+ EXPECT_EQ(
+ "// IWYU pragma: aaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbb",
+ format("// IWYU pragma: aaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbb", Pragmas));
+ EXPECT_EQ(
+ "/* IWYU pragma: aaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbb */",
+ format("/* IWYU pragma: aaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbb */", Pragmas));
+}
+
TEST_F(FormatTest, PriorityOfCommentBreaking) {
EXPECT_EQ("if (xxx ==\n"
" yyy && // aaaaaaaaaaaa bbbbbbbbb\n"
@@ -1068,9 +1185,9 @@
format("if (xxxxxxxxxx && yyy || // aaaaaa bbbbbbbb cccc\n"
" zzz) q();",
getLLVMStyleWithColumns(40)));
- EXPECT_EQ("fffffffff(&xxx, // aaaaaaaaaaaa\n"
- " // bbbbbbbbbbb\n"
- " zzz);",
+ EXPECT_EQ("fffffffff(\n"
+ " &xxx, // aaaaaaaaaaaa bbbbbbbbbbb\n"
+ " zzz);",
format("fffffffff(&xxx, // aaaaaaaaaaaa bbbbbbbbbbb\n"
" zzz);",
getLLVMStyleWithColumns(40)));
@@ -1309,21 +1426,21 @@
TEST_F(FormatTest, CommentsInStaticInitializers) {
EXPECT_EQ(
- "static SomeType type = { aaaaaaaaaaaaaaaaaaaa, /* comment */\n"
- " aaaaaaaaaaaaaaaaaaaa /* comment */,\n"
- " /* comment */ aaaaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaaaaaaa, // comment\n"
- " aaaaaaaaaaaaaaaaaaaa };",
+ "static SomeType type = {aaaaaaaaaaaaaaaaaaaa, /* comment */\n"
+ " aaaaaaaaaaaaaaaaaaaa /* comment */,\n"
+ " /* comment */ aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaa, // comment\n"
+ " aaaaaaaaaaaaaaaaaaaa};",
format("static SomeType type = { aaaaaaaaaaaaaaaaaaaa , /* comment */\n"
" aaaaaaaaaaaaaaaaaaaa /* comment */ ,\n"
" /* comment */ aaaaaaaaaaaaaaaaaaaa ,\n"
" aaaaaaaaaaaaaaaaaaaa , // comment\n"
" aaaaaaaaaaaaaaaaaaaa };"));
- verifyFormat("static SomeType type = { aaaaaaaaaaa, // comment for aa...\n"
- " bbbbbbbbbbb, ccccccccccc };");
- verifyFormat("static SomeType type = { aaaaaaaaaaa,\n"
- " // comment for bb....\n"
- " bbbbbbbbbbb, ccccccccccc };");
+ verifyFormat("static SomeType type = {aaaaaaaaaaa, // comment for aa...\n"
+ " bbbbbbbbbbb, ccccccccccc};");
+ verifyFormat("static SomeType type = {aaaaaaaaaaa,\n"
+ " // comment for bb....\n"
+ " bbbbbbbbbbb, ccccccccccc};");
verifyGoogleFormat(
"static SomeType type = {aaaaaaaaaaa, // comment for aa...\n"
" bbbbbbbbbbb, ccccccccccc};");
@@ -1331,23 +1448,22 @@
" // comment for bb....\n"
" bbbbbbbbbbb, ccccccccccc};");
- verifyFormat("S s = { { a, b, c }, // Group #1\n"
- " { d, e, f }, // Group #2\n"
- " { g, h, i } }; // Group #3");
- verifyFormat("S s = { { // Group #1\n"
- " a, b, c },\n"
- " { // Group #2\n"
- " d, e, f },\n"
- " { // Group #3\n"
- " g, h, i } };");
+ verifyFormat("S s = {{a, b, c}, // Group #1\n"
+ " {d, e, f}, // Group #2\n"
+ " {g, h, i}}; // Group #3");
+ verifyFormat("S s = {{// Group #1\n"
+ " a, b, c},\n"
+ " {// Group #2\n"
+ " d, e, f},\n"
+ " {// Group #3\n"
+ " g, h, i}};");
EXPECT_EQ("S s = {\n"
- " // Some comment\n"
- " a,\n"
+ " // Some comment\n"
+ " a,\n"
"\n"
- " // Comment after empty line\n"
- " b\n"
- "}",
+ " // Comment after empty line\n"
+ " b}",
format("S s = {\n"
" // Some comment\n"
" a,\n"
@@ -1356,12 +1472,11 @@
" b\n"
"}"));
EXPECT_EQ("S s = {\n"
- " /* Some comment */\n"
- " a,\n"
+ " /* Some comment */\n"
+ " a,\n"
"\n"
- " /* Comment after empty line */\n"
- " b\n"
- "}",
+ " /* Comment after empty line */\n"
+ " b}",
format("S s = {\n"
" /* Some comment */\n"
" a,\n"
@@ -1370,10 +1485,9 @@
" b\n"
"}"));
verifyFormat("const uint8_t aaaaaaaaaaaaaaaaaaaaaa[0] = {\n"
- " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // comment\n"
- " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // comment\n"
- " 0x00, 0x00, 0x00, 0x00 // comment\n"
- "};");
+ " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // comment\n"
+ " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // comment\n"
+ " 0x00, 0x00, 0x00, 0x00}; // comment\n");
}
TEST_F(FormatTest, IgnoresIf0Contents) {
@@ -1536,6 +1650,12 @@
" private:\n"
" void f() {}\n"
"};");
+ verifyFormat("class A {\n"
+ "public slots:\n"
+ " void f() {}\n"
+ "public Q_SLOTS:\n"
+ " void f() {}\n"
+ "};");
}
TEST_F(FormatTest, SeparatesLogicalBlocks) {
@@ -1601,6 +1721,9 @@
verifyFormat("struct aaaaaaaaaaaaaaaaaaaa\n"
" : public aaaaaaaaaaaaaaaaaaa<aaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaa> {};");
+ verifyFormat("template <class R, class C>\n"
+ "struct Aaaaaaaaaaaaaaaaa<R (C::*)(int) const>\n"
+ " : Aaaaaaaaaaaaaaaaa<R (C::*)(int)> {};");
}
TEST_F(FormatTest, FormatsVariableDeclarationsAfterStructOrClass) {
@@ -1634,18 +1757,22 @@
verifyFormat("enum X f() {\n a();\n return 42;\n}");
verifyFormat("enum {\n"
" Bar = Foo<int, int>::value\n"
- "};");
+ "};",
+ getLLVMStyleWithColumns(30));
+
+ verifyFormat("enum ShortEnum { A, B, C };");
+ verifyGoogleFormat("enum ShortEnum { A, B, C };");
}
TEST_F(FormatTest, FormatsEnumsWithErrors) {
verifyFormat("enum Type {\n"
- " One = 0;\n" // These semicolons should be commas.
+ " One = 0; // These semicolons should be commas.\n"
" Two = 1;\n"
"};");
verifyFormat("namespace n {\n"
"enum Type {\n"
" One,\n"
- " Two,\n" // missing };
+ " Two, // missing };\n"
" int i;\n"
"}\n"
"void g() {}");
@@ -1687,13 +1814,23 @@
TEST_F(FormatTest, FormatsEnumTypes) {
verifyFormat("enum X : int {\n"
- " A,\n"
+ " A, // Force multiple lines.\n"
" B\n"
"};");
- verifyFormat("enum X : std::uint32_t {\n"
- " A,\n"
- " B\n"
- "};");
+ verifyFormat("enum X : int { A, B };");
+ verifyFormat("enum X : std::uint32_t { A, B };");
+}
+
+TEST_F(FormatTest, FormatsNSEnums) {
+ verifyGoogleFormat("typedef NS_ENUM(NSInteger, SomeName) { AAA, BBB }");
+ verifyGoogleFormat("typedef NS_ENUM(NSInteger, MyType) {\n"
+ " // Information about someDecentlyLongValue.\n"
+ " someDecentlyLongValue,\n"
+ " // Information about anotherDecentlyLongValue.\n"
+ " anotherDecentlyLongValue,\n"
+ " // Information about aThirdDecentlyLongValue.\n"
+ " aThirdDecentlyLongValue\n"
+ "};");
}
TEST_F(FormatTest, FormatsBitfields) {
@@ -1726,7 +1863,7 @@
// This code is more common than we thought; if we
// layout this correctly the semicolon will go into
- // its own line, which is undesireable.
+ // its own line, which is undesirable.
verifyFormat("namespace {};");
verifyFormat("namespace {\n"
"class A {};\n"
@@ -1832,96 +1969,90 @@
}
TEST_F(FormatTest, StaticInitializers) {
- verifyFormat("static SomeClass SC = { 1, 'a' };");
+ verifyFormat("static SomeClass SC = {1, 'a'};");
verifyFormat(
"static SomeClass WithALoooooooooooooooooooongName = {\n"
- " 100000000, \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n"
- "};");
+ " 100000000, \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"};");
// Here, everything other than the "}" would fit on a line.
verifyFormat("static int LooooooooooooooooooooooooongVariable[1] = {\n"
- " 100000000000000000000000\n"
- "};");
- EXPECT_EQ("S s = { a, b };", format("S s = {\n"
- " a,\n"
- "\n"
- " b\n"
- "};"));
+ " 10000000000000000000000000};");
+ EXPECT_EQ("S s = {a, b};", format("S s = {\n"
+ " a,\n"
+ "\n"
+ " b\n"
+ "};"));
// FIXME: This would fit into the column limit if we'd fit "{ {" on the first
// line. However, the formatting looks a bit off and this probably doesn't
// happen often in practice.
verifyFormat("static int Variable[1] = {\n"
- " { 1000000000000000000000000000000000000 }\n"
- "};",
+ " {1000000000000000000000000000000000000}};",
getLLVMStyleWithColumns(40));
}
TEST_F(FormatTest, DesignatedInitializers) {
- verifyFormat("const struct A a = { .a = 1, .b = 2 };");
- verifyFormat("const struct A a = { .aaaaaaaaaa = 1,\n"
- " .bbbbbbbbbb = 2,\n"
- " .cccccccccc = 3,\n"
- " .dddddddddd = 4,\n"
- " .eeeeeeeeee = 5 };");
+ verifyFormat("const struct A a = {.a = 1, .b = 2};");
+ verifyFormat("const struct A a = {.aaaaaaaaaa = 1,\n"
+ " .bbbbbbbbbb = 2,\n"
+ " .cccccccccc = 3,\n"
+ " .dddddddddd = 4,\n"
+ " .eeeeeeeeee = 5};");
verifyFormat("const struct Aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaa = {\n"
- " .aaaaaaaaaaaaaaaaaaaaaaaaaaa = 1,\n"
- " .bbbbbbbbbbbbbbbbbbbbbbbbbbb = 2,\n"
- " .ccccccccccccccccccccccccccc = 3,\n"
- " .ddddddddddddddddddddddddddd = 4,\n"
- " .eeeeeeeeeeeeeeeeeeeeeeeeeee = 5\n"
- "};");
+ " .aaaaaaaaaaaaaaaaaaaaaaaaaaa = 1,\n"
+ " .bbbbbbbbbbbbbbbbbbbbbbbbbbb = 2,\n"
+ " .ccccccccccccccccccccccccccc = 3,\n"
+ " .ddddddddddddddddddddddddddd = 4,\n"
+ " .eeeeeeeeeeeeeeeeeeeeeeeeeee = 5};");
verifyGoogleFormat("const struct A a = {.a = 1, .b = 2};");
}
TEST_F(FormatTest, NestedStaticInitializers) {
- verifyFormat("static A x = { { {} } };\n");
- verifyFormat("static A x = { { { init1, init2, init3, init4 },\n"
- " { init1, init2, init3, init4 } } };");
+ verifyFormat("static A x = {{{}}};\n");
+ verifyFormat("static A x = {{{init1, init2, init3, init4},\n"
+ " {init1, init2, init3, init4}}};",
+ getLLVMStyleWithColumns(50));
verifyFormat("somes Status::global_reps[3] = {\n"
- " { kGlobalRef, OK_CODE, NULL, NULL, NULL },\n"
- " { kGlobalRef, CANCELLED_CODE, NULL, NULL, NULL },\n"
- " { kGlobalRef, UNKNOWN_CODE, NULL, NULL, NULL }\n"
- "};");
+ " {kGlobalRef, OK_CODE, NULL, NULL, NULL},\n"
+ " {kGlobalRef, CANCELLED_CODE, NULL, NULL, NULL},\n"
+ " {kGlobalRef, UNKNOWN_CODE, NULL, NULL, NULL}};",
+ getLLVMStyleWithColumns(60));
verifyGoogleFormat("SomeType Status::global_reps[3] = {\n"
" {kGlobalRef, OK_CODE, NULL, NULL, NULL},\n"
" {kGlobalRef, CANCELLED_CODE, NULL, NULL, NULL},\n"
" {kGlobalRef, UNKNOWN_CODE, NULL, NULL, NULL}};");
verifyFormat(
- "CGRect cg_rect = { { rect.fLeft, rect.fTop },\n"
- " { rect.fRight - rect.fLeft, rect.fBottom - rect.fTop"
- " } };");
+ "CGRect cg_rect = {{rect.fLeft, rect.fTop},\n"
+ " {rect.fRight - rect.fLeft, rect.fBottom - rect.fTop}};");
verifyFormat(
- "SomeArrayOfSomeType a = { { { 1, 2, 3 }, { 1, 2, 3 },\n"
- " { 111111111111111111111111111111,\n"
- " 222222222222222222222222222222,\n"
- " 333333333333333333333333333333 },\n"
- " { 1, 2, 3 }, { 1, 2, 3 } } };");
- verifyFormat(
- "SomeArrayOfSomeType a = { { { 1, 2, 3 } }, { { 1, 2, 3 } },\n"
- " { { 111111111111111111111111111111,\n"
- " 222222222222222222222222222222,\n"
- " 333333333333333333333333333333 } },\n"
- " { { 1, 2, 3 } }, { { 1, 2, 3 } } };");
- verifyGoogleFormat(
"SomeArrayOfSomeType a = {\n"
- " {{1, 2, 3}}, {{1, 2, 3}},\n"
+ " {{1, 2, 3},\n"
+ " {1, 2, 3},\n"
+ " {111111111111111111111111111111, 222222222222222222222222222222,\n"
+ " 333333333333333333333333333333},\n"
+ " {1, 2, 3},\n"
+ " {1, 2, 3}}};");
+ verifyFormat(
+ "SomeArrayOfSomeType a = {\n"
+ " {{1, 2, 3}},\n"
+ " {{1, 2, 3}},\n"
" {{111111111111111111111111111111, 222222222222222222222222222222,\n"
" 333333333333333333333333333333}},\n"
- " {{1, 2, 3}}, {{1, 2, 3}}};");
+ " {{1, 2, 3}},\n"
+ " {{1, 2, 3}}};");
verifyFormat(
"struct {\n"
" unsigned bit;\n"
" const char *const name;\n"
- "} kBitsToOs[] = { { kOsMac, \"Mac\" },\n"
- " { kOsWin, \"Windows\" },\n"
- " { kOsLinux, \"Linux\" },\n"
- " { kOsCrOS, \"Chrome OS\" } };");
+ "} kBitsToOs[] = {{kOsMac, \"Mac\"},\n"
+ " {kOsWin, \"Windows\"},\n"
+ " {kOsLinux, \"Linux\"},\n"
+ " {kOsCrOS, \"Chrome OS\"}};");
}
TEST_F(FormatTest, FormatsSmallMacroDefinitionsInSingleLine) {
@@ -1978,6 +2109,10 @@
verifyFormat("#define A ''qqq");
verifyFormat("#define A `qqq");
verifyFormat("f(\"aaaa, bbbb, \"\\\"ccccc\\\"\");");
+ EXPECT_EQ("const char *c = STRINGIFY(\n"
+ "\\na : b);",
+ format("const char * c = STRINGIFY(\n"
+ "\\na : b);"));
}
TEST_F(FormatTest, IndentsPPDirectiveInReducedSpace) {
@@ -2077,7 +2212,8 @@
}
TEST_F(FormatTest, RespectWhitespaceInMacroDefinitions) {
- verifyFormat("#define A (1)");
+ EXPECT_EQ("#define A (x)", format("#define A (x)"));
+ EXPECT_EQ("#define A(x)", format("#define A(x)"));
}
TEST_F(FormatTest, EmptyLinesInMacroDefinitions) {
@@ -2181,6 +2317,17 @@
" IPC_END_MESSAGE_MAP()\n"
"}"));
+ // Same inside macros.
+ EXPECT_EQ("#define LIST(L) \\\n"
+ " L(A) \\\n"
+ " L(B) \\\n"
+ " L(C)",
+ format("#define LIST(L) \\\n"
+ " L(A) \\\n"
+ " L(B) \\\n"
+ " L(C)",
+ getGoogleStyle()));
+
// These must not be recognized as macros.
EXPECT_EQ("int q() {\n"
" f(x);\n"
@@ -2225,30 +2372,30 @@
" ifstream(x)\n >> x;\n"
"}\n"));
EXPECT_EQ("int q() {\n"
- " f(x)\n"
+ " F(x)\n"
" if (1) {\n"
" }\n"
- " f(x)\n"
+ " F(x)\n"
" while (1) {\n"
" }\n"
- " f(x)\n"
- " g(x);\n"
- " f(x)\n"
+ " F(x)\n"
+ " G(x);\n"
+ " F(x)\n"
" try {\n"
- " q();\n"
+ " Q();\n"
" }\n"
" catch (...) {\n"
" }\n"
"}\n",
format("int q() {\n"
- "f(x)\n"
+ "F(x)\n"
"if (1) {}\n"
- "f(x)\n"
+ "F(x)\n"
"while (1) {}\n"
- "f(x)\n"
- "g(x);\n"
- "f(x)\n"
- "try { q(); } catch (...) {}\n"
+ "F(x)\n"
+ "G(x);\n"
+ "F(x)\n"
+ "try { Q(); } catch (...) {}\n"
"}\n"));
EXPECT_EQ("class A {\n"
" A() : t(0) {}\n"
@@ -2263,6 +2410,27 @@
" A(X x)\n"
" try : t(0) {} catch (...) {}\n"
"};"));
+ EXPECT_EQ(
+ "class SomeClass {\n"
+ "public:\n"
+ " SomeClass() EXCLUSIVE_LOCK_FUNCTION(mu_);\n"
+ "};",
+ format("class SomeClass {\n"
+ "public:\n"
+ " SomeClass()\n"
+ " EXCLUSIVE_LOCK_FUNCTION(mu_);\n"
+ "};"));
+ EXPECT_EQ(
+ "class SomeClass {\n"
+ "public:\n"
+ " SomeClass()\n"
+ " EXCLUSIVE_LOCK_FUNCTION(mu_);\n"
+ "};",
+ format("class SomeClass {\n"
+ "public:\n"
+ " SomeClass()\n"
+ " EXCLUSIVE_LOCK_FUNCTION(mu_);\n"
+ "};", getLLVMStyleWithColumns(40)));
}
TEST_F(FormatTest, LayoutMacroDefinitionsStatementsSpanningBlocks) {
@@ -2392,6 +2560,11 @@
"#endif");
}
+TEST_F(FormatTest, GraciouslyHandleIncorrectPreprocessorConditions) {
+ verifyFormat("#endif\n"
+ "#if B");
+}
+
TEST_F(FormatTest, FormatsJoinedLinesOnSubsequentRuns) {
FormatStyle SingleLine = getLLVMStyle();
SingleLine.AllowShortIfStatementsOnASingleLine = true;
@@ -2450,7 +2623,7 @@
" struct s {\n"
" int i;\n"
" };\n"
- " s kBitsToOs[] = { { 10 } };\n"
+ " s kBitsToOs[] = {{10}};\n"
" for (int i = 0; i < 10; ++i)\n"
" return;\n"
"}");
@@ -2460,6 +2633,14 @@
" somethingelse();\n"
"});",
getLLVMStyleWithColumns(40));
+ verifyFormat("DEBUG( //\n"
+ " { f(); }, a);");
+ verifyFormat("DEBUG( //\n"
+ " {\n"
+ " f(); //\n"
+ " },\n"
+ " a);");
+
EXPECT_EQ("call(parameter, {\n"
" something();\n"
" // Comment too\n"
@@ -2506,6 +2687,45 @@
" return;\n"
" },\n"
" a);", Style);
+}
+
+TEST_F(FormatTest, IndividualStatementsOfNestedBlocks) {
+ EXPECT_EQ("DEBUG({\n"
+ " int i;\n"
+ " int j;\n"
+ "});",
+ format("DEBUG( {\n"
+ " int i;\n"
+ " int j;\n"
+ "} ) ;",
+ 20, 1, getLLVMStyle()));
+ EXPECT_EQ("DEBUG( {\n"
+ " int i;\n"
+ " int j;\n"
+ "} ) ;",
+ format("DEBUG( {\n"
+ " int i;\n"
+ " int j;\n"
+ "} ) ;",
+ 41, 1, getLLVMStyle()));
+ EXPECT_EQ("DEBUG( {\n"
+ " int i;\n"
+ " int j;\n"
+ "} ) ;",
+ format("DEBUG( {\n"
+ " int i;\n"
+ " int j;\n"
+ "} ) ;",
+ 41, 1, getLLVMStyle()));
+ EXPECT_EQ("DEBUG({\n"
+ " int i;\n"
+ " int j;\n"
+ "});",
+ format("DEBUG( {\n"
+ " int i;\n"
+ " int j;\n"
+ "} ) ;",
+ 20, 1, getLLVMStyle()));
EXPECT_EQ("Debug({\n"
" if (aaaaaaaaaaaaaaaaaaaaaaaa)\n"
@@ -2518,18 +2738,26 @@
" },\n"
" a);",
50, 1, getLLVMStyle()));
-}
-
-TEST_F(FormatTest, IndividualStatementsOfNestedBlocks) {
EXPECT_EQ("DEBUG({\n"
- " int i;\n"
- " int j;\n"
+ " DEBUG({\n"
+ " int a;\n"
+ " int b;\n"
+ " }) ;\n"
"});",
- format("DEBUG( {\n"
- " int i;\n"
- " int j;\n"
- "} ) ;",
- 40, 1, getLLVMStyle()));
+ format("DEBUG({\n"
+ " DEBUG({\n"
+ " int a;\n"
+ " int b;\n" // Format this line only.
+ " }) ;\n" // Don't touch this line.
+ "});",
+ 35, 0, getLLVMStyle()));
+ EXPECT_EQ("DEBUG({\n"
+ " int a; //\n"
+ "});",
+ format("DEBUG({\n"
+ " int a; //\n"
+ "});",
+ 0, 0, getLLVMStyle()));
}
TEST_F(FormatTest, PutEmptyBlocksIntoOneLine) {
@@ -2661,8 +2889,9 @@
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n"
" bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}");
verifyFormat("if () {\n"
- "} else if (aaaaa && bbbbb > // break\n"
- " ccccc) {\n"
+ "} else if (aaaaa &&\n"
+ " bbbbb > // break\n"
+ " ccccc) {\n"
"}");
// Presence of a trailing comment used to change indentation of b.
@@ -2720,6 +2949,10 @@
" + sizeof(int32_t) // Offset of CU in the .debug_info section\n"
" + sizeof(int8_t) // Pointer Size (in bytes)\n"
" + sizeof(int8_t); // Segment Size (in bytes)");
+
+ verifyFormat("return boost::fusion::at_c<0>(iiii).second\n"
+ " == boost::fusion::at_c<1>(iiii).second;",
+ Style);
}
TEST_F(FormatTest, ConstructorInitializers) {
@@ -2768,7 +3001,7 @@
" aaaaaaaaaaaaaaaaaaaaaaaaa(aaaa, aaaa)) {}");
// Here a line could be saved by splitting the second initializer onto two
- // lines, but that is not desireable.
+ // lines, but that is not desirable.
verifyFormat("Constructor()\n"
" : aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaa),\n"
" aaaaaaaaaaa(aaaaaaaaaaa),\n"
@@ -2802,6 +3035,13 @@
" : aaaaa(aaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaa) {}",
OnePerLine);
+
+ EXPECT_EQ("Constructor()\n"
+ " : // Comment forcing unwanted break.\n"
+ " aaaa(aaaa) {}",
+ format("Constructor() :\n"
+ " // Comment forcing unwanted break.\n"
+ " aaaa(aaaa) {}"));
}
TEST_F(FormatTest, MemoizationTests) {
@@ -2963,9 +3203,18 @@
"operator>(const SomeLoooooooooooooooooooooooooogType &other);");
verifyFormat("SomeLoooooooooooooooooooooooooogType\n"
"operator>>(const SomeLooooooooooooooooooooooooogType &other);");
+ verifyFormat("SomeLoooooooooooooooooooooooooogType\n"
+ "operator<<(const SomeLooooooooooooooooooooooooogType &other);");
+ verifyGoogleFormat(
+ "SomeLoooooooooooooooooooooooooooooogType operator>>(\n"
+ " const SomeLooooooooogType &a, const SomeLooooooooogType &b);");
verifyGoogleFormat(
"SomeLoooooooooooooooooooooooooooooogType operator<<(\n"
" const SomeLooooooooogType &a, const SomeLooooooooogType &b);");
+ verifyFormat("void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 1);");
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaa\n"
+ "aaaaaaaaaaaaaaaaaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaa = 1);");
}
TEST_F(FormatTest, TrailingReturnType) {
@@ -3001,14 +3250,30 @@
" aaaaa aaaaaaaaaaaaaaaaaaaa) OVERRIDE FINAL;");
verifyFormat("void SomeFunction(aaaaa aaaaaaaaaaaaaaaaaaaa,\n"
" aaaaa aaaaaaaaaaaaaaaaaaaa) override final;");
+ verifyFormat("virtual void aaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaa aaaa,\n"
+ " aaaaaaaaaaa aaaaa) const override;");
+ verifyGoogleFormat(
+ "virtual void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()\n"
+ " const override;");
- // Unless this would lead to the first parameter being broken.
- verifyFormat("void someLongFunction(int someLongParameter)\n"
- " const {}",
+ // Even if the first parameter has to be wrapped.
+ verifyFormat("void someLongFunction(\n"
+ " int someLongParameter) const {}",
getLLVMStyleWithColumns(46));
- verifyFormat("void someLongFunction(int someLongParameter)\n"
- " const {}",
+ verifyFormat("void someLongFunction(\n"
+ " int someLongParameter) const {}",
Style);
+ verifyFormat("void someLongFunction(\n"
+ " int someLongParameter) override {}",
+ Style);
+ verifyFormat("void someLongFunction(\n"
+ " int someLongParameter) final {}",
+ Style);
+ verifyFormat("void someLongFunction(\n"
+ " int parameter) const override {}",
+ Style);
+
+ // Unless these are unknown annotations.
verifyFormat("void SomeFunction(aaaaaaaaaa aaaaaaaaaaaaaaa,\n"
" aaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
" LONG_AND_UGLY_ANNOTATION;");
@@ -3079,7 +3344,7 @@
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
- // Indent consistently indenpendent of call expression.
+ // Indent consistently independent of call expression.
verifyFormat("aaaaaaaaaaa(bbbbbbbbbbbbbbbbbbbbbbbbb.ccccccccccccccccc(\n"
" dddddddddddddddddddddddddddddd));\n"
"aaaaaaaaaaa(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(\n"
@@ -3230,15 +3495,15 @@
"void f() {\n"
" someo->Add((new util::filetools::Handler(dir))\n"
" ->OnEvent1(NewPermanentCallback(\n"
- " this, &HandlerHolderClass::EventHandlerCBA))\n"
+ " this, &HandlerHolderClass::EventHandlerCBA))\n"
" ->OnEvent2(NewPermanentCallback(\n"
- " this, &HandlerHolderClass::EventHandlerCBB))\n"
+ " this, &HandlerHolderClass::EventHandlerCBB))\n"
" ->OnEvent3(NewPermanentCallback(\n"
- " this, &HandlerHolderClass::EventHandlerCBC))\n"
+ " this, &HandlerHolderClass::EventHandlerCBC))\n"
" ->OnEvent5(NewPermanentCallback(\n"
- " this, &HandlerHolderClass::EventHandlerCBD))\n"
+ " this, &HandlerHolderClass::EventHandlerCBD))\n"
" ->OnEvent6(NewPermanentCallback(\n"
- " this, &HandlerHolderClass::EventHandlerCBE)));\n"
+ " this, &HandlerHolderClass::EventHandlerCBE)));\n"
"}");
verifyFormat(
@@ -3264,7 +3529,7 @@
" .has<bbbbbbbbbbbbbbbbbbbbb>();");
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaa()\n"
" .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa<\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>();");
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>();");
// Prefer not to break after empty parentheses.
verifyFormat("FirstToken->WhitespaceRange.getBegin().getLocWithOffset(\n"
@@ -3495,7 +3760,7 @@
" aaaaaaaaaaaaaaaaaaaaaaaaaaa;",
Style);
verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa =\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ?\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ?\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
Style);
@@ -3610,6 +3875,13 @@
verifyFormat("#define A \"def\"\n"
"f(\"abc\" A \"ghi\"\n"
" \"jkl\");");
+
+ verifyFormat("f(L\"a\"\n"
+ " L\"b\")");
+ verifyFormat("#define A(X) \\\n"
+ " L\"aaaaa\" #X L\"bbbbbb\" \\\n"
+ " L\"ccccc\"",
+ getLLVMStyleWithColumns(25));
}
TEST_F(FormatTest, AlwaysBreakBeforeMultilineStrings) {
@@ -3638,6 +3910,10 @@
" \"bbbb\"\n"
" \"cccc\");",
Break);
+ verifyFormat("aaaa(qqq,\n"
+ " L\"bbbb\"\n"
+ " L\"cccc\");",
+ Break);
// Don't break if there is no column gain.
verifyFormat("f(\"aaaa\"\n"
@@ -3730,6 +4006,8 @@
getLLVMStyleWithColumns(70));
// But sometimes, breaking before the first "<<" is desirable.
+ verifyFormat("Diag(aaaaaaaaaaaaaaaaaaaa, aaaaaaaa)\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaa);");
verifyFormat("Diag(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbb)\n"
" << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
@@ -3744,6 +4022,11 @@
EXPECT_EQ("llvm::errs() << \"\n"
" << a;",
format("llvm::errs() << \"\n<<a;"));
+
+ verifyFormat("void f() {\n"
+ " CHECK_EQ(aaaa, (*bbbbbbbbb)->cccccc)\n"
+ " << \"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\";\n"
+ "}");
}
TEST_F(FormatTest, UnderstandsEquals) {
@@ -3789,8 +4072,8 @@
verifyFormat("EXPECT_CALL(SomeObject, SomeFunction(Parameter))\n"
" .WillRepeatedly(Return(SomeValue));");
- verifyFormat("SomeMap[std::pair(aaaaaaaaaaaa, bbbbbbbbbbbbbbb)]\n"
- " .insert(ccccccccccccccccccccccc);");
+ verifyFormat("SomeMap[std::pair(aaaaaaaaaaaa, bbbbbbbbbbbbbbb)].insert(\n"
+ " ccccccccccccccccccccccc);");
verifyFormat("aaaaa(aaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa).aaaaa(aaaaa),\n"
" aaaaaaaaaaaaaaaaaaaaa);");
@@ -3847,6 +4130,12 @@
verifyFormat(
"aaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa));");
+ verifyFormat("aaaaaaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa();");
+ verifyFormat("aaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa());");
}
TEST_F(FormatTest, WrapsTemplateDeclarations) {
@@ -3877,6 +4166,10 @@
"template <typename T1, typename T2 = char, typename T3 = char,\n"
" typename T4 = char>\n"
"void f();");
+ verifyFormat("template <typename aaaaaaaaaaa, typename bbbbbbbbbbbbb,\n"
+ " template <typename> class cccccccccccccccccccccc,\n"
+ " typename ddddddddddddd>\n"
+ "class C {};");
verifyFormat(
"aaaaaaaaaaaaaaaaaaaaaaaa<aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa>(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
@@ -3953,7 +4246,7 @@
TEST_F(FormatTest, UnderstandsTemplateParameters) {
verifyFormat("A<int> a;");
- verifyFormat("A<A<A<int> > > a;");
+ verifyFormat("A<A<A<int>>> a;");
verifyFormat("A<A<A<int, 2>, 3>, 4> a;");
verifyFormat("bool x = a < 1 || 2 > a;");
verifyFormat("bool x = 5 < f<int>();");
@@ -4052,22 +4345,20 @@
verifyFormat("#define X -1");
verifyFormat("#define X -kConstant");
- verifyFormat("const NSPoint kBrowserFrameViewPatternOffset = { -5, +3 };");
- verifyFormat("const NSPoint kBrowserFrameViewPatternOffset = { +5, -3 };");
+ verifyFormat("const NSPoint kBrowserFrameViewPatternOffset = {-5, +3};");
+ verifyFormat("const NSPoint kBrowserFrameViewPatternOffset = {+5, -3};");
verifyFormat("int a = /* confusing comment */ -1;");
// FIXME: The space after 'i' is wrong, but hopefully, this is a rare case.
verifyFormat("int a = i /* confusing comment */++;");
}
-TEST_F(FormatTest, IndentsRelativeToUnaryOperators) {
+TEST_F(FormatTest, DoesNotIndentRelativeToUnaryOperators) {
verifyFormat("if (!aaaaaaaaaa( // break\n"
- " aaaaa)) {\n"
+ " aaaaa)) {\n"
"}");
verifyFormat("aaaaaaaaaa(!aaaaaaaaaa( // break\n"
- " aaaaa));");
-
- // Only indent relative to unary operators if the expression is nested.
+ " aaaaa));");
verifyFormat("*aaa = aaaaaaa( // break\n"
" bbbbbb);");
}
@@ -4088,7 +4379,7 @@
verifyFormat("operator void *();");
verifyFormat("operator SomeType<int>();");
verifyFormat("operator SomeType<int, int>();");
- verifyFormat("operator SomeType<SomeType<int> >();");
+ verifyFormat("operator SomeType<SomeType<int>>();");
verifyFormat("void *operator new(std::size_t size);");
verifyFormat("void *operator new[](std::size_t size);");
verifyFormat("void operator delete(void *ptr);");
@@ -4110,6 +4401,11 @@
verifyGoogleFormat("operator ::A();");
verifyFormat("using A::operator+;");
+
+ verifyFormat("Deleted &operator=(const Deleted &)& = default;");
+ verifyFormat("Deleted &operator=(const Deleted &)&& = delete;");
+ verifyGoogleFormat("Deleted& operator=(const Deleted&)& = default;");
+ verifyGoogleFormat("Deleted& operator=(const Deleted&)&& = delete;");
}
TEST_F(FormatTest, UnderstandsNewAndDelete) {
@@ -4167,6 +4463,7 @@
verifyFormat("auto a = [](int **&, int ***) {};");
verifyFormat("auto PointerBinding = [](const char *S) {};");
verifyFormat("typedef typeof(int(int, int)) *MyFunc;");
+ verifyIndependentOfContext("typedef void (*f)(int *a);");
verifyIndependentOfContext("InvalidRegions[*R] = 0;");
@@ -4207,9 +4504,8 @@
verifyIndependentOfContext("f(b * /* confusing comment */ ++c);");
verifyFormat(
- "int *MyValues = {\n"
- " *A, // Operator detection might be confused by the '{'\n"
- " *BB // Operator detection might be confused by previous comment\n"
+ "int *MyValues = {*A, // Operator detection might be confused by the '{'\n"
+ " *BB // Operator detection might be confused by previous comment\n"
"};");
verifyIndependentOfContext("if (int *a = &b)");
@@ -4246,10 +4542,34 @@
FormatStyle PointerLeft = getLLVMStyle();
PointerLeft.PointerBindsToType = true;
verifyFormat("delete *x;", PointerLeft);
+ verifyFormat("STATIC_ASSERT((a & b) == 0);");
+ verifyFormat("STATIC_ASSERT(0 == (a & b));");
+ verifyFormat("template <bool a, bool b> "
+ "typename t::if<x && y>::type f() {};");
+ verifyFormat("template <int *y> f() {};");
+ verifyFormat("vector<int *> v;");
+ verifyFormat("vector<int *const> v;");
+ verifyFormat("vector<int *const **const *> v;");
+ verifyFormat("vector<int *volatile> v;");
+ verifyFormat("vector<a * b> v;");
+ verifyFormat("foo<b && false>();");
+ verifyFormat("foo<b & 1>();");
+
+ verifyIndependentOfContext("MACRO(int *i);");
+ verifyIndependentOfContext("MACRO(auto *a);");
+ verifyIndependentOfContext("MACRO(const A *a);");
+ // FIXME: Is there a way to make this work?
+ // verifyIndependentOfContext("MACRO(A *a);");
+
+ // FIXME: We cannot handle this case yet; we might be able to figure out that
+ // foo<x> d > v; doesn't make sense.
+ verifyFormat("foo<a < b && c> d > v;");
}
TEST_F(FormatTest, UnderstandsAttributes) {
verifyFormat("SomeType s __attribute__((unused)) (InitValue);");
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa __attribute__((unused))\n"
+ "aaaaaaaaaaaaaaaaaaaaaaa(int i);");
}
TEST_F(FormatTest, UnderstandsEllipsis) {
@@ -4485,6 +4805,9 @@
"llvm::outs() << \"aaaaaaaaaaaa: \"\n"
" << (*aaaaaaaiaaaaaaa)[aaaaaaaaaaaaaaaaaaaaaaaaa]\n"
" [aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];");
+
+ verifyGoogleFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa<int>\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[aaaaaaaaaaaa];");
}
TEST_F(FormatTest, LineStartsWithSpecialCharacter) {
@@ -4515,6 +4838,10 @@
verifyFormat("#if __has_include(<strstream>)\n"
"#include <strstream>\n"
"#endif");
+
+ // Protocol buffer definition or missing "#".
+ verifyFormat("import \"aaaaaaaaaaaaaaaaa/aaaaaaaaaaaaaaa\";",
+ getLLVMStyleWithColumns(30));
}
//===----------------------------------------------------------------------===//
@@ -4645,134 +4972,201 @@
TEST_F(FormatTest, LayoutCallsInsideBraceInitializers) {
verifyFormat("int x = {\n"
- " avariable,\n"
- " b(alongervariable)\n"
- "};",
+ " avariable,\n"
+ " b(alongervariable)};",
getLLVMStyleWithColumns(25));
}
TEST_F(FormatTest, LayoutBraceInitializersInReturnStatement) {
- verifyFormat("return (a)(b) { 1, 2, 3 };");
+ verifyFormat("return (a)(b) {1, 2, 3};");
}
TEST_F(FormatTest, LayoutCxx11ConstructorBraceInitializers) {
- verifyFormat("vector<int> x{ 1, 2, 3, 4 };");
- verifyFormat("vector<T> x{ {}, {}, {}, {} };");
- verifyFormat("f({ 1, 2 });");
- verifyFormat("auto v = Foo{ 1 };");
- verifyFormat("f({ 1, 2 }, { { 2, 3 }, { 4, 5 } }, c, { d });");
- verifyFormat("Class::Class : member{ 1, 2, 3 } {}");
- verifyFormat("new vector<int>{ 1, 2, 3 };");
- verifyFormat("new int[3]{ 1, 2, 3 };");
- verifyFormat("return { arg1, arg2 };");
- verifyFormat("return { arg1, SomeType{ parameter } };");
- verifyFormat("new T{ arg1, arg2 };");
- verifyFormat("f(MyMap[{ composite, key }]);");
- verifyFormat("class Class {\n"
- " T member = { arg1, arg2 };\n"
- "};");
- verifyFormat(
- "foo = aaaaaaaaaaa ? vector<int>{ aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaaaaaaa, aaaaa }\n"
- " : vector<int>{ bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
- " bbbbbbbbbbbbbbbbbbbb, bbbbb };");
- verifyFormat("DoSomethingWithVector({} /* No data */);");
- verifyFormat("DoSomethingWithVector({ {} /* No data */ }, { { 1, 2 } });");
- verifyFormat(
- "someFunction(OtherParam, BracedList{\n"
- " // comment 1 (Forcing interesting break)\n"
- " param1, param2,\n"
- " // comment 2\n"
- " param3, param4\n"
- " });");
- verifyFormat(
- "std::this_thread::sleep_for(\n"
- " std::chrono::nanoseconds{ std::chrono::seconds{ 1 } } / 5);");
+ verifyFormat("vector<int> x{1, 2, 3, 4};");
+ verifyFormat("vector<int> x{\n"
+ " 1, 2, 3, 4,\n"
+ "};");
+ verifyFormat("vector<T> x{{}, {}, {}, {}};");
+ verifyFormat("f({1, 2});");
+ verifyFormat("auto v = Foo{-1};");
+ verifyFormat("f({1, 2}, {{2, 3}, {4, 5}}, c, {d});");
+ verifyFormat("Class::Class : member{1, 2, 3} {}");
+ verifyFormat("new vector<int>{1, 2, 3};");
+ verifyFormat("new int[3]{1, 2, 3};");
+ verifyFormat("return {arg1, arg2};");
+ verifyFormat("return {arg1, SomeType{parameter}};");
+ verifyFormat("int count = set<int>{f(), g(), h()}.size();");
+ verifyFormat("new T{arg1, arg2};");
+ verifyFormat("f(MyMap[{composite, key}]);");
+ verifyFormat("class Class {\n"
+ " T member = {arg1, arg2};\n"
+ "};");
+ verifyFormat("vector<int> foo = {::SomeGlobalFunction()};");
- FormatStyle NoSpaces = getLLVMStyle();
- NoSpaces.Cpp11BracedListStyle = true;
- verifyFormat("vector<int> x{1, 2, 3, 4};", NoSpaces);
- verifyFormat("vector<T> x{{}, {}, {}, {}};", NoSpaces);
- verifyFormat("f({1, 2});", NoSpaces);
- verifyFormat("auto v = Foo{-1};", NoSpaces);
- verifyFormat("f({1, 2}, {{2, 3}, {4, 5}}, c, {d});", NoSpaces);
- verifyFormat("Class::Class : member{1, 2, 3} {}", NoSpaces);
- verifyFormat("new vector<int>{1, 2, 3};", NoSpaces);
- verifyFormat("new int[3]{1, 2, 3};", NoSpaces);
- verifyFormat("return {arg1, arg2};", NoSpaces);
- verifyFormat("return {arg1, SomeType{parameter}};", NoSpaces);
- verifyFormat("new T{arg1, arg2};", NoSpaces);
- verifyFormat("f(MyMap[{composite, key}]);", NoSpaces);
- verifyFormat("class Class {\n"
- " T member = {arg1, arg2};\n"
- "};",
- NoSpaces);
- verifyFormat("Constructor::Constructor()\n"
- " : some_value{ //\n"
- " aaaaaaa //\n"
- " } {}",
- NoSpaces);
+ // FIXME: The alignment of these trailing comments might be bad. Then again,
+ // this might be utterly useless in real code.
+ verifyFormat("Constructor::Constructor()\n"
+ " : some_value{ //\n"
+ " aaaaaaa //\n"
+ " } {}");
+
+ // In braced lists, the first comment is always assumed to belong to the
+ // first element. Thus, it can be moved to the next or previous line as
+ // appropriate.
+ EXPECT_EQ("function({// First element:\n"
+ " 1,\n"
+ " // Second element:\n"
+ " 2});",
+ format("function({\n"
+ " // First element:\n"
+ " 1,\n"
+ " // Second element:\n"
+ " 2});"));
+ EXPECT_EQ("std::vector<int> MyNumbers{\n"
+ " // First element:\n"
+ " 1,\n"
+ " // Second element:\n"
+ " 2};",
+ format("std::vector<int> MyNumbers{// First element:\n"
+ " 1,\n"
+ " // Second element:\n"
+ " 2};",
+ getLLVMStyleWithColumns(30)));
+
+ FormatStyle ExtraSpaces = getLLVMStyle();
+ ExtraSpaces.Cpp11BracedListStyle = false;
+ ExtraSpaces.ColumnLimit = 75;
+ verifyFormat("vector<int> x{ 1, 2, 3, 4 };", ExtraSpaces);
+ verifyFormat("vector<T> x{ {}, {}, {}, {} };", ExtraSpaces);
+ verifyFormat("f({ 1, 2 });", ExtraSpaces);
+ verifyFormat("auto v = Foo{ 1 };", ExtraSpaces);
+ verifyFormat("f({ 1, 2 }, { { 2, 3 }, { 4, 5 } }, c, { d });", ExtraSpaces);
+ verifyFormat("Class::Class : member{ 1, 2, 3 } {}", ExtraSpaces);
+ verifyFormat("new vector<int>{ 1, 2, 3 };", ExtraSpaces);
+ verifyFormat("new int[3]{ 1, 2, 3 };", ExtraSpaces);
+ verifyFormat("return { arg1, arg2 };", ExtraSpaces);
+ verifyFormat("return { arg1, SomeType{ parameter } };", ExtraSpaces);
+ verifyFormat("int count = set<int>{ f(), g(), h() }.size();", ExtraSpaces);
+ verifyFormat("new T{ arg1, arg2 };", ExtraSpaces);
+ verifyFormat("f(MyMap[{ composite, key }]);", ExtraSpaces);
+ verifyFormat("class Class {\n"
+ " T member = { arg1, arg2 };\n"
+ "};",
+ ExtraSpaces);
+ verifyFormat(
+ "foo = aaaaaaaaaaa ? vector<int>{ aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaa, aaaaa }\n"
+ " : vector<int>{ bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
+ " bbbbbbbbbbbbbbbbbbbb, bbbbb };",
+ ExtraSpaces);
+ verifyFormat("DoSomethingWithVector({} /* No data */);", ExtraSpaces);
+ verifyFormat("DoSomethingWithVector({ {} /* No data */ }, { { 1, 2 } });",
+ ExtraSpaces);
+ verifyFormat(
+ "someFunction(OtherParam,\n"
+ " BracedList{ // comment 1 (Forcing interesting break)\n"
+ " param1, param2,\n"
+ " // comment 2\n"
+ " param3, param4 });",
+ ExtraSpaces);
+ verifyFormat(
+ "std::this_thread::sleep_for(\n"
+ " std::chrono::nanoseconds{ std::chrono::seconds{ 1 } } / 5);",
+ ExtraSpaces);
+ verifyFormat("std::vector<MyValues> aaaaaaaaaaaaaaaaaaa{\n"
+ " aaaaaaa, aaaaaaaaaa,\n"
+ " aaaaa, aaaaaaaaaaaaaaa,\n"
+ " aaa, aaaaaaaaaa,\n"
+ " a, aaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaa, a\n"
+ "};",
+ ExtraSpaces);
+ verifyFormat("vector<int> foo = { ::SomeGlobalFunction() };", ExtraSpaces);
}
TEST_F(FormatTest, FormatsBracedListsInColumnLayout) {
- verifyFormat("vector<int> x = { 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
- " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
- " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
- " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
- " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
- " 1, 22, 333, 4444, 55555, 666666, 7777777 };");
- verifyFormat("vector<int> x = { 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
- " // line comment\n"
- " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
- " 1, 22, 333, 4444, 55555,\n"
- " // line comment\n"
- " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
- " 1, 22, 333, 4444, 55555, 666666, 7777777 };");
+ verifyFormat("vector<int> x = {1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777};");
+ verifyFormat("vector<int> x = {1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " // line comment\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555,\n"
+ " // line comment\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777};");
verifyFormat(
- "vector<int> x = { 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
- " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
- " 1, 22, 333, 4444, 55555, 666666, // comment\n"
- " 7777777, 1, 22, 333, 4444, 55555, 666666,\n"
- " 7777777, 1, 22, 333, 4444, 55555, 666666,\n"
- " 7777777, 1, 22, 333, 4444, 55555, 666666,\n"
- " 7777777 };");
+ "vector<int> x = {1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
+ " 1, 22, 333, 4444, 55555, 666666, // comment\n"
+ " 7777777, 1, 22, 333, 4444, 55555, 666666,\n"
+ " 7777777, 1, 22, 333, 4444, 55555, 666666,\n"
+ " 7777777, 1, 22, 333, 4444, 55555, 666666,\n"
+ " 7777777};");
verifyFormat("static const uint16_t CallerSavedRegs64Bittttt[] = {\n"
- " X86::RAX, X86::RDX, X86::RCX, X86::RSI, X86::RDI,\n"
- " X86::R8, X86::R9, X86::R10, X86::R11, 0\n"
- "};");
- verifyFormat("vector<int> x = { 1, 1, 1, 1,\n"
- " 1, 1, 1, 1 };",
+ " X86::RAX, X86::RDX, X86::RCX, X86::RSI, X86::RDI,\n"
+ " X86::R8, X86::R9, X86::R10, X86::R11, 0};");
+ verifyFormat("vector<int> x = {1, 1, 1, 1,\n"
+ " 1, 1, 1, 1};",
getLLVMStyleWithColumns(39));
- verifyFormat("vector<int> x = { 1, 1, 1, 1,\n"
- " 1, 1, 1, 1 };",
+ verifyFormat("vector<int> x = {1, 1, 1, 1,\n"
+ " 1, 1, 1, 1};",
getLLVMStyleWithColumns(38));
verifyFormat("vector<int> aaaaaaaaaaaaaaaaaaaaaa = {\n"
- " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n"
- "};",
- getLLVMStyleWithColumns(40));
+ " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};",
+ getLLVMStyleWithColumns(43));
// Trailing commas.
- verifyFormat("vector<int> x = { 1, 1, 1, 1,\n"
- " 1, 1, 1, 1, };",
- getLLVMStyleWithColumns(39));
- verifyFormat("vector<int> x = { 1, 1, 1, 1,\n"
- " 1, 1, 1, 1, //\n"
+ verifyFormat("vector<int> x = {\n"
+ " 1, 1, 1, 1, 1, 1, 1, 1,\n"
"};",
getLLVMStyleWithColumns(39));
- verifyFormat("vector<int> x = { 1, 1, 1, 1,\n"
- " 1, 1, 1, 1,\n"
- " /**/ /**/ };",
+ verifyFormat("vector<int> x = {1, 1, 1, 1,\n"
+ " 1, 1, 1, 1, //\n"
+ "};",
getLLVMStyleWithColumns(39));
- verifyFormat("return { { aaaaaaaaaaaaaaaaaaaaa },\n"
- " { aaaaaaaaaaaaaaaaaaa },\n"
- " { aaaaaaaaaaaaaaaaaaaaa },\n"
- " { aaaaaaaaaaaaaaaaa } };",
+ verifyFormat("vector<int> x = {1, 1, 1, 1,\n"
+ " 1, 1, 1, 1,\n"
+ " /**/ /**/};",
+ getLLVMStyleWithColumns(39));
+ verifyFormat("return {{aaaaaaaaaaaaaaaaaaaaa},\n"
+ " {aaaaaaaaaaaaaaaaaaa},\n"
+ " {aaaaaaaaaaaaaaaaaaaaa},\n"
+ " {aaaaaaaaaaaaaaaaa}};",
getLLVMStyleWithColumns(60));
+
+ // With nested lists, we should either format one item per line or all nested
+ // lists one one line.
+ // FIXME: For some nested lists, we can do better.
+ verifyFormat(
+ "SomeStruct my_struct_array = {\n"
+ " {aaaaaa, aaaaaaaa, aaaaaaaaaa, aaaaaaaaa, aaaaaaaaa, aaaaaaaaaa,\n"
+ " aaaaaaaaaaaaa, aaaaaaa, aaa},\n"
+ " {aaa, aaa},\n"
+ " {aaa, aaa},\n"
+ " {aaaa, aaaa, aaaa, aaaa, aaaa, aaaa, aaaa, aaa},\n"
+ " {aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaa, a, aaaaaaaaaa, aaaaaaaaa, aaa}};");
+
+ // No column layout should be used here.
+ verifyFormat("aaaaaaaaaaaaaaa = {aaaaaaaaaaaaaaaaaaaaaaaaaaa, 0, 0,\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb};");
}
TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {
+ FormatStyle DoNotMerge = getLLVMStyle();
+ DoNotMerge.AllowShortFunctionsOnASingleLine = false;
+
verifyFormat("void f() { return 42; }");
verifyFormat("void f() {\n"
+ " return 42;\n"
+ "}",
+ DoNotMerge);
+ verifyFormat("void f() {\n"
" // Comment\n"
"}");
verifyFormat("{\n"
@@ -4787,6 +5181,13 @@
verifyFormat("void f() { int a; } // comment");
verifyFormat("void f() {\n"
"} // comment",
+ DoNotMerge);
+ verifyFormat("void f() {\n"
+ " int a;\n"
+ "} // comment",
+ DoNotMerge);
+ verifyFormat("void f() {\n"
+ "} // comment",
getLLVMStyleWithColumns(15));
verifyFormat("void f() { return 42; }", getLLVMStyleWithColumns(23));
@@ -4794,13 +5195,62 @@
verifyFormat("void f() {}", getLLVMStyleWithColumns(11));
verifyFormat("void f() {\n}", getLLVMStyleWithColumns(10));
+ verifyFormat("class C {\n"
+ " C()\n"
+ " : iiiiiiii(nullptr),\n"
+ " kkkkkkk(nullptr),\n"
+ " mmmmmmm(nullptr),\n"
+ " nnnnnnn(nullptr) {}\n"
+ "};",
+ getGoogleStyle());
+
+ FormatStyle NoColumnLimit = getLLVMStyle();
+ NoColumnLimit.ColumnLimit = 0;
+ EXPECT_EQ("A() : b(0) {}", format("A():b(0){}", NoColumnLimit));
+ EXPECT_EQ("class C {\n"
+ " A() : b(0) {}\n"
+ "};", format("class C{A():b(0){}};", NoColumnLimit));
+ EXPECT_EQ("A()\n"
+ " : b(0) {\n"
+ "}",
+ format("A()\n:b(0)\n{\n}", NoColumnLimit));
+
+ FormatStyle DoNotMergeNoColumnLimit = NoColumnLimit;
+ DoNotMergeNoColumnLimit.AllowShortFunctionsOnASingleLine = false;
+ EXPECT_EQ("A()\n"
+ " : b(0) {\n"
+ "}",
+ format("A():b(0){}", DoNotMergeNoColumnLimit));
+ EXPECT_EQ("A()\n"
+ " : b(0) {\n"
+ "}",
+ format("A()\n:b(0)\n{\n}", DoNotMergeNoColumnLimit));
+
+ verifyFormat("#define A \\\n"
+ " void f() { \\\n"
+ " int i; \\\n"
+ " }",
+ getLLVMStyleWithColumns(20));
+ verifyFormat("#define A \\\n"
+ " void f() { int i; }",
+ getLLVMStyleWithColumns(21));
+ verifyFormat("#define A \\\n"
+ " void f() { \\\n"
+ " int i; \\\n"
+ " } \\\n"
+ " int j;",
+ getLLVMStyleWithColumns(22));
+ verifyFormat("#define A \\\n"
+ " void f() { int i; } \\\n"
+ " int j;",
+ getLLVMStyleWithColumns(23));
}
TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
// Elaborate type variable declarations.
- verifyFormat("struct foo a = { bar };\nint n;");
- verifyFormat("class foo a = { bar };\nint n;");
- verifyFormat("union foo a = { bar };\nint n;");
+ verifyFormat("struct foo a = {bar};\nint n;");
+ verifyFormat("class foo a = {bar};\nint n;");
+ verifyFormat("union foo a = {bar};\nint n;");
// Elaborate types inside function definitions.
verifyFormat("struct foo f() {}\nint n;");
@@ -4864,6 +5314,7 @@
}
TEST_F(FormatTest, FormatHashIfExpressions) {
+ verifyFormat("#if AAAA && BBBB");
// FIXME: Come up with a better indentation for #elif.
verifyFormat(
"#if !defined(AAAAAAA) && (defined CCCCCC || defined DDDDDD) && \\\n"
@@ -4906,6 +5357,17 @@
" if (true) continue;\n"
"}",
ShortMergedIf);
+ ShortMergedIf.ColumnLimit = 29;
+ verifyFormat("#define A \\\n"
+ " if (aaaaaaaaaa) return 1; \\\n"
+ " return 2;",
+ ShortMergedIf);
+ ShortMergedIf.ColumnLimit = 28;
+ verifyFormat("#define A \\\n"
+ " if (aaaaaaaaaa) \\\n"
+ " return 1; \\\n"
+ " return 2;",
+ ShortMergedIf);
}
TEST_F(FormatTest, BlockCommentsInControlLoops) {
@@ -5054,13 +5516,13 @@
TEST_F(FormatTest, BlockCommentsAtEndOfLine) {
EXPECT_EQ("a = {\n"
- " 1111 /* */\n"
+ " 1111 /* */\n"
"};",
format("a = {1111 /* */\n"
"};",
getLLVMStyleWithColumns(15)));
EXPECT_EQ("a = {\n"
- " 1111 /* */\n"
+ " 1111 /* */\n"
"};",
format("a = {1111 /* */\n"
"};",
@@ -5068,8 +5530,8 @@
// FIXME: The formatting is still wrong here.
EXPECT_EQ("a = {\n"
- " 1111 /* a\n"
- " */\n"
+ " 1111 /* a\n"
+ " */\n"
"};",
format("a = {1111 /* a */\n"
"};",
@@ -5156,11 +5618,6 @@
verifyGoogleFormat("- foo:(int)foo;");
}
-TEST_F(FormatTest, FormatObjCBlocks) {
- verifyFormat("int (^Block)(int, int);");
- verifyFormat("int (^Block1)(int, int) = ^(int i, int j)");
-}
-
TEST_F(FormatTest, FormatObjCInterface) {
verifyFormat("@interface Foo : NSObject <NSSomeDelegate> {\n"
"@public\n"
@@ -5372,6 +5829,10 @@
" int *looooooooooooooooooooooooooooongNumber;\n"
"@property(nonatomic, assign, readonly)\n"
" NSString *looooooooooooooooooooooooooooongName;");
+
+ verifyFormat("@implementation PR18406\n"
+ "}\n"
+ "@end");
}
TEST_F(FormatTest, FormatObjCMethodDeclarations) {
@@ -5501,6 +5962,17 @@
" der:NO]);\n"
"}",
getLLVMStyleWithColumns(70));
+ verifyFormat("{\n"
+ " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n"
+ " initWithContentRect:NSMakeRect(origin_global.x,\n"
+ " origin_global.y,\n"
+ " pos.width(),\n"
+ " 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];");
@@ -5548,6 +6020,8 @@
verifyFormat("[self // break\n"
" a:a\n"
" aaa:aaa];");
+ verifyFormat("bool a = ([aaaaaaaa aaaaa] == aaaaaaaaaaaaaaaaa ||\n"
+ " [aaaaaaaa aaaaa] == aaaaaaaaaaaaaaaaaaaa);");
}
TEST_F(FormatTest, ObjCAt) {
@@ -5606,6 +6080,12 @@
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;");
@@ -5625,26 +6105,30 @@
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\" : @1}");
+ verifyFormat("return @{@\"one\" : @1;");
+ verifyFormat("@{@\"one\" : @1}");
- verifyFormat("@{ @\"one\" : @{ @2 : @1 } }");
- verifyFormat("@{ @\"one\" : @{ @2 : @1 }, }");
+ verifyFormat("@{@\"one\" : @{@2 : @1}}");
+ verifyFormat("@{\n"
+ " @\"one\" : @{@2 : @1},\n"
+ "}");
- verifyFormat("@{ 1 > 2 ? @\"one\" : @\"two\" : 1 > 2 ? @1 : @2 }");
+ verifyFormat("@{1 > 2 ? @\"one\" : @\"two\" : 1 > 2 ? @1 : @2}");
verifyFormat("[self setDict:@{}");
- verifyFormat("[self setDict:@{ @1 : @2 }");
- verifyFormat("NSLog(@\"%@\", @{ @1 : @2, @2 : @3 }[@1]);");
+ verifyFormat("[self setDict:@{@1 : @2}");
+ verifyFormat("NSLog(@\"%@\", @{@1 : @2, @2 : @3}[@1]);");
verifyFormat(
- "NSDictionary *masses = @{ @\"H\" : @1.0078, @\"He\" : @4.0026 };");
+ "NSDictionary *masses = @{@\"H\" : @1.0078, @\"He\" : @4.0026};");
verifyFormat(
- "NSDictionary *settings = @{ AVEncoderKey : @(AVAudioQualityMax) };");
+ "NSDictionary *settings = @{AVEncoderKey : @(AVAudioQualityMax)};");
verifyFormat(
"NSDictionary *d = @{\n"
@@ -5662,6 +6146,11 @@
" NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee : "
"regularFont,\n"
"};");
+ verifyFormat(
+ "@{\n"
+ " NSFontAttributeNameeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee :\n"
+ " reeeeeeeeeeeeeeeeeeeeeeeegularFont,\n"
+ "};");
// We should try to be robust in case someone forgets the "@".
verifyFormat(
@@ -5707,6 +6196,14 @@
" @\"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\"] ]];");
}
TEST_F(FormatTest, ReformatRegionAdjustsIndent) {
@@ -5792,6 +6289,29 @@
format(" int a;\n"
"void ffffff() {}",
11, 0, getLLVMStyleWithColumns(11)));
+
+ EXPECT_EQ(" void f() {\n"
+ "#define A 1\n"
+ " }",
+ format(" void f() {\n"
+ " #define A 1\n" // Format this line.
+ " }",
+ 20, 0, getLLVMStyle()));
+ EXPECT_EQ(" void f() {\n"
+ " int i;\n"
+ "#define A \\\n"
+ " int i; \\\n"
+ " int j;\n"
+ " int k;\n"
+ " }",
+ format(" void f() {\n"
+ " int i;\n"
+ "#define A \\\n"
+ " int i; \\\n"
+ " int j;\n"
+ " int k;\n" // Format this line.
+ " }",
+ 67, 0, getLLVMStyle()));
}
TEST_F(FormatTest, BreakStringLiterals) {
@@ -5954,7 +6474,7 @@
format("#define A \"some text other\";", AlignLeft));
}
-TEST_F(FormatTest, BreaksWideStringLiterals) {
+TEST_F(FormatTest, BreaksWideAndNSStringLiterals) {
EXPECT_EQ(
"u8\"utf8 string \"\n"
"u8\"literal\";",
@@ -5970,6 +6490,9 @@
EXPECT_EQ("L\"wide string \"\n"
"L\"literal\";",
format("L\"wide string literal\";", getGoogleStyleWithColumns(16)));
+ EXPECT_EQ("@\"NSString \"\n"
+ "@\"literal\";",
+ format("@\"NSString literal\";", getGoogleStyleWithColumns(19)));
}
TEST_F(FormatTest, BreaksRawStringLiterals) {
@@ -6026,7 +6549,7 @@
TEST_F(FormatTest, CountsCharactersInMultilineRawStringLiterals) {
EXPECT_EQ("f(g(R\"x(raw literal)x\", a), b);",
- format("f(g(R\"x(raw literal)x\", a), b);", getGoogleStyle()));
+ format("f(g(R\"x(raw literal)x\", a), b);", getGoogleStyle()));
EXPECT_EQ("fffffffffff(g(R\"x(\n"
"multiline raw string literal xxxxxxxxxxxxxx\n"
")x\",\n"
@@ -6056,10 +6579,19 @@
getGoogleStyleWithColumns(20)));
EXPECT_EQ("fffffffffff(R\"x(\n"
"multiline raw string literal xxxxxxxxxxxxxx\n"
- ")x\" +\n"
- " bbbbbb);",
+ ")x\" + bbbbbb);",
format("fffffffffff(R\"x(\n"
"multiline raw string literal xxxxxxxxxxxxxx\n"
+ ")x\" + bbbbbb);",
+ getGoogleStyleWithColumns(20)));
+ EXPECT_EQ("fffffffffff(\n"
+ " R\"x(\n"
+ "multiline raw string literal xxxxxxxxxxxxxx\n"
+ ")x\" +\n"
+ " bbbbbb);",
+ format("fffffffffff(\n"
+ " R\"x(\n"
+ "multiline raw string literal xxxxxxxxxxxxxx\n"
")x\" + bbbbbb);",
getGoogleStyleWithColumns(20)));
}
@@ -6073,8 +6605,10 @@
}
TEST_F(FormatTest, DoesNotTryToParseUDLiteralsInPreCpp11Code) {
+ FormatStyle Style = getLLVMStyle();
+ Style.Standard = FormatStyle::LS_Cpp03;
EXPECT_EQ("#define x(_a) printf(\"foo\" _a);",
- format("#define x(_a) printf(\"foo\"_a);", getLLVMStyle()));
+ format("#define x(_a) printf(\"foo\"_a);", Style));
}
TEST_F(FormatTest, BreakStringLiteralsBeforeUnbreakableTokenSequence) {
@@ -6172,14 +6706,18 @@
verifyFormat("void f() {\n"
" return g() {}\n"
" void h() {}");
- verifyFormat("if (foo)\n"
- " return { forgot_closing_brace();\n"
- "test();");
- verifyFormat("int a[] = { void forgot_closing_brace() { f();\n"
+ verifyFormat("int a[] = {void forgot_closing_brace() {f();\n"
"g();\n"
"}");
}
+TEST_F(FormatTest, DoNotPrematurelyEndUnwrappedLineForReturnStatements) {
+ verifyFormat(
+ "void f() {\n"
+ " return C{param1, param2}.SomeCall(param1, param2);\n"
+ "}\n");
+}
+
TEST_F(FormatTest, FormatsClosingBracesInEmptyNestedBlocks) {
verifyFormat("class X {\n"
" void f() {\n"
@@ -6191,6 +6729,7 @@
TEST_F(FormatTest, ConfigurableIndentWidth) {
FormatStyle EightIndent = getLLVMStyleWithColumns(18);
EightIndent.IndentWidth = 8;
+ EightIndent.ContinuationIndentWidth = 8;
verifyFormat("void f() {\n"
" someFunction();\n"
" if (true) {\n"
@@ -6205,8 +6744,7 @@
EightIndent);
verifyFormat("int x[] = {\n"
" call(),\n"
- " call(),\n"
- "};",
+ " call()};",
EightIndent);
}
@@ -6320,17 +6858,17 @@
Tab));
Tab.UseTab = FormatStyle::UT_ForIndentation;
- verifyFormat("T t[] = {\n"
- "\taaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- "\taaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- "\taaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- "\taaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- "\taaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- "\taaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ verifyFormat("{\n"
+ "\taaaaaaaaaaaaaaaaaaaaaaaaaaaa();\n"
+ "\taaaaaaaaaaaaaaaaaaaaaaaaaaaa();\n"
+ "\taaaaaaaaaaaaaaaaaaaaaaaaaaaa();\n"
+ "\taaaaaaaaaaaaaaaaaaaaaaaaaaaa();\n"
+ "\taaaaaaaaaaaaaaaaaaaaaaaaaaaa();\n"
+ "\taaaaaaaaaaaaaaaaaaaaaaaaaaaa();\n"
"};",
Tab);
verifyFormat("enum A {\n"
- "\ta1,\n"
+ "\ta1, // Force multiple lines\n"
"\ta2,\n"
"\ta3\n"
"};",
@@ -6500,9 +7038,9 @@
getLLVMStyle()));
}
-TEST_F(FormatTest, ConfigurableSpaceAfterControlStatementKeyword) {
+TEST_F(FormatTest, ConfigurableSpaceBeforeParens) {
FormatStyle NoSpace = getLLVMStyle();
- NoSpace.SpaceAfterControlStatementKeyword = false;
+ NoSpace.SpaceBeforeParens = FormatStyle::SBPO_Never;
verifyFormat("while(true)\n"
" continue;", NoSpace);
@@ -6519,6 +7057,42 @@
"default:\n"
" break;\n"
"}", NoSpace);
+
+ FormatStyle Space = getLLVMStyle();
+ Space.SpaceBeforeParens = FormatStyle::SBPO_Always;
+
+ verifyFormat("int f ();", Space);
+ verifyFormat("void f (int a, T b) {\n"
+ " while (true)\n"
+ " continue;\n"
+ "}",
+ Space);
+ verifyFormat("if (true)\n"
+ " f ();\n"
+ "else if (true)\n"
+ " f ();",
+ Space);
+ verifyFormat("do {\n"
+ " do_something ();\n"
+ "} while (something ());",
+ Space);
+ verifyFormat("switch (x) {\n"
+ "default:\n"
+ " break;\n"
+ "}",
+ Space);
+ verifyFormat("A::A () : a (1) {}", Space);
+ verifyFormat("void f () __attribute__ ((asdf));", Space);
+ verifyFormat("*(&a + 1);\n"
+ "&((&a)[1]);\n"
+ "a[(b + c) * d];\n"
+ "(((a + 1) * 2) + 3) * 4;",
+ Space);
+ verifyFormat("#define A(x) x", Space);
+ verifyFormat("#define A (x) x", Space);
+ verifyFormat("#if defined(x)\n"
+ "#endif",
+ Space);
}
TEST_F(FormatTest, ConfigurableSpacesInParentheses) {
@@ -6608,10 +7182,7 @@
" b();\n"
" }\n"
" }\n"
- " void g()\n"
- " {\n"
- " return;\n"
- " }\n"
+ " void g() { return; }\n"
"}\n"
"}",
BreakBeforeBrace);
@@ -6629,10 +7200,7 @@
" b();\n"
" }\n"
" }\n"
- " void g()\n"
- " {\n"
- " return;\n"
- " }\n"
+ " void g() { return; }\n"
"}\n"
"}",
BreakBeforeBrace);
@@ -6653,10 +7221,7 @@
" b();\n"
" }\n"
" }\n"
- " void g()\n"
- " {\n"
- " return;\n"
- " }\n"
+ " void g() { return; }\n"
"}\n"
"}",
BreakBeforeBrace);
@@ -6721,6 +7286,16 @@
"}\n",
BreakBeforeBrace);
+ BreakBeforeBrace.ColumnLimit = 19;
+ verifyFormat("void f() { int i; }", BreakBeforeBrace);
+ BreakBeforeBrace.ColumnLimit = 18;
+ verifyFormat("void f()\n"
+ "{\n"
+ " int i;\n"
+ "}",
+ BreakBeforeBrace);
+ BreakBeforeBrace.ColumnLimit = 80;
+
FormatStyle BreakBeforeBraceShortIfs = BreakBeforeBrace;
BreakBeforeBraceShortIfs.AllowShortIfStatementsOnASingleLine = true;
BreakBeforeBraceShortIfs.AllowShortLoopsOnASingleLine = true;
@@ -6747,6 +7322,91 @@
BreakBeforeBraceShortIfs);
}
+TEST_F(FormatTest, GNUBraceBreaking) {
+ FormatStyle GNUBraceStyle = getLLVMStyle();
+ GNUBraceStyle.BreakBeforeBraces = FormatStyle::BS_GNU;
+ verifyFormat("namespace a\n"
+ "{\n"
+ "class A\n"
+ "{\n"
+ " void f()\n"
+ " {\n"
+ " int a;\n"
+ " {\n"
+ " int b;\n"
+ " }\n"
+ " if (true)\n"
+ " {\n"
+ " a();\n"
+ " b();\n"
+ " }\n"
+ " }\n"
+ " void g() { return; }\n"
+ "}\n"
+ "}",
+ GNUBraceStyle);
+
+ verifyFormat("void f()\n"
+ "{\n"
+ " if (true)\n"
+ " {\n"
+ " a();\n"
+ " }\n"
+ " else if (false)\n"
+ " {\n"
+ " b();\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " c();\n"
+ " }\n"
+ "}\n",
+ GNUBraceStyle);
+
+ verifyFormat("void f()\n"
+ "{\n"
+ " for (int i = 0; i < 10; ++i)\n"
+ " {\n"
+ " a();\n"
+ " }\n"
+ " while (false)\n"
+ " {\n"
+ " b();\n"
+ " }\n"
+ " do\n"
+ " {\n"
+ " c();\n"
+ " }\n"
+ " while (false);\n"
+ "}\n",
+ GNUBraceStyle);
+
+ verifyFormat("void f(int a)\n"
+ "{\n"
+ " switch (a)\n"
+ " {\n"
+ " case 0:\n"
+ " break;\n"
+ " case 1:\n"
+ " {\n"
+ " break;\n"
+ " }\n"
+ " case 2:\n"
+ " {\n"
+ " }\n"
+ " break;\n"
+ " default:\n"
+ " break;\n"
+ " }\n"
+ "}\n",
+ GNUBraceStyle);
+
+ verifyFormat("enum X\n"
+ "{\n"
+ " Y = 0,\n"
+ "}\n",
+ GNUBraceStyle);
+}
TEST_F(FormatTest, CatchExceptionReferenceBinding) {
verifyFormat("void f() {\n"
" try {\n"
@@ -6760,48 +7420,102 @@
TEST_F(FormatTest, UnderstandsPragmas) {
verifyFormat("#pragma omp reduction(| : var)");
verifyFormat("#pragma omp reduction(+ : var)");
+
+ EXPECT_EQ("#pragma mark Any non-hyphenated or hyphenated string "
+ "(including parentheses).",
+ format("#pragma mark Any non-hyphenated or hyphenated string "
+ "(including parentheses)."));
}
-bool allStylesEqual(ArrayRef<FormatStyle> Styles) {
- for (size_t i = 1; i < Styles.size(); ++i)
- if (!(Styles[0] == Styles[i]))
- return false;
- return true;
-}
+#define EXPECT_ALL_STYLES_EQUAL(Styles) \
+ for (size_t i = 1; i < Styles.size(); ++i) \
+ EXPECT_EQ(Styles[0], Styles[i]) << "Style #" << i << " of " \
+ << Styles.size() \
+ << " differs from Style #0"
TEST_F(FormatTest, GetsPredefinedStyleByName) {
- FormatStyle Styles[3];
+ SmallVector<FormatStyle, 3> Styles;
+ Styles.resize(3);
Styles[0] = getLLVMStyle();
- EXPECT_TRUE(getPredefinedStyle("LLVM", &Styles[1]));
- EXPECT_TRUE(getPredefinedStyle("lLvM", &Styles[2]));
- EXPECT_TRUE(allStylesEqual(Styles));
+ EXPECT_TRUE(getPredefinedStyle("LLVM", FormatStyle::LK_Cpp, &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("lLvM", FormatStyle::LK_Cpp, &Styles[2]));
+ EXPECT_ALL_STYLES_EQUAL(Styles);
Styles[0] = getGoogleStyle();
- EXPECT_TRUE(getPredefinedStyle("Google", &Styles[1]));
- EXPECT_TRUE(getPredefinedStyle("gOOgle", &Styles[2]));
- EXPECT_TRUE(allStylesEqual(Styles));
+ EXPECT_TRUE(getPredefinedStyle("Google", FormatStyle::LK_Cpp, &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("gOOgle", FormatStyle::LK_Cpp, &Styles[2]));
+ EXPECT_ALL_STYLES_EQUAL(Styles);
- Styles[0] = getChromiumStyle();
- EXPECT_TRUE(getPredefinedStyle("Chromium", &Styles[1]));
- EXPECT_TRUE(getPredefinedStyle("cHRoMiUM", &Styles[2]));
- EXPECT_TRUE(allStylesEqual(Styles));
+ Styles[0] = getGoogleStyle(FormatStyle::LK_JavaScript);
+ EXPECT_TRUE(
+ getPredefinedStyle("Google", FormatStyle::LK_JavaScript, &Styles[1]));
+ EXPECT_TRUE(
+ getPredefinedStyle("gOOgle", FormatStyle::LK_JavaScript, &Styles[2]));
+ EXPECT_ALL_STYLES_EQUAL(Styles);
+
+ Styles[0] = getChromiumStyle(FormatStyle::LK_Cpp);
+ EXPECT_TRUE(getPredefinedStyle("Chromium", FormatStyle::LK_Cpp, &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("cHRoMiUM", FormatStyle::LK_Cpp, &Styles[2]));
+ EXPECT_ALL_STYLES_EQUAL(Styles);
Styles[0] = getMozillaStyle();
- EXPECT_TRUE(getPredefinedStyle("Mozilla", &Styles[1]));
- EXPECT_TRUE(getPredefinedStyle("moZILla", &Styles[2]));
- EXPECT_TRUE(allStylesEqual(Styles));
+ EXPECT_TRUE(getPredefinedStyle("Mozilla", FormatStyle::LK_Cpp, &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("moZILla", FormatStyle::LK_Cpp, &Styles[2]));
+ EXPECT_ALL_STYLES_EQUAL(Styles);
Styles[0] = getWebKitStyle();
- EXPECT_TRUE(getPredefinedStyle("WebKit", &Styles[1]));
- EXPECT_TRUE(getPredefinedStyle("wEbKit", &Styles[2]));
- EXPECT_TRUE(allStylesEqual(Styles));
+ EXPECT_TRUE(getPredefinedStyle("WebKit", FormatStyle::LK_Cpp, &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("wEbKit", FormatStyle::LK_Cpp, &Styles[2]));
+ EXPECT_ALL_STYLES_EQUAL(Styles);
- EXPECT_FALSE(getPredefinedStyle("qwerty", &Styles[0]));
+ Styles[0] = getGNUStyle();
+ EXPECT_TRUE(getPredefinedStyle("GNU", FormatStyle::LK_Cpp, &Styles[1]));
+ EXPECT_TRUE(getPredefinedStyle("gnU", FormatStyle::LK_Cpp, &Styles[2]));
+ EXPECT_ALL_STYLES_EQUAL(Styles);
+
+ EXPECT_FALSE(getPredefinedStyle("qwerty", FormatStyle::LK_Cpp, &Styles[0]));
}
-TEST_F(FormatTest, ParsesConfiguration) {
- FormatStyle Style = {};
+TEST_F(FormatTest, GetsCorrectBasedOnStyle) {
+ SmallVector<FormatStyle, 8> Styles;
+ Styles.resize(2);
+
+ Styles[0] = getGoogleStyle();
+ Styles[1] = getLLVMStyle();
+ EXPECT_EQ(0, parseConfiguration("BasedOnStyle: Google", &Styles[1]).value());
+ EXPECT_ALL_STYLES_EQUAL(Styles);
+
+ Styles.resize(5);
+ Styles[0] = getGoogleStyle(FormatStyle::LK_JavaScript);
+ Styles[1] = getLLVMStyle();
+ Styles[1].Language = FormatStyle::LK_JavaScript;
+ EXPECT_EQ(0, parseConfiguration("BasedOnStyle: Google", &Styles[1]).value());
+
+ Styles[2] = getLLVMStyle();
+ Styles[2].Language = FormatStyle::LK_JavaScript;
+ EXPECT_EQ(0, parseConfiguration("Language: JavaScript\n"
+ "BasedOnStyle: Google",
+ &Styles[2]).value());
+
+ Styles[3] = getLLVMStyle();
+ Styles[3].Language = FormatStyle::LK_JavaScript;
+ EXPECT_EQ(0, parseConfiguration("BasedOnStyle: Google\n"
+ "Language: JavaScript",
+ &Styles[3]).value());
+
+ Styles[4] = getLLVMStyle();
+ Styles[4].Language = FormatStyle::LK_JavaScript;
+ EXPECT_EQ(0, parseConfiguration("---\n"
+ "BasedOnStyle: LLVM\n"
+ "IndentWidth: 123\n"
+ "---\n"
+ "BasedOnStyle: Google\n"
+ "Language: JavaScript",
+ &Styles[4]).value());
+ EXPECT_ALL_STYLES_EQUAL(Styles);
+}
+
#define CHECK_PARSE(TEXT, FIELD, VALUE) \
EXPECT_NE(VALUE, Style.FIELD); \
EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value()); \
@@ -6814,9 +7528,13 @@
EXPECT_EQ(0, parseConfiguration(#FIELD ": false", &Style).value()); \
EXPECT_FALSE(Style.FIELD);
+TEST_F(FormatTest, ParsesConfiguration) {
+ FormatStyle Style = {};
+ Style.Language = FormatStyle::LK_Cpp;
CHECK_PARSE_BOOL(AlignEscapedNewlinesLeft);
CHECK_PARSE_BOOL(AlignTrailingComments);
CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine);
+ CHECK_PARSE_BOOL(AllowShortFunctionsOnASingleLine);
CHECK_PARSE_BOOL(AllowShortIfStatementsOnASingleLine);
CHECK_PARSE_BOOL(AllowShortLoopsOnASingleLine);
CHECK_PARSE_BOOL(AlwaysBreakTemplateDeclarations);
@@ -6827,6 +7545,8 @@
CHECK_PARSE_BOOL(ConstructorInitializerAllOnOneLineOrOnePerLine);
CHECK_PARSE_BOOL(DerivePointerBinding);
CHECK_PARSE_BOOL(IndentCaseLabels);
+ CHECK_PARSE_BOOL(KeepEmptyLinesAtTheStartOfBlocks);
+ CHECK_PARSE_BOOL(ObjCSpaceAfterProperty);
CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList);
CHECK_PARSE_BOOL(PointerBindsToType);
CHECK_PARSE_BOOL(Cpp11BracedListStyle);
@@ -6834,8 +7554,8 @@
CHECK_PARSE_BOOL(SpacesInParentheses);
CHECK_PARSE_BOOL(SpacesInAngles);
CHECK_PARSE_BOOL(SpaceInEmptyParentheses);
+ CHECK_PARSE_BOOL(SpacesInContainerLiterals);
CHECK_PARSE_BOOL(SpacesInCStyleCastParentheses);
- CHECK_PARSE_BOOL(SpaceAfterControlStatementKeyword);
CHECK_PARSE_BOOL(SpaceBeforeAssignmentOperators);
CHECK_PARSE("AccessModifierOffset: -1234", AccessModifierOffset, -1234);
@@ -6867,6 +7587,19 @@
CHECK_PARSE("UseTab: ForIndentation", UseTab, FormatStyle::UT_ForIndentation);
CHECK_PARSE("UseTab: Always", UseTab, FormatStyle::UT_Always);
+ Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
+ CHECK_PARSE("SpaceBeforeParens: Never", SpaceBeforeParens,
+ FormatStyle::SBPO_Never);
+ CHECK_PARSE("SpaceBeforeParens: Always", SpaceBeforeParens,
+ FormatStyle::SBPO_Always);
+ CHECK_PARSE("SpaceBeforeParens: ControlStatements", SpaceBeforeParens,
+ FormatStyle::SBPO_ControlStatements);
+ // For backward compatibility:
+ CHECK_PARSE("SpaceAfterControlStatementKeyword: false", SpaceBeforeParens,
+ FormatStyle::SBPO_Never);
+ CHECK_PARSE("SpaceAfterControlStatementKeyword: true", SpaceBeforeParens,
+ FormatStyle::SBPO_ControlStatements);
+
Style.ColumnLimit = 123;
FormatStyle BaseStyle = getLLVMStyle();
CHECK_PARSE("BasedOnStyle: LLVM", ColumnLimit, BaseStyle.ColumnLimit);
@@ -6879,6 +7612,9 @@
FormatStyle::BS_Linux);
CHECK_PARSE("BreakBeforeBraces: Stroustrup", BreakBeforeBraces,
FormatStyle::BS_Stroustrup);
+ CHECK_PARSE("BreakBeforeBraces: Allman", BreakBeforeBraces,
+ FormatStyle::BS_Allman);
+ CHECK_PARSE("BreakBeforeBraces: GNU", BreakBeforeBraces, FormatStyle::BS_GNU);
Style.NamespaceIndentation = FormatStyle::NI_All;
CHECK_PARSE("NamespaceIndentation: None", NamespaceIndentation,
@@ -6888,14 +7624,145 @@
CHECK_PARSE("NamespaceIndentation: All", NamespaceIndentation,
FormatStyle::NI_All);
+ Style.ForEachMacros.clear();
+ std::vector<std::string> BoostForeach;
+ BoostForeach.push_back("BOOST_FOREACH");
+ CHECK_PARSE("ForEachMacros: [BOOST_FOREACH]", ForEachMacros, BoostForeach);
+ std::vector<std::string> BoostAndQForeach;
+ BoostAndQForeach.push_back("BOOST_FOREACH");
+ BoostAndQForeach.push_back("Q_FOREACH");
+ CHECK_PARSE("ForEachMacros: [BOOST_FOREACH, Q_FOREACH]", ForEachMacros,
+ BoostAndQForeach);
+}
+
+TEST_F(FormatTest, ParsesConfigurationWithLanguages) {
+ FormatStyle Style = {};
+ Style.Language = FormatStyle::LK_Cpp;
+ CHECK_PARSE("Language: Cpp\n"
+ "IndentWidth: 12",
+ IndentWidth, 12u);
+ EXPECT_EQ(llvm::errc::not_supported,
+ parseConfiguration("Language: JavaScript\n"
+ "IndentWidth: 34",
+ &Style));
+ EXPECT_EQ(12u, Style.IndentWidth);
+ CHECK_PARSE("IndentWidth: 56", IndentWidth, 56u);
+ EXPECT_EQ(FormatStyle::LK_Cpp, Style.Language);
+
+ Style.Language = FormatStyle::LK_JavaScript;
+ CHECK_PARSE("Language: JavaScript\n"
+ "IndentWidth: 12",
+ IndentWidth, 12u);
+ CHECK_PARSE("IndentWidth: 23", IndentWidth, 23u);
+ EXPECT_EQ(llvm::errc::not_supported, parseConfiguration("Language: Cpp\n"
+ "IndentWidth: 34",
+ &Style));
+ EXPECT_EQ(23u, Style.IndentWidth);
+ CHECK_PARSE("IndentWidth: 56", IndentWidth, 56u);
+ EXPECT_EQ(FormatStyle::LK_JavaScript, Style.Language);
+
+ CHECK_PARSE("BasedOnStyle: LLVM\n"
+ "IndentWidth: 67",
+ IndentWidth, 67u);
+
+ CHECK_PARSE("---\n"
+ "Language: JavaScript\n"
+ "IndentWidth: 12\n"
+ "---\n"
+ "Language: Cpp\n"
+ "IndentWidth: 34\n"
+ "...\n",
+ IndentWidth, 12u);
+
+ Style.Language = FormatStyle::LK_Cpp;
+ CHECK_PARSE("---\n"
+ "Language: JavaScript\n"
+ "IndentWidth: 12\n"
+ "---\n"
+ "Language: Cpp\n"
+ "IndentWidth: 34\n"
+ "...\n",
+ IndentWidth, 34u);
+ CHECK_PARSE("---\n"
+ "IndentWidth: 78\n"
+ "---\n"
+ "Language: JavaScript\n"
+ "IndentWidth: 56\n"
+ "...\n",
+ IndentWidth, 78u);
+
+ Style.ColumnLimit = 123;
+ Style.IndentWidth = 234;
+ Style.BreakBeforeBraces = FormatStyle::BS_Linux;
+ Style.TabWidth = 345;
+ EXPECT_EQ(llvm::errc::success,
+ parseConfiguration("---\n"
+ "IndentWidth: 456\n"
+ "BreakBeforeBraces: Allman\n"
+ "---\n"
+ "Language: JavaScript\n"
+ "IndentWidth: 111\n"
+ "TabWidth: 111\n"
+ "---\n"
+ "Language: Cpp\n"
+ "BreakBeforeBraces: Stroustrup\n"
+ "TabWidth: 789\n"
+ "...\n",
+ &Style));
+ EXPECT_EQ(123u, Style.ColumnLimit);
+ EXPECT_EQ(456u, Style.IndentWidth);
+ EXPECT_EQ(FormatStyle::BS_Stroustrup, Style.BreakBeforeBraces);
+ EXPECT_EQ(789u, Style.TabWidth);
+
+
+ EXPECT_EQ(llvm::errc::invalid_argument,
+ parseConfiguration("---\n"
+ "Language: JavaScript\n"
+ "IndentWidth: 56\n"
+ "---\n"
+ "IndentWidth: 78\n"
+ "...\n",
+ &Style));
+ EXPECT_EQ(llvm::errc::invalid_argument,
+ parseConfiguration("---\n"
+ "Language: JavaScript\n"
+ "IndentWidth: 56\n"
+ "---\n"
+ "Language: JavaScript\n"
+ "IndentWidth: 78\n"
+ "...\n",
+ &Style));
+
+ EXPECT_EQ(FormatStyle::LK_Cpp, Style.Language);
+}
+
#undef CHECK_PARSE
#undef CHECK_PARSE_BOOL
+
+TEST_F(FormatTest, UsesLanguageForBasedOnStyle) {
+ FormatStyle Style = {};
+ Style.Language = FormatStyle::LK_JavaScript;
+ Style.BreakBeforeTernaryOperators = true;
+ EXPECT_EQ(0, parseConfiguration("BasedOnStyle: Google", &Style).value());
+ EXPECT_FALSE(Style.BreakBeforeTernaryOperators);
+
+ Style.BreakBeforeTernaryOperators = true;
+ EXPECT_EQ(0, parseConfiguration("---\n"
+ "BasedOnStyle: Google\n"
+ "---\n"
+ "Language: JavaScript\n"
+ "IndentWidth: 76\n"
+ "...\n", &Style).value());
+ EXPECT_FALSE(Style.BreakBeforeTernaryOperators);
+ EXPECT_EQ(76u, Style.IndentWidth);
+ EXPECT_EQ(FormatStyle::LK_JavaScript, Style.Language);
}
TEST_F(FormatTest, ConfigurationRoundTripTest) {
FormatStyle Style = getLLVMStyle();
std::string YAML = configurationAsText(Style);
FormatStyle ParsedStyle = {};
+ ParsedStyle.Language = FormatStyle::LK_Cpp;
EXPECT_EQ(0, parseConfiguration(YAML, &ParsedStyle).value());
EXPECT_EQ(Style, ParsedStyle);
}
@@ -6938,6 +7805,16 @@
}
TEST_F(FormatTest, SplitsUTF8Strings) {
+ // Non-printable characters' width is currently considered to be the length in
+ // bytes in UTF8. The characters can be displayed in very different manner
+ // (zero-width, single width with a substitution glyph, expanded to their code
+ // (e.g. "<8d>"), so there's no single correct way to handle them.
+ EXPECT_EQ("\"aaaaÄ\"\n"
+ "\"\xc2\x8d\";",
+ format("\"aaaaÄ\xc2\x8d\";", getLLVMStyleWithColumns(10)));
+ EXPECT_EQ("\"aaaaaaaÄ\"\n"
+ "\"\xc2\x8d\";",
+ format("\"aaaaaaaÄ\xc2\x8d\";", getLLVMStyleWithColumns(10)));
EXPECT_EQ(
"\"Однажды, в \"\n"
"\"студёную \"\n"
@@ -6971,6 +7848,8 @@
}
TEST_F(FormatTest, SplitsUTF8LineComments) {
+ EXPECT_EQ("// aaaaÄ\xc2\x8d",
+ format("// aaaaÄ\xc2\x8d", getLLVMStyleWithColumns(10)));
EXPECT_EQ("// Я из лесу\n"
"// вышел; был\n"
"// сильный\n"
@@ -7041,7 +7920,38 @@
" , b(b)\n"
" , c(c) {}",
Style);
+ verifyFormat("SomeClass::Constructor()\n"
+ " : a(a) {}",
+ Style);
+ Style.ColumnLimit = 0;
+ verifyFormat("SomeClass::Constructor()\n"
+ " : a(a) {}",
+ Style);
+ verifyFormat("SomeClass::Constructor()\n"
+ " : a(a)\n"
+ " , b(b)\n"
+ " , c(c) {}",
+ Style);
+ verifyFormat("SomeClass::Constructor()\n"
+ " : a(a) {\n"
+ " foo();\n"
+ " bar();\n"
+ "}",
+ Style);
+
+ Style.AllowShortFunctionsOnASingleLine = false;
+ verifyFormat("SomeClass::Constructor()\n"
+ " : a(a)\n"
+ " , b(b)\n"
+ " , c(c) {\n}",
+ Style);
+ verifyFormat("SomeClass::Constructor()\n"
+ " : a(a) {\n}",
+ Style);
+
+ Style.ColumnLimit = 80;
+ Style.AllowShortFunctionsOnASingleLine = true;
Style.ConstructorInitializerIndentWidth = 2;
verifyFormat("SomeClass::Constructor()\n"
" : a(a)\n"
@@ -7058,6 +7968,10 @@
Style.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
Style.ConstructorInitializerIndentWidth = 4;
+ verifyFormat("SomeClass::Constructor() : aaaaaaaa(aaaaaaaa) {}", Style);
+ verifyFormat(
+ "SomeClass::Constructor() : aaaaa(aaaaa), aaaaa(aaaaa), aaaaa(aaaaa)\n",
+ Style);
verifyFormat(
"SomeClass::Constructor()\n"
" : aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa) {}",
@@ -7121,7 +8035,32 @@
" : aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
" , aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaa, // break\n"
" aaaaaaaaaaaaaa)\n"
- " , aaaaaaaaaaaaaaaaaaaaaaa()\n{\n}",
+ " , aaaaaaaaaaaaaaaaaaaaaaa()\n"
+ "{\n"
+ "}",
+ Style);
+ verifyFormat("SomeClass::Constructor()\n"
+ " : a(a)\n"
+ "{\n"
+ "}",
+ Style);
+ EXPECT_EQ("SomeClass::Constructor()\n"
+ " : a(a)\n"
+ "{\n"
+ "}",
+ format("SomeClass::Constructor():a(a){}", Style));
+ verifyFormat("SomeClass::Constructor()\n"
+ " : a(a)\n"
+ " , b(b)\n"
+ " , c(c)\n"
+ "{\n"
+ "}", Style);
+ verifyFormat("SomeClass::Constructor()\n"
+ " : a(a)\n"
+ "{\n"
+ " foo();\n"
+ " bar();\n"
+ "}",
Style);
// Access specifiers should be aligned left.
@@ -7159,15 +8098,6 @@
Style));
}
-TEST_F(FormatTest, FormatsProtocolBufferDefinitions) {
- // It seems that clang-format can format protocol buffer definitions
- // (see https://code.google.com/p/protobuf/).
- verifyFormat("message SomeMessage {\n"
- " required int32 field1 = 1;\n"
- " optional string field2 = 2 [default = \"2\"]\n"
- "}");
-}
-
TEST_F(FormatTest, FormatsLambdas) {
verifyFormat("int c = [b]() mutable {\n"
" return [&b] { return b++; }();\n"
@@ -7181,10 +8111,10 @@
verifyFormat("int c = [&a, &a, a] {\n"
" [=, a, b, &c] { return b++; }();\n"
"}();\n");
- verifyFormat("auto c = { [&a, &a, a] {\n"
+ verifyFormat("auto c = {[&a, &a, a] {\n"
" [=, a, b, &c] { return b++; }();\n"
- "} }\n");
- verifyFormat("auto c = { [&a, &a, a] { [=, a, b, &c] {}(); } }\n");
+ "}}\n");
+ verifyFormat("auto c = {[&a, &a, a] { [=, a, b, &c] {}(); }}\n");
verifyFormat("void f() {\n"
" other(x.begin(), x.end(), [&](int, int) { return 1; });\n"
"}\n");
@@ -7194,18 +8124,110 @@
" [&](int, int) { return 1; });\n"
"}\n");
+ // Lambdas with return types.
+ verifyFormat("int c = []() -> int { return 2; }();\n");
+ verifyFormat("int c = []() -> vector<int> { return {2}; }();\n");
+ verifyFormat("Foo([]() -> std::vector<int> { return {2}; }());");
+ verifyFormat("auto aaaaaaaa = [](int i, // break for some reason\n"
+ " int j) -> int {\n"
+ " return fffffffffffffffffffffffffffffffffffffff(i * j);\n"
+ "};");
+
// Not lambdas.
- verifyFormat("constexpr char hello[]{ \"hello\" };");
+ verifyFormat("constexpr char hello[]{\"hello\"};");
verifyFormat("double &operator[](int i) { return 0; }\n"
"int i;");
+ verifyFormat("std::unique_ptr<int[]> foo() {}");
+ verifyFormat("int i = a[a][a]->f();");
+ verifyFormat("int i = (*b)[a]->f();");
+
+ // Other corner cases.
+ verifyFormat("void f() {\n"
+ " bar([]() {} // Did not respect SpacesBeforeTrailingComments\n"
+ " );\n"
+ "}");
+
+ // Lambdas created through weird macros.
+ verifyFormat("void f() {\n"
+ " MACRO((const AA &a) { return 1; });\n"
+ "}");
}
TEST_F(FormatTest, FormatsBlocks) {
+ verifyFormat("int (^Block)(int, int);");
+ verifyFormat("int (^Block1)(int, int) = ^(int i, int j)");
+ verifyFormat("void (^block)(int) = ^(id test) { int i; };");
+ verifyFormat("void (^block)(int) = ^(int test) { int i; };");
+ verifyFormat("void (^block)(int) = ^id(int test) { int i; };");
+ verifyFormat("void (^block)(int) = ^int(int test) { int i; };");
+
+ verifyFormat("foo(^{ bar(); });");
+ verifyFormat("foo(a, ^{ bar(); });");
+
// FIXME: Make whitespace formatting consistent. Ask a ObjC dev how
// it would ideally look.
verifyFormat("[operation setCompletionBlock:^{ [self onOperationDone]; }];");
verifyFormat("int i = {[operation setCompletionBlock : ^{ [self "
- "onOperationDone]; }] };");
+ "onOperationDone]; }]};");
+ verifyFormat("[operation setCompletionBlock:^(int *i) { f(); }];");
+ verifyFormat("int a = [operation block:^int(int *i) { return 1; }];");
+ verifyFormat("[myObject doSomethingWith:arg1\n"
+ " aaa:^int(int *a) { return 1; }\n"
+ " bbb:f(a * b)];");
+
+ verifyFormat("[operation setCompletionBlock:^{\n"
+ " [self.delegate newDataAvailable];\n"
+ "}];",
+ getLLVMStyleWithColumns(60));
+ verifyFormat("dispatch_async(_fileIOQueue, ^{\n"
+ " NSString *path = [self sessionFilePath];\n"
+ " if (path) {\n"
+ " // ...\n"
+ " }\n"
+ "});");
+ verifyFormat("[[SessionService sharedService]\n"
+ " loadWindowWithCompletionBlock:^(SessionWindow *window) {\n"
+ " if (window) {\n"
+ " [self windowDidLoad:window];\n"
+ " } else {\n"
+ " [self errorLoadingWindow];\n"
+ " }\n"
+ " }];");
+ verifyFormat("void (^largeBlock)(void) = ^{\n"
+ " // ...\n"
+ "};\n",
+ getLLVMStyleWithColumns(40));
+ verifyFormat("[[SessionService sharedService]\n"
+ " loadWindowWithCompletionBlock: //\n"
+ " ^(SessionWindow *window) {\n"
+ " if (window) {\n"
+ " [self windowDidLoad:window];\n"
+ " } else {\n"
+ " [self errorLoadingWindow];\n"
+ " }\n"
+ " }];",
+ getLLVMStyleWithColumns(60));
+ verifyFormat("[myObject doSomethingWith:arg1\n"
+ " firstBlock:^(Foo *a) {\n"
+ " // ...\n"
+ " int i;\n"
+ " }\n"
+ " secondBlock:^(Bar *b) {\n"
+ " // ...\n"
+ " int i;\n"
+ " }\n"
+ " thirdBlock:^Foo(Bar *b) {\n"
+ " // ...\n"
+ " int i;\n"
+ " }];");
+
+ verifyFormat("f(^{\n"
+ " @autoreleasepool {\n"
+ " if (a) {\n"
+ " g();\n"
+ " }\n"
+ " }\n"
+ "});");
}
TEST_F(FormatTest, SupportsCRLF) {
@@ -7299,10 +8321,24 @@
Spaces.Standard = FormatStyle::LS_Cpp11;
Spaces.SpacesInAngles = true;
verifyFormat("A< A< int > >();", Spaces);
-
+
Spaces.SpacesInAngles = false;
verifyFormat("A<A<int>>();", Spaces);
}
+TEST_F(FormatTest, HandleUnbalancedImplicitBracesAcrossPPBranches) {
+ std::string code = "#if A\n"
+ "#if B\n"
+ "a.\n"
+ "#endif\n"
+ " a = 1;\n"
+ "#else\n"
+ "#endif\n"
+ "#if C\n"
+ "#else\n"
+ "#endif\n";
+ EXPECT_EQ(code, format(code));
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp
new file mode 100644
index 0000000..c0215e7
--- /dev/null
+++ b/unittests/Format/FormatTestJS.cpp
@@ -0,0 +1,95 @@
+//===- unittest/Format/FormatTestJS.cpp - Formatting unit tests for JS ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "format-test"
+
+#include "FormatTestUtils.h"
+#include "clang/Format/Format.h"
+#include "llvm/Support/Debug.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace format {
+
+class FormatTestJS : public ::testing::Test {
+protected:
+ static std::string format(llvm::StringRef Code, unsigned Offset,
+ unsigned Length, const FormatStyle &Style) {
+ DEBUG(llvm::errs() << "---\n");
+ DEBUG(llvm::errs() << Code << "\n\n");
+ std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
+ tooling::Replacements Replaces = reformat(Style, Code, Ranges);
+ std::string Result = applyAllReplacements(Code, Replaces);
+ EXPECT_NE("", Result);
+ DEBUG(llvm::errs() << "\n" << Result << "\n\n");
+ return Result;
+ }
+
+ static std::string format(llvm::StringRef Code, const FormatStyle &Style) {
+ return format(Code, 0, Code.size(), Style);
+ }
+
+ static FormatStyle getGoogleJSStyleWithColumns(unsigned ColumnLimit) {
+ FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
+ Style.ColumnLimit = ColumnLimit;
+ return Style;
+ }
+
+ static void verifyFormat(
+ llvm::StringRef Code,
+ const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript)) {
+ EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
+ }
+};
+
+TEST_F(FormatTestJS, UnderstandsJavaScriptOperators) {
+ verifyFormat("a == = b;");
+ verifyFormat("a != = b;");
+
+ verifyFormat("a === b;");
+ verifyFormat("aaaaaaa ===\n b;", getGoogleJSStyleWithColumns(10));
+ verifyFormat("a !== b;");
+ verifyFormat("aaaaaaa !==\n b;", getGoogleJSStyleWithColumns(10));
+ verifyFormat("if (a + b + c +\n"
+ " d !==\n"
+ " e + f + g)\n"
+ " q();",
+ getGoogleJSStyleWithColumns(20));
+
+ verifyFormat("a >> >= b;");
+
+ verifyFormat("a >>> b;");
+ verifyFormat("aaaaaaa >>>\n b;", getGoogleJSStyleWithColumns(10));
+ verifyFormat("a >>>= b;");
+ verifyFormat("aaaaaaa >>>=\n b;", getGoogleJSStyleWithColumns(10));
+ verifyFormat("if (a + b + c +\n"
+ " d >>>\n"
+ " e + f + g)\n"
+ " q();",
+ getGoogleJSStyleWithColumns(20));
+ verifyFormat("var x = aaaaaaaaaa ?\n"
+ " bbbbbb :\n"
+ " ccc;",
+ getGoogleJSStyleWithColumns(20));
+}
+
+TEST_F(FormatTestJS, SpacesInContainerLiterals) {
+ verifyFormat("var arr = [1, 2, 3];");
+ verifyFormat("var obj = {a: 1, b: 2, c: 3};");
+
+ verifyFormat("var obj = {a: 1, b: 2, c: 3};",
+ getChromiumStyle(FormatStyle::LK_JavaScript));
+}
+
+TEST_F(FormatTestJS, SingleQuoteStrings) {
+ verifyFormat("this.function('', true);");
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/unittests/Format/FormatTestProto.cpp b/unittests/Format/FormatTestProto.cpp
new file mode 100644
index 0000000..0a4416e
--- /dev/null
+++ b/unittests/Format/FormatTestProto.cpp
@@ -0,0 +1,96 @@
+//===- unittest/Format/FormatTestProto.cpp --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "format-test"
+
+#include "FormatTestUtils.h"
+#include "clang/Format/Format.h"
+#include "llvm/Support/Debug.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace format {
+
+class FormatTestProto : public ::testing::Test {
+protected:
+ static std::string format(llvm::StringRef Code, unsigned Offset,
+ unsigned Length, const FormatStyle &Style) {
+ DEBUG(llvm::errs() << "---\n");
+ DEBUG(llvm::errs() << Code << "\n\n");
+ std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
+ tooling::Replacements Replaces = reformat(Style, Code, Ranges);
+ std::string Result = applyAllReplacements(Code, Replaces);
+ EXPECT_NE("", Result);
+ DEBUG(llvm::errs() << "\n" << Result << "\n\n");
+ return Result;
+ }
+
+ static std::string format(llvm::StringRef Code) {
+ FormatStyle Style = getGoogleStyle(FormatStyle::LK_Proto);
+ Style.ColumnLimit = 60; // To make writing tests easier.
+ return format(Code, 0, Code.size(), Style);
+ }
+
+ static void verifyFormat(llvm::StringRef Code) {
+ EXPECT_EQ(Code.str(), format(test::messUp(Code)));
+ }
+};
+
+TEST_F(FormatTestProto, FormatsMessages) {
+ verifyFormat("message SomeMessage {\n"
+ " required int32 field1 = 1;\n"
+ "}");
+ verifyFormat("message SomeMessage {\n"
+ " required int32 field1 = 1;\n"
+ " optional string field2 = 2 [default = \"2\"]\n"
+ "}");
+
+ verifyFormat("message SomeMessage {\n"
+ " optional really.really.long.and.qualified.type.aaaaaaa\n"
+ " fiiiiiiiiiiiiiiiiiiiiiiiiield = 1;\n"
+ " optional\n"
+ " really.really.long.and.qualified.type.aaaaaaa.aaaaaaaa\n"
+ " another_fiiiiiiiiiiiiiiiiiiiiield = 2;\n"
+ "}");
+}
+
+TEST_F(FormatTestProto, FormatsEnums) {
+ verifyFormat("enum Type {\n"
+ " UNKNOWN = 0;\n"
+ " TYPE_A = 1;\n"
+ " TYPE_B = 2;\n"
+ "};");
+}
+
+TEST_F(FormatTestProto, UnderstandsReturns) {
+ verifyFormat("rpc Search(SearchRequest) returns (SearchResponse);");
+}
+
+TEST_F(FormatTestProto, MessageFieldAttributes) {
+ verifyFormat("optional string test = 1 [default = \"test\"];");
+ verifyFormat("optional bool a = 1 [default = true, deprecated = true];");
+ verifyFormat("optional LongMessageType long_proto_field = 1\n"
+ " [default = REALLY_REALLY_LONG_CONSTANT_VALUE,\n"
+ " deprecated = true];");
+ verifyFormat("optional LongMessageType long_proto_field = 1\n"
+ " [default = REALLY_REALLY_LONG_CONSTANT_VALUE];");
+ verifyFormat("repeated double value = 1\n"
+ " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaaa : AAAAAAAA}];");
+ verifyFormat("repeated double value = 1\n"
+ " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaa : AAAAAAAAAA,\n"
+ " bbbbbbbbbbbbbbbb : BBBBBBBBBB}];");
+}
+
+TEST_F(FormatTestProto, FormatsOptions) {
+ verifyFormat("option java_package = \"my.test.package\";");
+ verifyFormat("option (my_custom_option) = \"abc\";");
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/unittests/Format/FormatTestUtils.h b/unittests/Format/FormatTestUtils.h
new file mode 100644
index 0000000..649f5b3
--- /dev/null
+++ b/unittests/Format/FormatTestUtils.h
@@ -0,0 +1,67 @@
+//===- unittest/Format/FormatTestUtils.h - Formatting unit tests ----------===//
+//
+// 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 functions for Clang-Format related tests.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FORMAT_TEST_UTILS_H
+#define LLVM_CLANG_FORMAT_TEST_UTILS_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace format {
+namespace test {
+
+inline std::string messUp(llvm::StringRef Code) {
+ std::string MessedUp(Code.str());
+ bool InComment = false;
+ bool InPreprocessorDirective = false;
+ bool JustReplacedNewline = false;
+ for (unsigned i = 0, e = MessedUp.size() - 1; i != e; ++i) {
+ if (MessedUp[i] == '/' && MessedUp[i + 1] == '/') {
+ if (JustReplacedNewline)
+ MessedUp[i - 1] = '\n';
+ InComment = true;
+ } else if (MessedUp[i] == '#' && (JustReplacedNewline || i == 0)) {
+ if (i != 0)
+ MessedUp[i - 1] = '\n';
+ InPreprocessorDirective = true;
+ } else if (MessedUp[i] == '\\' && MessedUp[i + 1] == '\n') {
+ MessedUp[i] = ' ';
+ MessedUp[i + 1] = ' ';
+ } else if (MessedUp[i] == '\n') {
+ if (InComment) {
+ InComment = false;
+ } else if (InPreprocessorDirective) {
+ InPreprocessorDirective = false;
+ } else {
+ JustReplacedNewline = true;
+ MessedUp[i] = ' ';
+ }
+ } else if (MessedUp[i] != ' ') {
+ JustReplacedNewline = false;
+ }
+ }
+ std::string WithoutWhitespace;
+ if (MessedUp[0] != ' ')
+ WithoutWhitespace.push_back(MessedUp[0]);
+ for (unsigned i = 1, e = MessedUp.size(); i != e; ++i) {
+ if (MessedUp[i] != ' ' || MessedUp[i - 1] != ' ')
+ WithoutWhitespace.push_back(MessedUp[i]);
+ }
+ return WithoutWhitespace;
+}
+
+} // end namespace test
+} // end namespace format
+} // end namespace clang
+
+#endif // LLVM_CLANG_FORMAT_TEST_UTILS_H
diff --git a/unittests/Frontend/CMakeLists.txt b/unittests/Frontend/CMakeLists.txt
index c65a163..cdc9559 100644
--- a/unittests/Frontend/CMakeLists.txt
+++ b/unittests/Frontend/CMakeLists.txt
@@ -1,14 +1,11 @@
set(LLVM_LINK_COMPONENTS
- ${LLVM_TARGETS_TO_BUILD}
- asmparser
- bitreader
- support
- mc
+ Support
)
add_clang_unittest(FrontendTests
FrontendActionTest.cpp
)
target_link_libraries(FrontendTests
+ clangAST
clangFrontend
)
diff --git a/unittests/Frontend/FrontendActionTest.cpp b/unittests/Frontend/FrontendActionTest.cpp
index bcb340d..e39d00f 100644
--- a/unittests/Frontend/FrontendActionTest.cpp
+++ b/unittests/Frontend/FrontendActionTest.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/MemoryBuffer.h"
#include "gtest/gtest.h"
@@ -24,8 +25,19 @@
class TestASTFrontendAction : public ASTFrontendAction {
public:
+ TestASTFrontendAction(bool enableIncrementalProcessing = false)
+ : EnableIncrementalProcessing(enableIncrementalProcessing) { }
+
+ bool EnableIncrementalProcessing;
std::vector<std::string> decl_names;
+ virtual bool BeginSourceFileAction(CompilerInstance &ci, StringRef filename) {
+ if (EnableIncrementalProcessing)
+ ci.getPreprocessor().enableIncrementalProcessing();
+
+ return ASTFrontendAction::BeginSourceFileAction(ci, filename);
+ }
+
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
return new Visitor(decl_names);
@@ -64,10 +76,28 @@
TestASTFrontendAction test_action;
ASSERT_TRUE(compiler.ExecuteAction(test_action));
- ASSERT_EQ(3U, test_action.decl_names.size());
- EXPECT_EQ("__builtin_va_list", test_action.decl_names[0]);
- EXPECT_EQ("main", test_action.decl_names[1]);
- EXPECT_EQ("x", test_action.decl_names[2]);
+ ASSERT_EQ(2U, test_action.decl_names.size());
+ EXPECT_EQ("main", test_action.decl_names[0]);
+ EXPECT_EQ("x", test_action.decl_names[1]);
+}
+
+TEST(ASTFrontendAction, IncrementalParsing) {
+ CompilerInvocation *invocation = new CompilerInvocation;
+ invocation->getPreprocessorOpts().addRemappedFile(
+ "test.cc", MemoryBuffer::getMemBuffer("int main() { float x; }"));
+ 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);
+ compiler.createDiagnostics();
+
+ TestASTFrontendAction test_action(/*enableIncrementalProcessing=*/true);
+ ASSERT_TRUE(compiler.ExecuteAction(test_action));
+ ASSERT_EQ(2U, test_action.decl_names.size());
+ EXPECT_EQ("main", test_action.decl_names[0]);
+ EXPECT_EQ("x", test_action.decl_names[1]);
}
} // anonymous namespace
diff --git a/unittests/Lex/CMakeLists.txt b/unittests/Lex/CMakeLists.txt
index cb3b927..461e0d9 100644
--- a/unittests/Lex/CMakeLists.txt
+++ b/unittests/Lex/CMakeLists.txt
@@ -1,3 +1,7 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
add_clang_unittest(LexTests
LexerTest.cpp
PPCallbacksTest.cpp
@@ -5,5 +9,9 @@
)
target_link_libraries(LexTests
- clangLex clangParse clangSema
+ clangAST
+ clangBasic
+ clangLex
+ clangParse
+ clangSema
)
diff --git a/unittests/Lex/PPCallbacksTest.cpp b/unittests/Lex/PPCallbacksTest.cpp
index 9405a84..e3a4a76 100644
--- a/unittests/Lex/PPCallbacksTest.cpp
+++ b/unittests/Lex/PPCallbacksTest.cpp
@@ -8,6 +8,8 @@
//===--------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
@@ -20,8 +22,6 @@
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/Sema.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTConsumer.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
#include "gtest/gtest.h"
diff --git a/unittests/Makefile b/unittests/Makefile
index d0dfe47..9b95a6e 100644
--- a/unittests/Makefile
+++ b/unittests/Makefile
@@ -14,7 +14,7 @@
IS_UNITTEST_LEVEL := 1
CLANG_LEVEL := ..
-PARALLEL_DIRS = Basic Lex
+PARALLEL_DIRS = Basic Lex Driver libclang
include $(CLANG_LEVEL)/../..//Makefile.config
diff --git a/unittests/Sema/CMakeLists.txt b/unittests/Sema/CMakeLists.txt
index d491655..c25db81 100644
--- a/unittests/Sema/CMakeLists.txt
+++ b/unittests/Sema/CMakeLists.txt
@@ -1,7 +1,16 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
add_clang_unittest(SemaTests
ExternalSemaSourceTest.cpp
)
target_link_libraries(SemaTests
- clangAST clangASTMatchers clangTooling
+ clangAST
+ clangBasic
+ clangFrontend
+ clangParse
+ clangSema
+ clangTooling
)
diff --git a/unittests/Sema/ExternalSemaSourceTest.cpp b/unittests/Sema/ExternalSemaSourceTest.cpp
index e27d0cd..7cb5af1 100644
--- a/unittests/Sema/ExternalSemaSourceTest.cpp
+++ b/unittests/Sema/ExternalSemaSourceTest.cpp
@@ -137,7 +137,7 @@
class ExternalSemaSourceInstaller : public clang::ASTFrontendAction {
std::vector<NamespaceDiagnosticWatcher *> Watchers;
std::vector<clang::ExternalSemaSource *> Sources;
- llvm::OwningPtr<DiagnosticConsumer> OwnedClient;
+ std::unique_ptr<DiagnosticConsumer> OwnedClient;
protected:
virtual clang::ASTConsumer *
@@ -178,20 +178,20 @@
// Make sure that the NamespaceDiagnosticWatcher is not miscounting.
TEST(ExternalSemaSource, SanityCheck) {
- llvm::OwningPtr<ExternalSemaSourceInstaller> Installer(
+ std::unique_ptr<ExternalSemaSourceInstaller> Installer(
new ExternalSemaSourceInstaller);
NamespaceDiagnosticWatcher Watcher("AAB", "BBB");
Installer->PushWatcher(&Watcher);
std::vector<std::string> Args(1, "-std=c++11");
ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs(
- Installer.take(), "namespace AAA { } using namespace AAB;", Args));
+ Installer.release(), "namespace AAA { } using namespace AAB;", Args));
ASSERT_EQ(0, Watcher.SeenCount);
}
// Check that when we add a NamespaceTypeProvider, we use that suggestion
// instead of the usual suggestion we would use above.
TEST(ExternalSemaSource, ExternalTypoCorrectionPrioritized) {
- llvm::OwningPtr<ExternalSemaSourceInstaller> Installer(
+ std::unique_ptr<ExternalSemaSourceInstaller> Installer(
new ExternalSemaSourceInstaller);
NamespaceTypoProvider Provider("AAB", "BBB");
NamespaceDiagnosticWatcher Watcher("AAB", "BBB");
@@ -199,7 +199,7 @@
Installer->PushWatcher(&Watcher);
std::vector<std::string> Args(1, "-std=c++11");
ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs(
- Installer.take(), "namespace AAA { } using namespace AAB;", Args));
+ Installer.release(), "namespace AAA { } using namespace AAB;", Args));
ASSERT_LE(0, Provider.CallCount);
ASSERT_EQ(1, Watcher.SeenCount);
}
@@ -207,7 +207,7 @@
// Check that we use the first successful TypoCorrection returned from an
// ExternalSemaSource.
TEST(ExternalSemaSource, ExternalTypoCorrectionOrdering) {
- llvm::OwningPtr<ExternalSemaSourceInstaller> Installer(
+ std::unique_ptr<ExternalSemaSourceInstaller> Installer(
new ExternalSemaSourceInstaller);
NamespaceTypoProvider First("XXX", "BBB");
NamespaceTypoProvider Second("AAB", "CCC");
@@ -219,7 +219,7 @@
Installer->PushWatcher(&Watcher);
std::vector<std::string> Args(1, "-std=c++11");
ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs(
- Installer.take(), "namespace AAA { } using namespace AAB;", Args));
+ Installer.release(), "namespace AAA { } using namespace AAB;", Args));
ASSERT_LE(1, First.CallCount);
ASSERT_LE(1, Second.CallCount);
ASSERT_EQ(0, Third.CallCount);
@@ -229,7 +229,7 @@
// We should only try MaybeDiagnoseMissingCompleteType if we can't otherwise
// solve the problem.
TEST(ExternalSemaSource, TryOtherTacticsBeforeDiagnosing) {
- llvm::OwningPtr<ExternalSemaSourceInstaller> Installer(
+ std::unique_ptr<ExternalSemaSourceInstaller> Installer(
new ExternalSemaSourceInstaller);
CompleteTypeDiagnoser Diagnoser(false);
Installer->PushSource(&Diagnoser);
@@ -237,7 +237,7 @@
// This code hits the class template specialization/class member of a class
// template specialization checks in Sema::RequireCompleteTypeImpl.
ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs(
- Installer.take(),
+ Installer.release(),
"template <typename T> struct S { class C { }; }; S<char>::C SCInst;",
Args));
ASSERT_EQ(0, Diagnoser.CallCount);
@@ -246,7 +246,7 @@
// The first ExternalSemaSource where MaybeDiagnoseMissingCompleteType returns
// true should be the last one called.
TEST(ExternalSemaSource, FirstDiagnoserTaken) {
- llvm::OwningPtr<ExternalSemaSourceInstaller> Installer(
+ std::unique_ptr<ExternalSemaSourceInstaller> Installer(
new ExternalSemaSourceInstaller);
CompleteTypeDiagnoser First(false);
CompleteTypeDiagnoser Second(true);
@@ -256,7 +256,7 @@
Installer->PushSource(&Third);
std::vector<std::string> Args(1, "-std=c++11");
ASSERT_FALSE(clang::tooling::runToolOnCodeWithArgs(
- Installer.take(), "class Incomplete; Incomplete IncompleteInstance;",
+ Installer.release(), "class Incomplete; Incomplete IncompleteInstance;",
Args));
ASSERT_EQ(1, First.CallCount);
ASSERT_EQ(1, Second.CallCount);
diff --git a/unittests/Tooling/CMakeLists.txt b/unittests/Tooling/CMakeLists.txt
index 33d7617..c59ff87 100644
--- a/unittests/Tooling/CMakeLists.txt
+++ b/unittests/Tooling/CMakeLists.txt
@@ -1,9 +1,5 @@
set(LLVM_LINK_COMPONENTS
- ${LLVM_TARGETS_TO_BUILD}
- asmparser
- bitreader
- support
- mc
+ Support
)
add_clang_unittest(ToolingTests
@@ -19,6 +15,10 @@
target_link_libraries(ToolingTests
clangAST
- clangTooling
+ clangASTMatchers
+ clangBasic
+ clangFrontend
+ clangLex
clangRewriteCore
+ clangTooling
)
diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp
index c575dff..9f078f4 100644
--- a/unittests/Tooling/CompilationDatabaseTest.cpp
+++ b/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -24,7 +24,7 @@
std::string ErrorMessage;
EXPECT_EQ(NULL, JSONCompilationDatabase::loadFromBuffer(JSONDatabase,
ErrorMessage))
- << "Expected an error because of: " << Explanation;
+ << "Expected an error because of: " << Explanation.str();
}
TEST(JSONCompilationDatabase, ErrsOnInvalidFormat) {
@@ -42,7 +42,7 @@
static std::vector<std::string> getAllFiles(StringRef JSONDatabase,
std::string &ErrorMessage) {
- OwningPtr<CompilationDatabase> Database(
+ std::unique_ptr<CompilationDatabase> Database(
JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
if (!Database) {
ADD_FAILURE() << ErrorMessage;
@@ -53,7 +53,7 @@
static std::vector<CompileCommand> getAllCompileCommands(StringRef JSONDatabase,
std::string &ErrorMessage) {
- OwningPtr<CompilationDatabase> Database(
+ std::unique_ptr<CompilationDatabase> Database(
JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
if (!Database) {
ADD_FAILURE() << ErrorMessage;
@@ -115,7 +115,7 @@
static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName,
StringRef JSONDatabase,
std::string &ErrorMessage) {
- OwningPtr<CompilationDatabase> Database(
+ std::unique_ptr<CompilationDatabase> Database(
JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
if (!Database)
return CompileCommand();
@@ -433,7 +433,7 @@
TEST(ParseFixedCompilationDatabase, ReturnsNullOnEmptyArgumentList) {
int Argc = 0;
- OwningPtr<FixedCompilationDatabase> Database(
+ std::unique_ptr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, NULL));
EXPECT_FALSE(Database);
EXPECT_EQ(0, Argc);
@@ -442,7 +442,7 @@
TEST(ParseFixedCompilationDatabase, ReturnsNullWithoutDoubleDash) {
int Argc = 2;
const char *Argv[] = { "1", "2" };
- OwningPtr<FixedCompilationDatabase> Database(
+ std::unique_ptr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
EXPECT_FALSE(Database);
EXPECT_EQ(2, Argc);
@@ -453,9 +453,9 @@
const char *Argv[] = {
"1", "2", "--\0no-constant-folding", "-DDEF3", "-DDEF4"
};
- OwningPtr<FixedCompilationDatabase> Database(
+ std::unique_ptr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
- ASSERT_TRUE(Database.isValid());
+ ASSERT_TRUE((bool)Database);
std::vector<CompileCommand> Result =
Database->getCompileCommands("source");
ASSERT_EQ(1ul, Result.size());
@@ -472,9 +472,9 @@
TEST(ParseFixedCompilationDatabase, ReturnsEmptyCommandLine) {
int Argc = 3;
const char *Argv[] = { "1", "2", "--\0no-constant-folding" };
- OwningPtr<FixedCompilationDatabase> Database(
+ std::unique_ptr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
- ASSERT_TRUE(Database.isValid());
+ ASSERT_TRUE((bool)Database);
std::vector<CompileCommand> Result =
Database->getCompileCommands("source");
ASSERT_EQ(1ul, Result.size());
@@ -489,9 +489,9 @@
TEST(ParseFixedCompilationDatabase, HandlesPositionalArgs) {
const char *Argv[] = {"1", "2", "--", "-c", "somefile.cpp", "-DDEF3"};
int Argc = sizeof(Argv) / sizeof(char*);
- OwningPtr<FixedCompilationDatabase> Database(
+ std::unique_ptr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
- ASSERT_TRUE(Database.isValid());
+ ASSERT_TRUE((bool)Database);
std::vector<CompileCommand> Result =
Database->getCompileCommands("source");
ASSERT_EQ(1ul, Result.size());
@@ -508,9 +508,9 @@
TEST(ParseFixedCompilationDatabase, HandlesArgv0) {
const char *Argv[] = {"1", "2", "--", "mytool", "somefile.cpp"};
int Argc = sizeof(Argv) / sizeof(char*);
- OwningPtr<FixedCompilationDatabase> Database(
+ std::unique_ptr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
- ASSERT_TRUE(Database.isValid());
+ ASSERT_TRUE((bool)Database);
std::vector<CompileCommand> Result =
Database->getCompileCommands("source");
ASSERT_EQ(1ul, Result.size());
diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp
index 3234767..a5f85ff 100644
--- a/unittests/Tooling/RecursiveASTVisitorTest.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "TestVisitor.h"
-
#include <stack>
namespace clang {
@@ -577,4 +576,43 @@
EXPECT_TRUE(Visitor.sawOnlyImplicitLambdaClasses());
}
+
+
+// Check to ensure that attributes and expressions within them are being
+// visited.
+class AttrVisitor : public ExpectedLocationVisitor<AttrVisitor> {
+public:
+ bool VisitMemberExpr(MemberExpr *ME) {
+ Match(ME->getMemberDecl()->getNameAsString(), ME->getLocStart());
+ return true;
+ }
+ bool VisitAttr(Attr *A) {
+ Match("Attr", A->getLocation());
+ return true;
+ }
+ bool VisitGuardedByAttr(GuardedByAttr *A) {
+ Match("guarded_by", A->getLocation());
+ return true;
+ }
+};
+
+
+TEST(RecursiveASTVisitor, AttributesAreVisited) {
+ AttrVisitor Visitor;
+ Visitor.ExpectMatch("Attr", 4, 24);
+ Visitor.ExpectMatch("guarded_by", 4, 24);
+ Visitor.ExpectMatch("mu1", 4, 35);
+ Visitor.ExpectMatch("Attr", 5, 29);
+ Visitor.ExpectMatch("mu1", 5, 54);
+ Visitor.ExpectMatch("mu2", 5, 59);
+ EXPECT_TRUE(Visitor.runOver(
+ "class Foo {\n"
+ " int mu1;\n"
+ " int mu2;\n"
+ " int a __attribute__((guarded_by(mu1)));\n"
+ " void bar() __attribute__((exclusive_locks_required(mu1, mu2)));\n"
+ "};\n"));
+}
+
+
} // end namespace clang
diff --git a/unittests/Tooling/RefactoringCallbacksTest.cpp b/unittests/Tooling/RefactoringCallbacksTest.cpp
index 9e086d8..c2b331c 100644
--- a/unittests/Tooling/RefactoringCallbacksTest.cpp
+++ b/unittests/Tooling/RefactoringCallbacksTest.cpp
@@ -25,7 +25,7 @@
RefactoringCallback &Callback) {
MatchFinder Finder;
Finder.addMatcher(AMatcher, &Callback);
- OwningPtr<tooling::FrontendActionFactory> Factory(
+ std::unique_ptr<tooling::FrontendActionFactory> Factory(
tooling::newFrontendActionFactory(&Finder));
ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), Code))
<< "Parsing error in \"" << Code << "\"";
diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp
index 2c4a8a7..1eff6d0 100644
--- a/unittests/Tooling/ToolingTest.cpp
+++ b/unittests/Tooling/ToolingTest.cpp
@@ -16,8 +16,9 @@
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/Tooling.h"
-#include "gtest/gtest.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Config/config.h"
+#include "gtest/gtest.h"
#include <string>
namespace clang {
@@ -60,12 +61,7 @@
bool FoundTopLevelDecl = false;
EXPECT_TRUE(runToolOnCode(
new TestAction(new FindTopLevelDeclConsumer(&FoundTopLevelDecl)), ""));
-#if !defined(_MSC_VER)
EXPECT_FALSE(FoundTopLevelDecl);
-#else
- // FIXME: LangOpts.MicrosoftExt appends "class type_info;"
- EXPECT_TRUE(FoundTopLevelDecl);
-#endif
}
namespace {
@@ -112,7 +108,7 @@
}
TEST(buildASTFromCode, FindsClassDecl) {
- OwningPtr<ASTUnit> AST(buildASTFromCode("class X;"));
+ std::unique_ptr<ASTUnit> AST(buildASTFromCode("class X;"));
ASSERT_TRUE(AST.get());
EXPECT_TRUE(FindClassDeclX(AST.get()));
@@ -122,9 +118,9 @@
}
TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) {
- OwningPtr<FrontendActionFactory> Factory(
+ std::unique_ptr<FrontendActionFactory> Factory(
newFrontendActionFactory<SyntaxOnlyAction>());
- OwningPtr<FrontendAction> Action(Factory->create());
+ std::unique_ptr<FrontendAction> Action(Factory->create());
EXPECT_TRUE(Action.get() != NULL);
}
@@ -136,9 +132,9 @@
TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) {
IndependentFrontendActionCreator Creator;
- OwningPtr<FrontendActionFactory> Factory(
+ std::unique_ptr<FrontendActionFactory> Factory(
newFrontendActionFactory(&Creator));
- OwningPtr<FrontendAction> Action(Factory->create());
+ std::unique_ptr<FrontendAction> Action(Factory->create());
EXPECT_TRUE(Action.get() != NULL);
}
@@ -182,7 +178,7 @@
struct VerifyEndCallback : public SourceFileCallbacks {
VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {}
virtual bool handleBeginSource(CompilerInstance &CI,
- StringRef Filename) LLVM_OVERRIDE {
+ StringRef Filename) override {
++BeginCalled;
return true;
}
@@ -197,7 +193,7 @@
bool Matched;
};
-#if !defined(_WIN32)
+#if !defined(LLVM_ON_WIN32)
TEST(newFrontendActionFactory, InjectsSourceFileCallbacks) {
VerifyEndCallback EndCallback;
@@ -241,6 +237,21 @@
"int skipMeNot() { an_error_here }"));
}
+TEST(runToolOnCodeWithArgs, TestNoDepFile) {
+ llvm::SmallString<32> DepFilePath;
+ ASSERT_FALSE(
+ llvm::sys::fs::createTemporaryFile("depfile", "d", DepFilePath));
+ std::vector<std::string> Args;
+ Args.push_back("-MMD");
+ Args.push_back("-MT");
+ Args.push_back(DepFilePath.str());
+ Args.push_back("-MF");
+ Args.push_back(DepFilePath.str());
+ EXPECT_TRUE(runToolOnCodeWithArgs(new SkipBodyAction, "", Args));
+ EXPECT_FALSE(llvm::sys::fs::exists(DepFilePath.str()));
+ EXPECT_FALSE(llvm::sys::fs::remove(DepFilePath.str()));
+}
+
struct CheckSyntaxOnlyAdjuster: public ArgumentsAdjuster {
bool &Found;
bool &Ran;
@@ -248,7 +259,7 @@
CheckSyntaxOnlyAdjuster(bool &Found, bool &Ran) : Found(Found), Ran(Ran) { }
virtual CommandLineArguments
- Adjust(const CommandLineArguments &Args) LLVM_OVERRIDE {
+ Adjust(const CommandLineArguments &Args) override {
Ran = true;
for (unsigned I = 0, E = Args.size(); I != E; ++I) {
if (Args[I] == "-fsyntax-only") {
@@ -282,7 +293,7 @@
EXPECT_FALSE(Found);
}
-#ifndef _WIN32
+#ifndef LLVM_ON_WIN32
TEST(ClangToolTest, BuildASTs) {
FixedCompilationDatabase Compilations("/", std::vector<std::string>());
diff --git a/unittests/libclang/CMakeLists.txt b/unittests/libclang/CMakeLists.txt
new file mode 100644
index 0000000..1cdc45e
--- /dev/null
+++ b/unittests/libclang/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_clang_unittest(libclangTests
+ LibclangTest.cpp
+ )
+
+target_link_libraries(libclangTests
+ libclang
+ )
diff --git a/unittests/libclang/LibclangTest.cpp b/unittests/libclang/LibclangTest.cpp
new file mode 100644
index 0000000..64128f1
--- /dev/null
+++ b/unittests/libclang/LibclangTest.cpp
@@ -0,0 +1,189 @@
+//===- unittests/libclang/LibclangTest.cpp --- libclang tests -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang-c/Index.h"
+#include "gtest/gtest.h"
+
+TEST(libclang, clang_parseTranslationUnit2_InvalidArgs) {
+ EXPECT_EQ(CXError_InvalidArguments,
+ clang_parseTranslationUnit2(0, 0, 0, 0, 0, 0, 0, 0));
+}
+
+TEST(libclang, clang_createTranslationUnit_InvalidArgs) {
+ EXPECT_EQ(0, clang_createTranslationUnit(0, 0));
+}
+
+TEST(libclang, clang_createTranslationUnit2_InvalidArgs) {
+ EXPECT_EQ(CXError_InvalidArguments,
+ clang_createTranslationUnit2(0, 0, 0));
+
+ CXTranslationUnit TU = reinterpret_cast<CXTranslationUnit>(1);
+ EXPECT_EQ(CXError_InvalidArguments,
+ clang_createTranslationUnit2(0, 0, &TU));
+ EXPECT_EQ(0, TU);
+}
+
+namespace {
+struct TestVFO {
+ const char *Contents;
+ CXVirtualFileOverlay VFO;
+
+ TestVFO(const char *Contents) : Contents(Contents) {
+ VFO = clang_VirtualFileOverlay_create(0);
+ }
+
+ void map(const char *VPath, const char *RPath) {
+ CXErrorCode Err = clang_VirtualFileOverlay_addFileMapping(VFO, VPath, RPath);
+ EXPECT_EQ(Err, CXError_Success);
+ }
+
+ void mapError(const char *VPath, const char *RPath, CXErrorCode ExpErr) {
+ CXErrorCode Err = clang_VirtualFileOverlay_addFileMapping(VFO, VPath, RPath);
+ EXPECT_EQ(Err, ExpErr);
+ }
+
+ ~TestVFO() {
+ if (!Contents)
+ return;
+ char *BufPtr;
+ unsigned BufSize;
+ clang_VirtualFileOverlay_writeToBuffer(VFO, 0, &BufPtr, &BufSize);
+ std::string BufStr(BufPtr, BufSize);
+ EXPECT_STREQ(Contents, BufStr.c_str());
+ free(BufPtr);
+ clang_VirtualFileOverlay_dispose(VFO);
+ }
+};
+}
+
+TEST(libclang, VirtualFileOverlay) {
+ {
+ const char *contents =
+ "{\n"
+ " 'version': 0,\n"
+ " 'roots': [\n"
+ " {\n"
+ " 'type': 'directory',\n"
+ " 'name': \"/path/virtual\",\n"
+ " 'contents': [\n"
+ " {\n"
+ " 'type': 'file',\n"
+ " 'name': \"foo.h\",\n"
+ " 'external-contents': \"/real/foo.h\"\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " ]\n"
+ "}\n";
+ TestVFO T(contents);
+ T.map("/path/virtual/foo.h", "/real/foo.h");
+ }
+ {
+ TestVFO T(NULL);
+ T.mapError("/path/./virtual/../foo.h", "/real/foo.h",
+ CXError_InvalidArguments);
+ }
+ {
+ const char *contents =
+ "{\n"
+ " 'version': 0,\n"
+ " 'roots': [\n"
+ " {\n"
+ " 'type': 'directory',\n"
+ " 'name': \"/another/dir\",\n"
+ " 'contents': [\n"
+ " {\n"
+ " 'type': 'file',\n"
+ " 'name': \"foo2.h\",\n"
+ " 'external-contents': \"/real/foo2.h\"\n"
+ " }\n"
+ " ]\n"
+ " },\n"
+ " {\n"
+ " 'type': 'directory',\n"
+ " 'name': \"/path/virtual/dir\",\n"
+ " 'contents': [\n"
+ " {\n"
+ " 'type': 'file',\n"
+ " 'name': \"foo1.h\",\n"
+ " 'external-contents': \"/real/foo1.h\"\n"
+ " },\n"
+ " {\n"
+ " 'type': 'file',\n"
+ " 'name': \"foo3.h\",\n"
+ " 'external-contents': \"/real/foo3.h\"\n"
+ " },\n"
+ " {\n"
+ " 'type': 'directory',\n"
+ " 'name': \"in/subdir\",\n"
+ " 'contents': [\n"
+ " {\n"
+ " 'type': 'file',\n"
+ " 'name': \"foo4.h\",\n"
+ " 'external-contents': \"/real/foo4.h\"\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " ]\n"
+ "}\n";
+ TestVFO T(contents);
+ T.map("/path/virtual/dir/foo1.h", "/real/foo1.h");
+ T.map("/another/dir/foo2.h", "/real/foo2.h");
+ T.map("/path/virtual/dir/foo3.h", "/real/foo3.h");
+ T.map("/path/virtual/dir/in/subdir/foo4.h", "/real/foo4.h");
+ }
+ {
+ const char *contents =
+ "{\n"
+ " 'version': 0,\n"
+ " 'case-sensitive': 'false',\n"
+ " 'roots': [\n"
+ " {\n"
+ " 'type': 'directory',\n"
+ " 'name': \"/path/virtual\",\n"
+ " 'contents': [\n"
+ " {\n"
+ " 'type': 'file',\n"
+ " 'name': \"foo.h\",\n"
+ " 'external-contents': \"/real/foo.h\"\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " ]\n"
+ "}\n";
+ TestVFO T(contents);
+ T.map("/path/virtual/foo.h", "/real/foo.h");
+ clang_VirtualFileOverlay_setCaseSensitivity(T.VFO, false);
+ }
+}
+
+TEST(libclang, ModuleMapDescriptor) {
+ const char *Contents =
+ "framework module TestFrame {\n"
+ " umbrella header \"TestFrame.h\"\n"
+ "\n"
+ " export *\n"
+ " module * { export * }\n"
+ "}\n";
+
+ CXModuleMapDescriptor MMD = clang_ModuleMapDescriptor_create(0);
+
+ clang_ModuleMapDescriptor_setFrameworkModuleName(MMD, "TestFrame");
+ clang_ModuleMapDescriptor_setUmbrellaHeader(MMD, "TestFrame.h");
+
+ char *BufPtr;
+ unsigned BufSize;
+ clang_ModuleMapDescriptor_writeToBuffer(MMD, 0, &BufPtr, &BufSize);
+ std::string BufStr(BufPtr, BufSize);
+ EXPECT_STREQ(Contents, BufStr.c_str());
+ free(BufPtr);
+ clang_ModuleMapDescriptor_dispose(MMD);
+}
diff --git a/unittests/libclang/Makefile b/unittests/libclang/Makefile
new file mode 100644
index 0000000..7b14c82
--- /dev/null
+++ b/unittests/libclang/Makefile
@@ -0,0 +1,27 @@
+##===- unittests/libclang/Makefile -------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL = ../..
+TESTNAME = libclang
+LINK_LIBS_IN_SHARED := 1
+
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
+
+# Note that 'USEDLIBS' must include all of the core clang libraries
+# when -static is given to linker on cygming.
+USEDLIBS = clang.a \
+ clangIndex.a clangFormat.a clangRewriteCore.a \
+ clangFrontend.a clangDriver.a \
+ clangTooling.a \
+ clangSerialization.a clangParse.a clangSema.a \
+ clangAnalysis.a clangEdit.a clangAST.a clangLex.a \
+ clangBasic.a
+
+include $(CLANG_LEVEL)/unittests/Makefile