diff options
Diffstat (limited to 'unittests')
35 files changed, 2621 insertions, 485 deletions
diff --git a/unittests/AST/ASTContextParentMapTest.cpp b/unittests/AST/ASTContextParentMapTest.cpp index 0dcb175e07b31..b1d7db4164ef2 100644 --- a/unittests/AST/ASTContextParentMapTest.cpp +++ b/unittests/AST/ASTContextParentMapTest.cpp @@ -27,8 +27,9 @@ using clang::tooling::FrontendActionFactory; TEST(GetParents, ReturnsParentForDecl) { MatchVerifier<Decl> Verifier; - EXPECT_TRUE(Verifier.match("class C { void f(); };", - methodDecl(hasParent(recordDecl(hasName("C")))))); + EXPECT_TRUE( + Verifier.match("class C { void f(); };", + cxxMethodDecl(hasParent(recordDecl(hasName("C")))))); } TEST(GetParents, ReturnsParentForStmt) { @@ -37,24 +38,38 @@ TEST(GetParents, ReturnsParentForStmt) { ifStmt(hasParent(compoundStmt())))); } +TEST(GetParents, ReturnsParentForTypeLoc) { + MatchVerifier<TypeLoc> Verifier; + EXPECT_TRUE( + Verifier.match("namespace a { class b {}; } void f(a::b) {}", + typeLoc(hasParent(typeLoc(hasParent(functionDecl())))))); +} + +TEST(GetParents, ReturnsParentForNestedNameSpecifierLoc) { + MatchVerifier<NestedNameSpecifierLoc> Verifier; + EXPECT_TRUE(Verifier.match("namespace a { class b {}; } void f(a::b) {}", + nestedNameSpecifierLoc(hasParent(typeLoc())))); +} + TEST(GetParents, ReturnsParentInsideTemplateInstantiations) { MatchVerifier<Decl> DeclVerifier; EXPECT_TRUE(DeclVerifier.match( "template<typename T> struct C { void f() {} };" "void g() { C<int> c; c.f(); }", - methodDecl(hasName("f"), - hasParent(recordDecl(isTemplateInstantiation()))))); + cxxMethodDecl(hasName("f"), + hasParent(cxxRecordDecl(isTemplateInstantiation()))))); EXPECT_TRUE(DeclVerifier.match( "template<typename T> struct C { void f() {} };" "void g() { C<int> c; c.f(); }", - methodDecl(hasName("f"), - hasParent(recordDecl(unless(isTemplateInstantiation())))))); + cxxMethodDecl(hasName("f"), + hasParent(cxxRecordDecl(unless(isTemplateInstantiation())))))); EXPECT_FALSE(DeclVerifier.match( "template<typename T> struct C { void f() {} };" "void g() { C<int> c; c.f(); }", - methodDecl(hasName("f"), - allOf(hasParent(recordDecl(unless(isTemplateInstantiation()))), - hasParent(recordDecl(isTemplateInstantiation())))))); + cxxMethodDecl( + hasName("f"), + allOf(hasParent(cxxRecordDecl(unless(isTemplateInstantiation()))), + hasParent(cxxRecordDecl(isTemplateInstantiation())))))); } TEST(GetParents, ReturnsMultipleParentsInTemplateInstantiations) { @@ -62,9 +77,9 @@ TEST(GetParents, ReturnsMultipleParentsInTemplateInstantiations) { EXPECT_TRUE(TemplateVerifier.match( "template<typename T> struct C { void f() {} };" "void g() { C<int> c; c.f(); }", - compoundStmt( - allOf(hasAncestor(recordDecl(isTemplateInstantiation())), - hasAncestor(recordDecl(unless(isTemplateInstantiation()))))))); + compoundStmt(allOf( + hasAncestor(cxxRecordDecl(isTemplateInstantiation())), + hasAncestor(cxxRecordDecl(unless(isTemplateInstantiation()))))))); } } // end namespace ast_matchers diff --git a/unittests/AST/ASTTypeTraitsTest.cpp b/unittests/AST/ASTTypeTraitsTest.cpp index eeb01ccad1dfe..b6356538a12ae 100644 --- a/unittests/AST/ASTTypeTraitsTest.cpp +++ b/unittests/AST/ASTTypeTraitsTest.cpp @@ -162,5 +162,12 @@ TEST(DynTypedNode, StmtPrint) { EXPECT_TRUE(Verifier.match("void f() {}", stmt())); } +TEST(DynTypedNode, QualType) { + QualType Q; + DynTypedNode Node = DynTypedNode::create(Q); + EXPECT_TRUE(Node == Node); + EXPECT_FALSE(Node < Node); +} + } // namespace ast_type_traits } // namespace clang diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp index d8cb97709229b..d06fbfea6f5e5 100644 --- a/unittests/AST/DeclPrinterTest.cpp +++ b/unittests/AST/DeclPrinterTest.cpp @@ -471,7 +471,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl1) { "struct A {" " A();" "};", - constructorDecl(ofClass(hasName("A"))).bind("id"), + cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A()")); } @@ -480,7 +480,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl2) { "struct A {" " A(int a);" "};", - constructorDecl(ofClass(hasName("A"))).bind("id"), + cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A(int a)")); } @@ -489,7 +489,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl3) { "struct A {" " A(const A &a);" "};", - constructorDecl(ofClass(hasName("A"))).bind("id"), + cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A(const A &a)")); } @@ -498,7 +498,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl4) { "struct A {" " A(const A &a, int = 0);" "};", - constructorDecl(ofClass(hasName("A"))).bind("id"), + cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A(const A &a, int = 0)")); } @@ -507,7 +507,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl5) { "struct A {" " A(const A &&a);" "};", - constructorDecl(ofClass(hasName("A"))).bind("id"), + cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A(const A &&a)")); } @@ -516,7 +516,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl6) { "struct A {" " explicit A(int a);" "};", - constructorDecl(ofClass(hasName("A"))).bind("id"), + cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "explicit A(int a)")); } @@ -525,7 +525,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl7) { "struct A {" " constexpr A();" "};", - constructorDecl(ofClass(hasName("A"))).bind("id"), + cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "constexpr A()")); } @@ -534,7 +534,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl8) { "struct A {" " A() = default;" "};", - constructorDecl(ofClass(hasName("A"))).bind("id"), + cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A() = default")); } @@ -543,7 +543,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl9) { "struct A {" " A() = delete;" "};", - constructorDecl(ofClass(hasName("A"))).bind("id"), + cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A() = delete")); } @@ -553,7 +553,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl10) { "struct A {" " A(const A &a);" "};", - constructorDecl(ofClass(hasName("A"))).bind("id"), + cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A<T...>(const A<T...> &a)")); // WRONG; Should be: "A(const A<T...> &a);" } @@ -564,7 +564,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl11) { "struct A : public T... {" " A(T&&... ts) : T(ts)... {}" "};", - constructorDecl(ofClass(hasName("A"))).bind("id"), + cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A<T...>(T &&...ts) : T(ts)...")); // WRONG; Should be: "A(T &&...ts) : T(ts)... {}" } @@ -574,7 +574,7 @@ TEST(DeclPrinter, TestCXXDestructorDecl1) { "struct A {" " ~A();" "};", - destructorDecl(ofClass(hasName("A"))).bind("id"), + cxxDestructorDecl(ofClass(hasName("A"))).bind("id"), "~A()")); } @@ -583,7 +583,7 @@ TEST(DeclPrinter, TestCXXDestructorDecl2) { "struct A {" " virtual ~A();" "};", - destructorDecl(ofClass(hasName("A"))).bind("id"), + cxxDestructorDecl(ofClass(hasName("A"))).bind("id"), "virtual ~A()")); } @@ -592,7 +592,7 @@ TEST(DeclPrinter, TestCXXConversionDecl1) { "struct A {" " operator int();" "};", - methodDecl(ofClass(hasName("A"))).bind("id"), + cxxMethodDecl(ofClass(hasName("A"))).bind("id"), "operator int()")); } @@ -601,7 +601,7 @@ TEST(DeclPrinter, TestCXXConversionDecl2) { "struct A {" " operator bool();" "};", - methodDecl(ofClass(hasName("A"))).bind("id"), + cxxMethodDecl(ofClass(hasName("A"))).bind("id"), "operator bool()")); } @@ -611,7 +611,7 @@ TEST(DeclPrinter, TestCXXConversionDecl3) { "struct A {" " operator Z();" "};", - methodDecl(ofClass(hasName("A"))).bind("id"), + cxxMethodDecl(ofClass(hasName("A"))).bind("id"), "operator Z()")); } @@ -621,7 +621,7 @@ TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction1) { "struct Z {" " void *operator new(std::size_t);" "};", - methodDecl(ofClass(hasName("Z"))).bind("id"), + cxxMethodDecl(ofClass(hasName("Z"))).bind("id"), "void *operator new(std::size_t)")); // Should be: with semicolon } @@ -632,7 +632,7 @@ TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction2) { "struct Z {" " void *operator new[](std::size_t);" "};", - methodDecl(ofClass(hasName("Z"))).bind("id"), + cxxMethodDecl(ofClass(hasName("Z"))).bind("id"), "void *operator new[](std::size_t)")); // Should be: with semicolon } @@ -642,7 +642,7 @@ TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction3) { "struct Z {" " void operator delete(void *);" "};", - methodDecl(ofClass(hasName("Z"))).bind("id"), + cxxMethodDecl(ofClass(hasName("Z"))).bind("id"), "void operator delete(void *) noexcept")); // Should be: with semicolon, without noexcept? } @@ -652,7 +652,7 @@ TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction4) { "struct Z {" " void operator delete(void *);" "};", - methodDecl(ofClass(hasName("Z"))).bind("id"), + cxxMethodDecl(ofClass(hasName("Z"))).bind("id"), "void operator delete(void *)")); // Should be: with semicolon } @@ -662,7 +662,7 @@ TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction5) { "struct Z {" " void operator delete[](void *);" "};", - methodDecl(ofClass(hasName("Z"))).bind("id"), + cxxMethodDecl(ofClass(hasName("Z"))).bind("id"), "void operator delete[](void *) noexcept")); // Should be: with semicolon, without noexcept? } @@ -690,7 +690,7 @@ TEST(DeclPrinter, TestCXXMethodDecl_Operator1) { ASSERT_TRUE(PrintedDeclCXX98Matches( Code, - methodDecl(ofClass(hasName("Z"))).bind("id"), + cxxMethodDecl(ofClass(hasName("Z"))).bind("id"), Expected)); } } @@ -714,7 +714,7 @@ TEST(DeclPrinter, TestCXXMethodDecl_Operator2) { ASSERT_TRUE(PrintedDeclCXX98Matches( Code, - methodDecl(ofClass(hasName("Z"))).bind("id"), + cxxMethodDecl(ofClass(hasName("Z"))).bind("id"), Expected)); } } diff --git a/unittests/AST/NamedDeclPrinterTest.cpp b/unittests/AST/NamedDeclPrinterTest.cpp index cf97a0abf6c8b..92df4577ac779 100644 --- a/unittests/AST/NamedDeclPrinterTest.cpp +++ b/unittests/AST/NamedDeclPrinterTest.cpp @@ -131,3 +131,45 @@ TEST(NamedDeclPrinter, TestNamespace2) { "A", "A")); } + +TEST(NamedDeclPrinter, TestUnscopedUnnamedEnum) { + ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( + "enum { A };", + "A", + "A")); +} + +TEST(NamedDeclPrinter, TestNamedEnum) { + ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( + "enum X { A };", + "A", + "X::A")); +} + +TEST(NamedDeclPrinter, TestScopedNamedEnum) { + ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( + "enum class X { A };", + "A", + "X::A")); +} + +TEST(NamedDeclPrinter, TestClassWithUnscopedUnnamedEnum) { + ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( + "class X { enum { A }; };", + "A", + "X::A")); +} + +TEST(NamedDeclPrinter, TestClassWithUnscopedNamedEnum) { + ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( + "class X { enum Y { A }; };", + "A", + "X::Y::A")); +} + +TEST(NamedDeclPrinter, TestClassWithScopedNamedEnum) { + ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( + "class X { enum class Y { A }; };", + "A", + "X::Y::A")); +} diff --git a/unittests/AST/SourceLocationTest.cpp b/unittests/AST/SourceLocationTest.cpp index b0a8f85f0e403..4c77def61bc4a 100644 --- a/unittests/AST/SourceLocationTest.cpp +++ b/unittests/AST/SourceLocationTest.cpp @@ -92,13 +92,13 @@ TEST(ParmVarDecl, KNRRange) { TEST(CXXNewExpr, ArrayRange) { RangeVerifier<CXXNewExpr> Verifier; Verifier.expectRange(1, 12, 1, 22); - EXPECT_TRUE(Verifier.match("void f() { new int[10]; }", newExpr())); + EXPECT_TRUE(Verifier.match("void f() { new int[10]; }", cxxNewExpr())); } TEST(CXXNewExpr, ParenRange) { RangeVerifier<CXXNewExpr> Verifier; Verifier.expectRange(1, 12, 1, 20); - EXPECT_TRUE(Verifier.match("void f() { new int(); }", newExpr())); + EXPECT_TRUE(Verifier.match("void f() { new int(); }", cxxNewExpr())); } TEST(MemberExpr, ImplicitMemberRange) { @@ -221,7 +221,7 @@ TEST(TemplateSpecializationTypeLoc, AngleBracketLocations) { TEST(CXXNewExpr, TypeParenRange) { RangeVerifier<CXXNewExpr> Verifier; Verifier.expectRange(1, 10, 1, 18); - EXPECT_TRUE(Verifier.match("int* a = new (int);", newExpr())); + EXPECT_TRUE(Verifier.match("int* a = new (int);", cxxNewExpr())); } class UnaryTransformTypeLocParensRangeVerifier : public RangeVerifier<TypeLoc> { @@ -252,7 +252,7 @@ TEST(CXXFunctionalCastExpr, SourceRange) { "int foo() {\n" " return int{};\n" "}", - functionalCastExpr(), Lang_CXX11)); + cxxFunctionalCastExpr(), Lang_CXX11)); } TEST(CXXConstructExpr, SourceRange) { @@ -262,7 +262,7 @@ TEST(CXXConstructExpr, SourceRange) { "struct A { A(int, int); };\n" "void f(A a);\n" "void g() { f({0, 0}); }", - constructExpr(), Lang_CXX11)); + cxxConstructExpr(), Lang_CXX11)); } TEST(CXXTemporaryObjectExpr, SourceRange) { @@ -271,7 +271,7 @@ TEST(CXXTemporaryObjectExpr, SourceRange) { EXPECT_TRUE(Verifier.match( "struct A { A(int, int); };\n" "A a( A{0, 0} );", - temporaryObjectExpr(), Lang_CXX11)); + cxxTemporaryObjectExpr(), Lang_CXX11)); } TEST(CXXUnresolvedConstructExpr, SourceRange) { @@ -284,7 +284,7 @@ TEST(CXXUnresolvedConstructExpr, SourceRange) { "U foo() {\n" " return U{};\n" "}", - unresolvedConstructExpr(), Args, Lang_CXX11)); + cxxUnresolvedConstructExpr(), Args, Lang_CXX11)); } TEST(UsingDecl, SourceRange) { @@ -434,11 +434,11 @@ TEST(FriendDecl, FriendConstructorDestructorLocation) { LocationVerifier<FriendDecl> ConstructorVerifier; ConstructorVerifier.expectLocation(6, 11); EXPECT_TRUE(ConstructorVerifier.match( - Code, friendDecl(has(constructorDecl(ofClass(hasName("B"))))))); + Code, friendDecl(has(cxxConstructorDecl(ofClass(hasName("B"))))))); LocationVerifier<FriendDecl> DestructorVerifier; DestructorVerifier.expectLocation(6, 19); EXPECT_TRUE(DestructorVerifier.match( - Code, friendDecl(has(destructorDecl(ofClass(hasName("B"))))))); + Code, friendDecl(has(cxxDestructorDecl(ofClass(hasName("B"))))))); } TEST(FriendDecl, FriendConstructorDestructorRange) { @@ -452,11 +452,11 @@ TEST(FriendDecl, FriendConstructorDestructorRange) { RangeVerifier<FriendDecl> ConstructorVerifier; ConstructorVerifier.expectRange(6, 1, 6, 13); EXPECT_TRUE(ConstructorVerifier.match( - Code, friendDecl(has(constructorDecl(ofClass(hasName("B"))))))); + Code, friendDecl(has(cxxConstructorDecl(ofClass(hasName("B"))))))); RangeVerifier<FriendDecl> DestructorVerifier; DestructorVerifier.expectRange(6, 1, 6, 22); EXPECT_TRUE(DestructorVerifier.match( - Code, friendDecl(has(destructorDecl(ofClass(hasName("B"))))))); + Code, friendDecl(has(cxxDestructorDecl(ofClass(hasName("B"))))))); } TEST(FriendDecl, FriendTemplateFunctionLocation) { @@ -527,7 +527,7 @@ TEST(FriendDecl, InstantiationSourceRange) { " friend void operator+<>(S<T> src);\n" "};\n" "void test(S<double> s) { +s; }", - friendDecl(hasParent(recordDecl(isTemplateInstantiation()))))); + friendDecl(hasParent(cxxRecordDecl(isTemplateInstantiation()))))); } TEST(ObjCMessageExpr, CXXConstructExprRange) { @@ -539,7 +539,7 @@ TEST(ObjCMessageExpr, CXXConstructExprRange) { "+ (void) f1: (A)arg;\n" "@end\n" "void f2() { A a; [B f1: (a)]; }\n", - constructExpr(), Lang_OBJCXX)); + cxxConstructExpr(), Lang_OBJCXX)); } } // end namespace ast_matchers diff --git a/unittests/AST/StmtPrinterTest.cpp b/unittests/AST/StmtPrinterTest.cpp index b1fd2c1eb42c1..bc7fd54e4ad96 100644 --- a/unittests/AST/StmtPrinterTest.cpp +++ b/unittests/AST/StmtPrinterTest.cpp @@ -196,7 +196,7 @@ TEST(StmtPrinter, TestCXXConversionDeclImplicit) { "void foo(A a, A b) {" " bar(a & b);" "}", - memberCallExpr(anything()).bind("id"), + cxxMemberCallExpr(anything()).bind("id"), "a & b")); } @@ -210,7 +210,7 @@ TEST(StmtPrinter, TestCXXConversionDeclExplicit) { "void foo(A a, A b) {" " auto x = (a & b).operator void *();" "}", - memberCallExpr(anything()).bind("id"), + cxxMemberCallExpr(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 8ef3f15e4c086..cd18df8410b73 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -36,7 +36,7 @@ TEST(HasNameDeathTest, DiesOnEmptyPattern) { TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) { ASSERT_DEBUG_DEATH({ - DeclarationMatcher IsDerivedFromEmpty = recordDecl(isDerivedFrom("")); + DeclarationMatcher IsDerivedFromEmpty = cxxRecordDecl(isDerivedFrom("")); EXPECT_TRUE(notMatches("class X {};", IsDerivedFromEmpty)); }, ""); } @@ -122,7 +122,7 @@ TEST(DeclarationMatcher, MatchClass) { } TEST(DeclarationMatcher, ClassIsDerived) { - DeclarationMatcher IsDerivedFromX = recordDecl(isDerivedFrom("X")); + DeclarationMatcher IsDerivedFromX = cxxRecordDecl(isDerivedFrom("X")); EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsDerivedFromX)); EXPECT_TRUE(notMatches("class X {};", IsDerivedFromX)); @@ -130,7 +130,7 @@ TEST(DeclarationMatcher, ClassIsDerived) { EXPECT_TRUE(notMatches("class Y;", IsDerivedFromX)); EXPECT_TRUE(notMatches("", IsDerivedFromX)); - DeclarationMatcher IsAX = recordDecl(isSameOrDerivedFrom("X")); + DeclarationMatcher IsAX = cxxRecordDecl(isSameOrDerivedFrom("X")); EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsAX)); EXPECT_TRUE(matches("class X {};", IsAX)); @@ -139,7 +139,7 @@ TEST(DeclarationMatcher, ClassIsDerived) { EXPECT_TRUE(notMatches("", IsAX)); DeclarationMatcher ZIsDerivedFromX = - recordDecl(hasName("Z"), isDerivedFrom("X")); + cxxRecordDecl(hasName("Z"), isDerivedFrom("X")); EXPECT_TRUE( matches("class X {}; class Y : public X {}; class Z : public Y {};", ZIsDerivedFromX)); @@ -258,14 +258,14 @@ TEST(DeclarationMatcher, ClassIsDerived) { EXPECT_TRUE( notMatches("template<int> struct X;" "template<int i> struct X : public X<i-1> {};", - recordDecl(isDerivedFrom(recordDecl(hasName("Some")))))); + cxxRecordDecl(isDerivedFrom(recordDecl(hasName("Some")))))); EXPECT_TRUE(matches( "struct A {};" "template<int> struct X;" "template<int i> struct X : public X<i-1> {};" "template<> struct X<0> : public A {};" "struct B : public X<42> {};", - recordDecl(hasName("B"), isDerivedFrom(recordDecl(hasName("A")))))); + cxxRecordDecl(hasName("B"), isDerivedFrom(recordDecl(hasName("A")))))); // FIXME: Once we have better matchers for template type matching, // get rid of the Variable(...) matching and match the right template @@ -282,15 +282,15 @@ TEST(DeclarationMatcher, ClassIsDerived) { EXPECT_TRUE(matches( RecursiveTemplateOneParameter, varDecl(hasName("z_float"), - hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"))))))); + hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1"))))))); EXPECT_TRUE(notMatches( RecursiveTemplateOneParameter, varDecl(hasName("z_float"), - hasInitializer(hasType(recordDecl(isDerivedFrom("Base2"))))))); + hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base2"))))))); EXPECT_TRUE(matches( RecursiveTemplateOneParameter, varDecl(hasName("z_char"), - hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"), + hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1"), isDerivedFrom("Base2"))))))); const char *RecursiveTemplateTwoParameters = @@ -307,39 +307,39 @@ TEST(DeclarationMatcher, ClassIsDerived) { EXPECT_TRUE(matches( RecursiveTemplateTwoParameters, varDecl(hasName("z_float"), - hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"))))))); + hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1"))))))); EXPECT_TRUE(notMatches( RecursiveTemplateTwoParameters, varDecl(hasName("z_float"), - hasInitializer(hasType(recordDecl(isDerivedFrom("Base2"))))))); + hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base2"))))))); EXPECT_TRUE(matches( RecursiveTemplateTwoParameters, varDecl(hasName("z_char"), - hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"), + hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1"), isDerivedFrom("Base2"))))))); EXPECT_TRUE(matches( "namespace ns { class X {}; class Y : public X {}; }", - recordDecl(isDerivedFrom("::ns::X")))); + cxxRecordDecl(isDerivedFrom("::ns::X")))); EXPECT_TRUE(notMatches( "class X {}; class Y : public X {};", - recordDecl(isDerivedFrom("::ns::X")))); + cxxRecordDecl(isDerivedFrom("::ns::X")))); EXPECT_TRUE(matches( "class X {}; class Y : public X {};", - recordDecl(isDerivedFrom(recordDecl(hasName("X")).bind("test"))))); + cxxRecordDecl(isDerivedFrom(recordDecl(hasName("X")).bind("test"))))); EXPECT_TRUE(matches( "template<typename T> class X {};" "template<typename T> using Z = X<T>;" "template <typename T> class Y : Z<T> {};", - recordDecl(isDerivedFrom(namedDecl(hasName("X")))))); + cxxRecordDecl(isDerivedFrom(namedDecl(hasName("X")))))); } TEST(DeclarationMatcher, hasMethod) { EXPECT_TRUE(matches("class A { void func(); };", - recordDecl(hasMethod(hasName("func"))))); + cxxRecordDecl(hasMethod(hasName("func"))))); EXPECT_TRUE(notMatches("class A { void func(); };", - recordDecl(hasMethod(isPublic())))); + cxxRecordDecl(hasMethod(isPublic())))); } TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) { @@ -349,7 +349,7 @@ TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) { "};" "template <typename T> struct B : A<T>::template F<T> {};" "B<int> b;", - recordDecl(hasName("B"), isDerivedFrom(recordDecl())))); + cxxRecordDecl(hasName("B"), isDerivedFrom(recordDecl())))); } TEST(DeclarationMatcher, hasDeclContext) { @@ -453,11 +453,20 @@ TEST(AllOf, AllOverloadsWork) { hasArgument(3, integerLiteral(equals(4))))))); } -TEST(DeclarationMatcher, MatchAnyOf) { - DeclarationMatcher YOrZDerivedFromX = - recordDecl(anyOf(hasName("Y"), allOf(isDerivedFrom("X"), hasName("Z")))); +TEST(ConstructVariadic, MismatchedTypes_Regression) { EXPECT_TRUE( - matches("class X {}; class Z : public X {};", YOrZDerivedFromX)); + matches("const int a = 0;", + internal::DynTypedMatcher::constructVariadic( + internal::DynTypedMatcher::VO_AnyOf, + ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>(), + {isConstQualified(), arrayType()}) + .convertTo<QualType>())); +} + +TEST(DeclarationMatcher, MatchAnyOf) { + DeclarationMatcher YOrZDerivedFromX = cxxRecordDecl( + anyOf(hasName("Y"), allOf(isDerivedFrom("X"), hasName("Z")))); + EXPECT_TRUE(matches("class X {}; class Z : public X {};", YOrZDerivedFromX)); EXPECT_TRUE(matches("class Y {};", YOrZDerivedFromX)); EXPECT_TRUE( notMatches("class X {}; class W : public X {};", YOrZDerivedFromX)); @@ -485,7 +494,7 @@ TEST(DeclarationMatcher, MatchAnyOf) { EXPECT_TRUE( matches("void f() try { } catch (int) { } catch (...) { }", - catchStmt(anyOf(hasDescendant(varDecl()), isCatchAll())))); + cxxCatchStmt(anyOf(hasDescendant(varDecl()), isCatchAll())))); } TEST(DeclarationMatcher, MatchHas) { @@ -592,7 +601,7 @@ TEST(DeclarationMatcher, MatchHasRecursiveAnyOf) { TEST(DeclarationMatcher, MatchNot) { DeclarationMatcher NotClassX = - recordDecl( + cxxRecordDecl( isDerivedFrom("Y"), unless(hasName("X"))); EXPECT_TRUE(notMatches("", NotClassX)); @@ -709,11 +718,11 @@ TEST(DeclarationMatcher, HasAttr) { TEST(DeclarationMatcher, MatchCudaDecl) { EXPECT_TRUE(matchesWithCuda("__global__ void f() { }" "void g() { f<<<1, 2>>>(); }", - CUDAKernelCallExpr())); + cudaKernelCallExpr())); EXPECT_TRUE(matchesWithCuda("__attribute__((device)) void f() {}", hasAttr(clang::attr::CUDADevice))); EXPECT_TRUE(notMatchesWithCuda("void f() {}", - CUDAKernelCallExpr())); + cudaKernelCallExpr())); EXPECT_FALSE(notMatchesWithCuda("__attribute__((global)) void f() {}", hasAttr(clang::attr::CUDAGlobal))); } @@ -898,7 +907,8 @@ TEST(TypeMatcher, MatchesClassType) { EXPECT_TRUE(matches("class A { public: A *a; };", TypeA)); EXPECT_TRUE(notMatches("class A {};", TypeA)); - TypeMatcher TypeDerivedFromA = hasDeclaration(recordDecl(isDerivedFrom("A"))); + TypeMatcher TypeDerivedFromA = + hasDeclaration(cxxRecordDecl(isDerivedFrom("A"))); EXPECT_TRUE(matches("class A {}; class B : public A { public: B *b; };", TypeDerivedFromA)); @@ -909,6 +919,57 @@ TEST(TypeMatcher, MatchesClassType) { EXPECT_TRUE( matches("class A { public: A *a; class B {}; };", TypeAHasClassB)); + + EXPECT_TRUE(matchesC("struct S {}; void f(void) { struct S s; }", + varDecl(hasType(namedDecl(hasName("S")))))); +} + +TEST(TypeMatcher, MatchesDeclTypes) { + // TypedefType -> TypedefNameDecl + EXPECT_TRUE(matches("typedef int I; void f(I i);", + parmVarDecl(hasType(namedDecl(hasName("I")))))); + // ObjCObjectPointerType + EXPECT_TRUE(matchesObjC("@interface Foo @end void f(Foo *f);", + parmVarDecl(hasType(objcObjectPointerType())))); + // ObjCObjectPointerType -> ObjCInterfaceType -> ObjCInterfaceDecl + EXPECT_TRUE(matchesObjC( + "@interface Foo @end void f(Foo *f);", + parmVarDecl(hasType(pointsTo(objcInterfaceDecl(hasName("Foo"))))))); + // TemplateTypeParmType + EXPECT_TRUE(matches("template <typename T> void f(T t);", + parmVarDecl(hasType(templateTypeParmType())))); + // TemplateTypeParmType -> TemplateTypeParmDecl + EXPECT_TRUE(matches("template <typename T> void f(T t);", + parmVarDecl(hasType(namedDecl(hasName("T")))))); + // InjectedClassNameType + EXPECT_TRUE(matches("template <typename T> struct S {" + " void f(S s);" + "};", + parmVarDecl(hasType(injectedClassNameType())))); + EXPECT_TRUE(notMatches("template <typename T> struct S {" + " void g(S<T> s);" + "};", + parmVarDecl(hasType(injectedClassNameType())))); + // InjectedClassNameType -> CXXRecordDecl + EXPECT_TRUE(matches("template <typename T> struct S {" + " void f(S s);" + "};", + parmVarDecl(hasType(namedDecl(hasName("S")))))); + + static const char Using[] = "template <typename T>" + "struct Base {" + " typedef T Foo;" + "};" + "" + "template <typename T>" + "struct S : private Base<T> {" + " using typename Base<T>::Foo;" + " void f(Foo);" + "};"; + // UnresolvedUsingTypenameDecl + EXPECT_TRUE(matches(Using, unresolvedUsingTypenameDecl(hasName("Foo")))); + // UnresolvedUsingTypenameType -> UnresolvedUsingTypenameDecl + EXPECT_TRUE(matches(Using, parmVarDecl(hasType(namedDecl(hasName("Foo")))))); } TEST(Matcher, BindMatchedNodes) { @@ -928,7 +989,7 @@ TEST(Matcher, BindMatchedNodes) { new VerifyIdIsBoundTo<Decl>("b"))); StatementMatcher MethodX = - callExpr(callee(methodDecl(hasName("x")))).bind("x"); + callExpr(callee(cxxMethodDecl(hasName("x")))).bind("x"); EXPECT_TRUE(matchAndVerifyResultTrue("class A { void x() { x(); } };", MethodX, @@ -1042,13 +1103,14 @@ TEST(HasTypeLoc, MatchesDeclaratorDecls) { TEST(Matcher, Call) { // FIXME: Do we want to overload Call() to directly take // Matcher<Decl>, too? - StatementMatcher MethodX = callExpr(hasDeclaration(methodDecl(hasName("x")))); + StatementMatcher MethodX = + callExpr(hasDeclaration(cxxMethodDecl(hasName("x")))); EXPECT_TRUE(matches("class Y { void x() { x(); } };", MethodX)); EXPECT_TRUE(notMatches("class Y { void x() {} };", MethodX)); StatementMatcher MethodOnY = - memberCallExpr(on(hasType(recordDecl(hasName("Y"))))); + cxxMemberCallExpr(on(hasType(recordDecl(hasName("Y"))))); EXPECT_TRUE( matches("class Y { public: void x(); }; void z() { Y y; y.x(); }", @@ -1067,7 +1129,7 @@ TEST(Matcher, Call) { MethodOnY)); StatementMatcher MethodOnYPointer = - memberCallExpr(on(hasType(pointsTo(recordDecl(hasName("Y")))))); + cxxMemberCallExpr(on(hasType(pointsTo(recordDecl(hasName("Y")))))); EXPECT_TRUE( matches("class Y { public: void x(); }; void z() { Y *y; y->x(); }", @@ -1094,9 +1156,9 @@ TEST(Matcher, Lambda) { TEST(Matcher, ForRange) { EXPECT_TRUE(matches("int as[] = { 1, 2, 3 };" "void f() { for (auto &a : as); }", - forRangeStmt())); + cxxForRangeStmt())); EXPECT_TRUE(notMatches("void f() { for (int i; i<5; ++i); }", - forRangeStmt())); + cxxForRangeStmt())); } TEST(Matcher, SubstNonTypeTemplateParm) { @@ -1110,6 +1172,20 @@ TEST(Matcher, SubstNonTypeTemplateParm) { substNonTypeTemplateParmExpr())); } +TEST(Matcher, NonTypeTemplateParmDecl) { + EXPECT_TRUE(matches("template <int N> void f();", + nonTypeTemplateParmDecl(hasName("N")))); + EXPECT_TRUE( + notMatches("template <typename T> void f();", nonTypeTemplateParmDecl())); +} + +TEST(Matcher, templateTypeParmDecl) { + EXPECT_TRUE(matches("template <typename T> void f();", + templateTypeParmDecl(hasName("T")))); + EXPECT_TRUE( + notMatches("template <int N> void f();", templateTypeParmDecl())); +} + TEST(Matcher, UserDefinedLiteral) { EXPECT_TRUE(matches("constexpr char operator \"\" _inc (const char i) {" " return i + 1;" @@ -1130,9 +1206,10 @@ TEST(Matcher, FlowControl) { TEST(HasType, MatchesAsString) { EXPECT_TRUE( matches("class Y { public: void x(); }; void z() {Y* y; y->x(); }", - memberCallExpr(on(hasType(asString("class Y *")))))); - EXPECT_TRUE(matches("class X { void x(int x) {} };", - methodDecl(hasParameter(0, hasType(asString("int")))))); + cxxMemberCallExpr(on(hasType(asString("class Y *")))))); + EXPECT_TRUE( + matches("class X { void x(int x) {} };", + cxxMethodDecl(hasParameter(0, hasType(asString("int")))))); 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; };", @@ -1140,7 +1217,7 @@ TEST(HasType, MatchesAsString) { } TEST(Matcher, OverloadedOperatorCall) { - StatementMatcher OpCall = operatorCallExpr(); + StatementMatcher OpCall = cxxOperatorCallExpr(); // Unary operator EXPECT_TRUE(matches("class Y { }; " "bool operator!(Y x) { return false; }; " @@ -1167,22 +1244,22 @@ TEST(Matcher, OverloadedOperatorCall) { TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) { StatementMatcher OpCallAndAnd = - operatorCallExpr(hasOverloadedOperatorName("&&")); + cxxOperatorCallExpr(hasOverloadedOperatorName("&&")); EXPECT_TRUE(matches("class Y { }; " "bool operator&&(Y x, Y y) { return true; }; " "Y a; Y b; bool c = a && b;", OpCallAndAnd)); StatementMatcher OpCallLessLess = - operatorCallExpr(hasOverloadedOperatorName("<<")); + cxxOperatorCallExpr(hasOverloadedOperatorName("<<")); EXPECT_TRUE(notMatches("class Y { }; " "bool operator&&(Y x, Y y) { return true; }; " "Y a; Y b; bool c = a && b;", OpCallLessLess)); StatementMatcher OpStarCall = - operatorCallExpr(hasOverloadedOperatorName("*")); + cxxOperatorCallExpr(hasOverloadedOperatorName("*")); EXPECT_TRUE(matches("class Y; int operator*(Y &); void f(Y &y) { *y; }", OpStarCall)); DeclarationMatcher ClassWithOpStar = - recordDecl(hasMethod(hasOverloadedOperatorName("*"))); + cxxRecordDecl(hasMethod(hasOverloadedOperatorName("*"))); EXPECT_TRUE(matches("class Y { int operator*(); };", ClassWithOpStar)); EXPECT_TRUE(notMatches("class Y { void myOperator(); };", @@ -1194,26 +1271,25 @@ TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) { TEST(Matcher, NestedOverloadedOperatorCalls) { EXPECT_TRUE(matchAndVerifyResultTrue( - "class Y { }; " - "Y& operator&&(Y& x, Y& y) { return x; }; " - "Y a; Y b; Y c; Y d = a && b && c;", - operatorCallExpr(hasOverloadedOperatorName("&&")).bind("x"), - new VerifyIdIsBoundTo<CXXOperatorCallExpr>("x", 2))); - EXPECT_TRUE(matches( - "class Y { }; " - "Y& operator&&(Y& x, Y& y) { return x; }; " - "Y a; Y b; Y c; Y d = a && b && c;", - operatorCallExpr(hasParent(operatorCallExpr())))); - EXPECT_TRUE(matches( - "class Y { }; " - "Y& operator&&(Y& x, Y& y) { return x; }; " - "Y a; Y b; Y c; Y d = a && b && c;", - operatorCallExpr(hasDescendant(operatorCallExpr())))); + "class Y { }; " + "Y& operator&&(Y& x, Y& y) { return x; }; " + "Y a; Y b; Y c; Y d = a && b && c;", + cxxOperatorCallExpr(hasOverloadedOperatorName("&&")).bind("x"), + new VerifyIdIsBoundTo<CXXOperatorCallExpr>("x", 2))); + EXPECT_TRUE(matches("class Y { }; " + "Y& operator&&(Y& x, Y& y) { return x; }; " + "Y a; Y b; Y c; Y d = a && b && c;", + cxxOperatorCallExpr(hasParent(cxxOperatorCallExpr())))); + EXPECT_TRUE( + matches("class Y { }; " + "Y& operator&&(Y& x, Y& y) { return x; }; " + "Y a; Y b; Y c; Y d = a && b && c;", + cxxOperatorCallExpr(hasDescendant(cxxOperatorCallExpr())))); } TEST(Matcher, ThisPointerType) { StatementMatcher MethodOnY = - memberCallExpr(thisPointerType(recordDecl(hasName("Y")))); + cxxMemberCallExpr(thisPointerType(recordDecl(hasName("Y")))); EXPECT_TRUE( matches("class Y { public: void x(); }; void z() { Y y; y.x(); }", @@ -1245,7 +1321,7 @@ TEST(Matcher, VariableUsage) { StatementMatcher Reference = declRefExpr(to( varDecl(hasInitializer( - memberCallExpr(thisPointerType(recordDecl(hasName("Y")))))))); + cxxMemberCallExpr(thisPointerType(recordDecl(hasName("Y")))))))); EXPECT_TRUE(matches( "class Y {" @@ -1279,6 +1355,29 @@ TEST(Matcher, VarDecl_Storage) { EXPECT_TRUE(matches("void f() { static int X; }", M)); } +TEST(Matcher, VarDecl_StorageDuration) { + std::string T = + "void f() { int x; static int y; } int a;"; + + EXPECT_TRUE(matches(T, varDecl(hasName("x"), hasAutomaticStorageDuration()))); + EXPECT_TRUE( + notMatches(T, varDecl(hasName("y"), hasAutomaticStorageDuration()))); + EXPECT_TRUE( + notMatches(T, varDecl(hasName("a"), hasAutomaticStorageDuration()))); + + EXPECT_TRUE(matches(T, varDecl(hasName("y"), hasStaticStorageDuration()))); + EXPECT_TRUE(matches(T, varDecl(hasName("a"), hasStaticStorageDuration()))); + EXPECT_TRUE(notMatches(T, varDecl(hasName("x"), hasStaticStorageDuration()))); + + // FIXME: It is really hard to test with thread_local itself because not all + // targets support TLS, which causes this to be an error depending on what + // platform the test is being run on. We do not have access to the TargetInfo + // object to be able to test whether the platform supports TLS or not. + EXPECT_TRUE(notMatches(T, varDecl(hasName("x"), hasThreadStorageDuration()))); + EXPECT_TRUE(notMatches(T, varDecl(hasName("y"), hasThreadStorageDuration()))); + EXPECT_TRUE(notMatches(T, varDecl(hasName("a"), hasThreadStorageDuration()))); +} + TEST(Matcher, FindsVarDeclInFunctionParameter) { EXPECT_TRUE(matches( "void f(int i) {}", @@ -1287,7 +1386,7 @@ TEST(Matcher, FindsVarDeclInFunctionParameter) { TEST(Matcher, CalledVariable) { StatementMatcher CallOnVariableY = - memberCallExpr(on(declRefExpr(to(varDecl(hasName("y")))))); + cxxMemberCallExpr(on(declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE(matches( "class Y { public: void x() { Y y; y.x(); } };", CallOnVariableY)); @@ -1370,6 +1469,14 @@ TEST(IsInteger, ReportsNoFalsePositives) { to(varDecl(hasType(isInteger())))))))); } +TEST(IsAnyCharacter, MatchesCharacters) { + EXPECT_TRUE(matches("char i = 0;", varDecl(hasType(isAnyCharacter())))); +} + +TEST(IsAnyCharacter, ReportsNoFalsePositives) { + EXPECT_TRUE(notMatches("int i;", varDecl(hasType(isAnyCharacter())))); +} + TEST(IsArrow, MatchesMemberVariablesViaArrow) { EXPECT_TRUE(matches("class Y { void x() { this->y; } int y; };", memberExpr(isArrow()))); @@ -1398,18 +1505,25 @@ TEST(IsArrow, MatchesMemberCallsViaArrow) { } TEST(Callee, MatchesDeclarations) { - StatementMatcher CallMethodX = callExpr(callee(methodDecl(hasName("x")))); + StatementMatcher CallMethodX = callExpr(callee(cxxMethodDecl(hasName("x")))); EXPECT_TRUE(matches("class Y { void x() { x(); } };", CallMethodX)); EXPECT_TRUE(notMatches("class Y { void x() {} };", CallMethodX)); - CallMethodX = callExpr(callee(conversionDecl())); + CallMethodX = callExpr(callee(cxxConversionDecl())); EXPECT_TRUE( matches("struct Y { operator int() const; }; int i = Y();", CallMethodX)); EXPECT_TRUE(notMatches("struct Y { operator int() const; }; Y y = Y();", CallMethodX)); } +TEST(ConversionDeclaration, IsExplicit) { + EXPECT_TRUE(matches("struct S { explicit operator int(); };", + cxxConversionDecl(isExplicit()))); + EXPECT_TRUE(notMatches("struct S { operator int(); };", + cxxConversionDecl(isExplicit()))); +} + TEST(Callee, MatchesMemberExpressions) { EXPECT_TRUE(matches("class Y { void x() { this->x(); } };", callExpr(callee(memberExpr())))); @@ -1442,6 +1556,13 @@ TEST(Function, MatchesFunctionDeclarations) { notMatches("void f(int);" "template <typename T> struct S { void g(T t) { f(t); } };", CallFunctionF)); + + EXPECT_TRUE(matches("void f(...);", functionDecl(isVariadic()))); + EXPECT_TRUE(notMatches("void f(int);", functionDecl(isVariadic()))); + EXPECT_TRUE(notMatches("template <typename... Ts> void f(Ts...);", + functionDecl(isVariadic()))); + EXPECT_TRUE(notMatches("void f();", functionDecl(isVariadic()))); + EXPECT_TRUE(notMatchesC("void f();", functionDecl(isVariadic()))); } TEST(FunctionTemplate, MatchesFunctionTemplateDeclarations) { @@ -1545,34 +1666,38 @@ TEST(QualType, hasLocalQualifiers) { TEST(HasParameter, CallsInnerMatcher) { EXPECT_TRUE(matches("class X { void x(int) {} };", - methodDecl(hasParameter(0, varDecl())))); + cxxMethodDecl(hasParameter(0, varDecl())))); EXPECT_TRUE(notMatches("class X { void x(int) {} };", - methodDecl(hasParameter(0, hasName("x"))))); + cxxMethodDecl(hasParameter(0, hasName("x"))))); } TEST(HasParameter, DoesNotMatchIfIndexOutOfBounds) { EXPECT_TRUE(notMatches("class X { void x(int) {} };", - methodDecl(hasParameter(42, varDecl())))); + cxxMethodDecl(hasParameter(42, varDecl())))); } TEST(HasType, MatchesParameterVariableTypesStrictly) { - EXPECT_TRUE(matches("class X { void x(X x) {} };", - methodDecl(hasParameter(0, hasType(recordDecl(hasName("X"))))))); - EXPECT_TRUE(notMatches("class X { void x(const X &x) {} };", - methodDecl(hasParameter(0, hasType(recordDecl(hasName("X"))))))); + EXPECT_TRUE(matches( + "class X { void x(X x) {} };", + cxxMethodDecl(hasParameter(0, hasType(recordDecl(hasName("X"))))))); + EXPECT_TRUE(notMatches( + "class X { void x(const X &x) {} };", + cxxMethodDecl(hasParameter(0, hasType(recordDecl(hasName("X"))))))); EXPECT_TRUE(matches("class X { void x(const X *x) {} };", - methodDecl(hasParameter(0, - hasType(pointsTo(recordDecl(hasName("X")))))))); + cxxMethodDecl(hasParameter( + 0, hasType(pointsTo(recordDecl(hasName("X")))))))); EXPECT_TRUE(matches("class X { void x(const X &x) {} };", - methodDecl(hasParameter(0, - hasType(references(recordDecl(hasName("X")))))))); + cxxMethodDecl(hasParameter( + 0, hasType(references(recordDecl(hasName("X")))))))); } TEST(HasAnyParameter, MatchesIndependentlyOfPosition) { - EXPECT_TRUE(matches("class Y {}; class X { void x(X x, Y y) {} };", - methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); - EXPECT_TRUE(matches("class Y {}; class X { void x(Y y, X x) {} };", - methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); + EXPECT_TRUE(matches( + "class Y {}; class X { void x(X x, Y y) {} };", + cxxMethodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); + EXPECT_TRUE(matches( + "class Y {}; class X { void x(Y y, X x) {} };", + cxxMethodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); } TEST(Returns, MatchesReturnTypes) { @@ -1599,6 +1724,15 @@ TEST(IsDeleted, MatchesDeletedFunctionDeclarations) { functionDecl(hasName("Func"), isDeleted()))); } +TEST(IsNoThrow, MatchesNoThrowFunctionDeclarations) { + EXPECT_TRUE(notMatches("void f();", functionDecl(isNoThrow()))); + EXPECT_TRUE(notMatches("void f() throw(int);", functionDecl(isNoThrow()))); + EXPECT_TRUE( + notMatches("void f() noexcept(false);", functionDecl(isNoThrow()))); + EXPECT_TRUE(matches("void f() throw();", functionDecl(isNoThrow()))); + EXPECT_TRUE(matches("void f() noexcept;", functionDecl(isNoThrow()))); +} + TEST(isConstexpr, MatchesConstexprDeclarations) { EXPECT_TRUE(matches("constexpr int foo = 42;", varDecl(hasName("foo"), isConstexpr()))); @@ -1607,21 +1741,22 @@ TEST(isConstexpr, MatchesConstexprDeclarations) { } TEST(HasAnyParameter, DoesntMatchIfInnerMatcherDoesntMatch) { - EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };", - methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); + EXPECT_TRUE(notMatches( + "class Y {}; class X { void x(int) {} };", + cxxMethodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); } TEST(HasAnyParameter, DoesNotMatchThisPointer) { EXPECT_TRUE(notMatches("class Y {}; class X { void x() {} };", - methodDecl(hasAnyParameter(hasType(pointsTo( - recordDecl(hasName("X")))))))); + cxxMethodDecl(hasAnyParameter( + hasType(pointsTo(recordDecl(hasName("X")))))))); } TEST(HasName, MatchesParameterVariableDeclarations) { EXPECT_TRUE(matches("class Y {}; class X { void x(int x) {} };", - methodDecl(hasAnyParameter(hasName("x"))))); + cxxMethodDecl(hasAnyParameter(hasName("x"))))); EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };", - methodDecl(hasAnyParameter(hasName("x"))))); + cxxMethodDecl(hasAnyParameter(hasName("x"))))); } TEST(Matcher, MatchesClassTemplateSpecialization) { @@ -1774,46 +1909,68 @@ TEST(Matcher, MatchesAccessSpecDecls) { EXPECT_TRUE(notMatches("class C { int i; };", accessSpecDecl())); } +TEST(Matcher, MatchesFinal) { + EXPECT_TRUE(matches("class X final {};", cxxRecordDecl(isFinal()))); + EXPECT_TRUE(matches("class X { virtual void f() final; };", + cxxMethodDecl(isFinal()))); + EXPECT_TRUE(notMatches("class X {};", cxxRecordDecl(isFinal()))); + EXPECT_TRUE( + notMatches("class X { virtual void f(); };", cxxMethodDecl(isFinal()))); +} + TEST(Matcher, MatchesVirtualMethod) { EXPECT_TRUE(matches("class X { virtual int f(); };", - methodDecl(isVirtual(), hasName("::X::f")))); - EXPECT_TRUE(notMatches("class X { int f(); };", - methodDecl(isVirtual()))); + cxxMethodDecl(isVirtual(), hasName("::X::f")))); + EXPECT_TRUE(notMatches("class X { int f(); };", cxxMethodDecl(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()))); + cxxMethodDecl(isPure(), hasName("::X::f")))); + EXPECT_TRUE(notMatches("class X { int f(); };", cxxMethodDecl(isPure()))); +} + +TEST(Matcher, MatchesCopyAssignmentOperator) { + EXPECT_TRUE(matches("class X { X &operator=(X); };", + cxxMethodDecl(isCopyAssignmentOperator()))); + EXPECT_TRUE(matches("class X { X &operator=(X &); };", + cxxMethodDecl(isCopyAssignmentOperator()))); + EXPECT_TRUE(matches("class X { X &operator=(const X &); };", + cxxMethodDecl(isCopyAssignmentOperator()))); + EXPECT_TRUE(matches("class X { X &operator=(volatile X &); };", + cxxMethodDecl(isCopyAssignmentOperator()))); + EXPECT_TRUE(matches("class X { X &operator=(const volatile X &); };", + cxxMethodDecl(isCopyAssignmentOperator()))); + EXPECT_TRUE(notMatches("class X { X &operator=(X &&); };", + cxxMethodDecl(isCopyAssignmentOperator()))); } TEST(Matcher, MatchesConstMethod) { - EXPECT_TRUE(matches("struct A { void foo() const; };", - methodDecl(isConst()))); - EXPECT_TRUE(notMatches("struct A { void foo(); };", - methodDecl(isConst()))); + EXPECT_TRUE( + matches("struct A { void foo() const; };", cxxMethodDecl(isConst()))); + EXPECT_TRUE( + notMatches("struct A { void foo(); };", cxxMethodDecl(isConst()))); } TEST(Matcher, MatchesOverridingMethod) { EXPECT_TRUE(matches("class X { virtual int f(); }; " "class Y : public X { int f(); };", - methodDecl(isOverride(), hasName("::Y::f")))); + cxxMethodDecl(isOverride(), hasName("::Y::f")))); EXPECT_TRUE(notMatches("class X { virtual int f(); }; " - "class Y : public X { int f(); };", - methodDecl(isOverride(), hasName("::X::f")))); + "class Y : public X { int f(); };", + cxxMethodDecl(isOverride(), hasName("::X::f")))); EXPECT_TRUE(notMatches("class X { int f(); }; " "class Y : public X { int f(); };", - methodDecl(isOverride()))); + cxxMethodDecl(isOverride()))); EXPECT_TRUE(notMatches("class X { int f(); int f(int); }; ", - methodDecl(isOverride()))); + cxxMethodDecl(isOverride()))); EXPECT_TRUE( matches("template <typename Base> struct Y : Base { void f() override;};", - methodDecl(isOverride(), hasName("::Y::f")))); + cxxMethodDecl(isOverride(), hasName("::Y::f")))); } TEST(Matcher, ConstructorCall) { - StatementMatcher Constructor = constructExpr(); + StatementMatcher Constructor = cxxConstructExpr(); EXPECT_TRUE( matches("class X { public: X(); }; void x() { X x; }", Constructor)); @@ -1827,7 +1984,7 @@ TEST(Matcher, ConstructorCall) { } TEST(Matcher, ConstructorArgument) { - StatementMatcher Constructor = constructExpr( + StatementMatcher Constructor = cxxConstructExpr( hasArgument(0, declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE( @@ -1843,7 +2000,7 @@ TEST(Matcher, ConstructorArgument) { notMatches("class X { public: X(int); }; void x() { int z; X x(z); }", Constructor)); - StatementMatcher WrongIndex = constructExpr( + StatementMatcher WrongIndex = cxxConstructExpr( hasArgument(42, declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE( notMatches("class X { public: X(int); }; void x() { int y; X x(y); }", @@ -1851,7 +2008,7 @@ TEST(Matcher, ConstructorArgument) { } TEST(Matcher, ConstructorArgumentCount) { - StatementMatcher Constructor1Arg = constructExpr(argumentCountIs(1)); + StatementMatcher Constructor1Arg = cxxConstructExpr(argumentCountIs(1)); EXPECT_TRUE( matches("class X { public: X(int); }; void x() { X x(0); }", @@ -1868,7 +2025,8 @@ TEST(Matcher, ConstructorArgumentCount) { } TEST(Matcher, ConstructorListInitialization) { - StatementMatcher ConstructorListInit = constructExpr(isListInitialization()); + StatementMatcher ConstructorListInit = + cxxConstructExpr(isListInitialization()); EXPECT_TRUE( matches("class X { public: X(int); }; void x() { X x{0}; }", @@ -1880,13 +2038,13 @@ TEST(Matcher, ConstructorListInitialization) { TEST(Matcher,ThisExpr) { EXPECT_TRUE( - matches("struct X { int a; int f () { return a; } };", thisExpr())); + matches("struct X { int a; int f () { return a; } };", cxxThisExpr())); EXPECT_TRUE( - notMatches("struct X { int f () { int a; return a; } };", thisExpr())); + notMatches("struct X { int f () { int a; return a; } };", cxxThisExpr())); } TEST(Matcher, BindTemporaryExpression) { - StatementMatcher TempExpression = bindTemporaryExpr(); + StatementMatcher TempExpression = cxxBindTemporaryExpr(); std::string ClassString = "class string { public: string(); ~string(); }; "; @@ -1953,46 +2111,76 @@ TEST(MaterializeTemporaryExpr, MatchesTemporary) { TEST(ConstructorDeclaration, SimpleCase) { EXPECT_TRUE(matches("class Foo { Foo(int i); };", - constructorDecl(ofClass(hasName("Foo"))))); + cxxConstructorDecl(ofClass(hasName("Foo"))))); EXPECT_TRUE(notMatches("class Foo { Foo(int i); };", - constructorDecl(ofClass(hasName("Bar"))))); + cxxConstructorDecl(ofClass(hasName("Bar"))))); } TEST(ConstructorDeclaration, IsImplicit) { // This one doesn't match because the constructor is not added by the // compiler (it is not needed). EXPECT_TRUE(notMatches("class Foo { };", - constructorDecl(isImplicit()))); + cxxConstructorDecl(isImplicit()))); // The compiler added the implicit default constructor. EXPECT_TRUE(matches("class Foo { }; Foo* f = new Foo();", - constructorDecl(isImplicit()))); + cxxConstructorDecl(isImplicit()))); EXPECT_TRUE(matches("class Foo { Foo(){} };", - constructorDecl(unless(isImplicit())))); + cxxConstructorDecl(unless(isImplicit())))); // The compiler added an implicit assignment operator. EXPECT_TRUE(matches("struct A { int x; } a = {0}, b = a; void f() { a = b; }", - methodDecl(isImplicit(), hasName("operator=")))); + cxxMethodDecl(isImplicit(), hasName("operator=")))); +} + +TEST(ConstructorDeclaration, IsExplicit) { + EXPECT_TRUE(matches("struct S { explicit S(int); };", + cxxConstructorDecl(isExplicit()))); + EXPECT_TRUE(notMatches("struct S { S(int); };", + cxxConstructorDecl(isExplicit()))); +} + +TEST(ConstructorDeclaration, Kinds) { + EXPECT_TRUE(matches("struct S { S(); };", + cxxConstructorDecl(isDefaultConstructor()))); + EXPECT_TRUE(notMatches("struct S { S(); };", + cxxConstructorDecl(isCopyConstructor()))); + EXPECT_TRUE(notMatches("struct S { S(); };", + cxxConstructorDecl(isMoveConstructor()))); + + EXPECT_TRUE(notMatches("struct S { S(const S&); };", + cxxConstructorDecl(isDefaultConstructor()))); + EXPECT_TRUE(matches("struct S { S(const S&); };", + cxxConstructorDecl(isCopyConstructor()))); + EXPECT_TRUE(notMatches("struct S { S(const S&); };", + cxxConstructorDecl(isMoveConstructor()))); + + EXPECT_TRUE(notMatches("struct S { S(S&&); };", + cxxConstructorDecl(isDefaultConstructor()))); + EXPECT_TRUE(notMatches("struct S { S(S&&); };", + cxxConstructorDecl(isCopyConstructor()))); + EXPECT_TRUE(matches("struct S { S(S&&); };", + cxxConstructorDecl(isMoveConstructor()))); } TEST(DestructorDeclaration, MatchesVirtualDestructor) { EXPECT_TRUE(matches("class Foo { virtual ~Foo(); };", - destructorDecl(ofClass(hasName("Foo"))))); + cxxDestructorDecl(ofClass(hasName("Foo"))))); } TEST(DestructorDeclaration, DoesNotMatchImplicitDestructor) { EXPECT_TRUE(notMatches("class Foo {};", - destructorDecl(ofClass(hasName("Foo"))))); + cxxDestructorDecl(ofClass(hasName("Foo"))))); } TEST(HasAnyConstructorInitializer, SimpleCase) { - EXPECT_TRUE(notMatches( - "class Foo { Foo() { } };", - constructorDecl(hasAnyConstructorInitializer(anything())))); - EXPECT_TRUE(matches( - "class Foo {" - " Foo() : foo_() { }" - " int foo_;" - "};", - constructorDecl(hasAnyConstructorInitializer(anything())))); + EXPECT_TRUE( + notMatches("class Foo { Foo() { } };", + cxxConstructorDecl(hasAnyConstructorInitializer(anything())))); + EXPECT_TRUE( + matches("class Foo {" + " Foo() : foo_() { }" + " int foo_;" + "};", + cxxConstructorDecl(hasAnyConstructorInitializer(anything())))); } TEST(HasAnyConstructorInitializer, ForField) { @@ -2003,11 +2191,11 @@ TEST(HasAnyConstructorInitializer, ForField) { " Baz foo_;" " Baz bar_;" "};"; - EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( forField(hasType(recordDecl(hasName("Baz")))))))); - EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( forField(hasName("foo_")))))); - EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( forField(hasType(recordDecl(hasName("Bar")))))))); } @@ -2017,9 +2205,9 @@ TEST(HasAnyConstructorInitializer, WithInitializer) { " Foo() : foo_(0) { }" " int foo_;" "};"; - EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( withInitializer(integerLiteral(equals(0))))))); - EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( withInitializer(integerLiteral(equals(1))))))); } @@ -2031,16 +2219,40 @@ TEST(HasAnyConstructorInitializer, IsWritten) { " Bar foo_;" " Bar bar_;" "};"; - EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( allOf(forField(hasName("foo_")), isWritten()))))); - EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( allOf(forField(hasName("bar_")), isWritten()))))); - EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer( + EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( allOf(forField(hasName("bar_")), unless(isWritten())))))); } +TEST(HasAnyConstructorInitializer, IsBaseInitializer) { + static const char Code[] = + "struct B {};" + "struct D : B {" + " int I;" + " D(int i) : I(i) {}" + "};" + "struct E : B {" + " E() : B() {}" + "};"; + EXPECT_TRUE(matches(Code, cxxConstructorDecl(allOf( + hasAnyConstructorInitializer(allOf(isBaseInitializer(), isWritten())), + hasName("E"))))); + EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(allOf( + hasAnyConstructorInitializer(allOf(isBaseInitializer(), isWritten())), + hasName("D"))))); + EXPECT_TRUE(matches(Code, cxxConstructorDecl(allOf( + hasAnyConstructorInitializer(allOf(isMemberInitializer(), isWritten())), + hasName("D"))))); + EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(allOf( + hasAnyConstructorInitializer(allOf(isMemberInitializer(), isWritten())), + hasName("E"))))); +} + TEST(Matcher, NewExpression) { - StatementMatcher New = newExpr(); + StatementMatcher New = cxxNewExpr(); EXPECT_TRUE(matches("class X { public: X(); }; void x() { new X; }", New)); EXPECT_TRUE( @@ -2051,7 +2263,7 @@ TEST(Matcher, NewExpression) { } TEST(Matcher, NewExpressionArgument) { - StatementMatcher New = constructExpr( + StatementMatcher New = cxxConstructExpr( hasArgument(0, declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE( @@ -2064,7 +2276,7 @@ TEST(Matcher, NewExpressionArgument) { notMatches("class X { public: X(int); }; void x() { int z; new X(z); }", New)); - StatementMatcher WrongIndex = constructExpr( + StatementMatcher WrongIndex = cxxConstructExpr( hasArgument(42, declRefExpr(to(varDecl(hasName("y")))))); EXPECT_TRUE( notMatches("class X { public: X(int); }; void x() { int y; new X(y); }", @@ -2072,7 +2284,7 @@ TEST(Matcher, NewExpressionArgument) { } TEST(Matcher, NewExpressionArgumentCount) { - StatementMatcher New = constructExpr(argumentCountIs(1)); + StatementMatcher New = cxxConstructExpr(argumentCountIs(1)); EXPECT_TRUE( matches("class X { public: X(int); }; void x() { new X(0); }", New)); @@ -2083,11 +2295,11 @@ TEST(Matcher, NewExpressionArgumentCount) { TEST(Matcher, DeleteExpression) { EXPECT_TRUE(matches("struct A {}; void f(A* a) { delete a; }", - deleteExpr())); + cxxDeleteExpr())); } TEST(Matcher, DefaultArgument) { - StatementMatcher Arg = defaultArgExpr(); + StatementMatcher Arg = cxxDefaultArgExpr(); EXPECT_TRUE(matches("void x(int, int = 0) { int y; x(y); }", Arg)); EXPECT_TRUE( @@ -2152,7 +2364,7 @@ TEST(Matcher, FloatLiterals) { } TEST(Matcher, NullPtrLiteral) { - EXPECT_TRUE(matches("int* i = nullptr;", nullPtrLiteralExpr())); + EXPECT_TRUE(matches("int* i = nullptr;", cxxNullPtrLiteralExpr())); } TEST(Matcher, GNUNullExpr) { @@ -2164,7 +2376,8 @@ TEST(Matcher, AsmStatement) { } TEST(Matcher, Conditions) { - StatementMatcher Condition = ifStmt(hasCondition(boolLiteral(equals(true)))); + StatementMatcher Condition = + ifStmt(hasCondition(cxxBoolLiteral(equals(true)))); EXPECT_TRUE(matches("void x() { if (true) {} }", Condition)); EXPECT_TRUE(notMatches("void x() { if (false) {} }", Condition)); @@ -2175,13 +2388,13 @@ TEST(Matcher, Conditions) { TEST(IfStmt, ChildTraversalMatchers) { EXPECT_TRUE(matches("void f() { if (false) true; else false; }", - ifStmt(hasThen(boolLiteral(equals(true)))))); + ifStmt(hasThen(cxxBoolLiteral(equals(true)))))); EXPECT_TRUE(notMatches("void f() { if (false) false; else true; }", - ifStmt(hasThen(boolLiteral(equals(true)))))); + ifStmt(hasThen(cxxBoolLiteral(equals(true)))))); EXPECT_TRUE(matches("void f() { if (false) false; else true; }", - ifStmt(hasElse(boolLiteral(equals(true)))))); + ifStmt(hasElse(cxxBoolLiteral(equals(true)))))); EXPECT_TRUE(notMatches("void f() { if (false) true; else false; }", - ifStmt(hasElse(boolLiteral(equals(true)))))); + ifStmt(hasElse(cxxBoolLiteral(equals(true)))))); } TEST(MatchBinaryOperator, HasOperatorName) { @@ -2193,17 +2406,22 @@ TEST(MatchBinaryOperator, HasOperatorName) { TEST(MatchBinaryOperator, HasLHSAndHasRHS) { StatementMatcher OperatorTrueFalse = - binaryOperator(hasLHS(boolLiteral(equals(true))), - hasRHS(boolLiteral(equals(false)))); + binaryOperator(hasLHS(cxxBoolLiteral(equals(true))), + hasRHS(cxxBoolLiteral(equals(false)))); EXPECT_TRUE(matches("void x() { true || false; }", OperatorTrueFalse)); EXPECT_TRUE(matches("void x() { true && false; }", OperatorTrueFalse)); EXPECT_TRUE(notMatches("void x() { false || true; }", OperatorTrueFalse)); + + StatementMatcher OperatorIntPointer = arraySubscriptExpr( + hasLHS(hasType(isInteger())), hasRHS(hasType(pointsTo(qualType())))); + EXPECT_TRUE(matches("void x() { 1[\"abc\"]; }", OperatorIntPointer)); + EXPECT_TRUE(notMatches("void x() { \"abc\"[1]; }", OperatorIntPointer)); } TEST(MatchBinaryOperator, HasEitherOperand) { StatementMatcher HasOperand = - binaryOperator(hasEitherOperand(boolLiteral(equals(false)))); + binaryOperator(hasEitherOperand(cxxBoolLiteral(equals(false)))); EXPECT_TRUE(matches("void x() { true || false; }", HasOperand)); EXPECT_TRUE(matches("void x() { false && true; }", HasOperand)); @@ -2320,7 +2538,7 @@ TEST(MatchUnaryOperator, HasOperatorName) { TEST(MatchUnaryOperator, HasUnaryOperand) { StatementMatcher OperatorOnFalse = - unaryOperator(hasUnaryOperand(boolLiteral(equals(false)))); + unaryOperator(hasUnaryOperand(cxxBoolLiteral(equals(false)))); EXPECT_TRUE(matches("void x() { !false; }", OperatorOnFalse)); EXPECT_TRUE(notMatches("void x() { !true; }", OperatorOnFalse)); @@ -2363,15 +2581,15 @@ TEST(Matcher, UnaryOperatorTypes) { TEST(Matcher, ConditionalOperator) { StatementMatcher Conditional = conditionalOperator( - hasCondition(boolLiteral(equals(true))), - hasTrueExpression(boolLiteral(equals(false)))); + hasCondition(cxxBoolLiteral(equals(true))), + hasTrueExpression(cxxBoolLiteral(equals(false)))); EXPECT_TRUE(matches("void x() { true ? false : true; }", Conditional)); EXPECT_TRUE(notMatches("void x() { false ? false : true; }", Conditional)); EXPECT_TRUE(notMatches("void x() { true ? true : false; }", Conditional)); StatementMatcher ConditionalFalse = conditionalOperator( - hasFalseExpression(boolLiteral(equals(false)))); + hasFalseExpression(cxxBoolLiteral(equals(false)))); EXPECT_TRUE(matches("void x() { true ? true : false; }", ConditionalFalse)); EXPECT_TRUE( @@ -2478,13 +2696,13 @@ TEST(Matcher, IsDefinition) { EXPECT_TRUE(notMatches("extern int a;", DefinitionOfVariableA)); DeclarationMatcher DefinitionOfMethodA = - methodDecl(hasName("a"), isDefinition()); + cxxMethodDecl(hasName("a"), isDefinition()); EXPECT_TRUE(matches("class A { void a() {} };", DefinitionOfMethodA)); EXPECT_TRUE(notMatches("class A { void a(); };", DefinitionOfMethodA)); } TEST(Matcher, OfClass) { - StatementMatcher Constructor = constructExpr(hasDeclaration(methodDecl( + StatementMatcher Constructor = cxxConstructExpr(hasDeclaration(cxxMethodDecl( ofClass(hasName("X"))))); EXPECT_TRUE( @@ -2502,7 +2720,7 @@ TEST(Matcher, VisitsTemplateInstantiations) { "class A { public: void x(); };" "template <typename T> class B { public: void y() { T t; t.x(); } };" "void f() { B<A> b; b.y(); }", - callExpr(callee(methodDecl(hasName("x")))))); + callExpr(callee(cxxMethodDecl(hasName("x")))))); EXPECT_TRUE(matches( "class A { public: void x(); };" @@ -2513,8 +2731,8 @@ TEST(Matcher, VisitsTemplateInstantiations) { "void f() {" " C::B<A> b; b.y();" "}", - recordDecl(hasName("C"), - hasDescendant(callExpr(callee(methodDecl(hasName("x")))))))); + recordDecl(hasName("C"), hasDescendant(callExpr( + callee(cxxMethodDecl(hasName("x")))))))); } TEST(Matcher, HandlesNullQualTypes) { @@ -2607,10 +2825,10 @@ TEST(For, ForLoopInternals) { TEST(For, ForRangeLoopInternals) { EXPECT_TRUE(matches("void f(){ int a[] {1, 2}; for (int i : a); }", - forRangeStmt(hasLoopVariable(anything())))); + cxxForRangeStmt(hasLoopVariable(anything())))); EXPECT_TRUE(matches( "void f(){ int a[] {1, 2}; for (int i : a); }", - forRangeStmt(hasRangeInit(declRefExpr(to(varDecl(hasName("a")))))))); + cxxForRangeStmt(hasRangeInit(declRefExpr(to(varDecl(hasName("a")))))))); } TEST(For, NegativeForLoopInternals) { @@ -2650,7 +2868,7 @@ TEST(HasBody, FindsBodyOfForWhileDoLoops) { EXPECT_TRUE(matches("void f() { do {} while(true); }", doStmt(hasBody(compoundStmt())))); EXPECT_TRUE(matches("void f() { int p[2]; for (auto x : p) {} }", - forRangeStmt(hasBody(compoundStmt())))); + cxxForRangeStmt(hasBody(compoundStmt())))); } TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) { @@ -2771,16 +2989,16 @@ TEST(Member, MatchesMemberAllocationFunction) { EXPECT_TRUE(matchesConditionally( "namespace std { typedef typeof(sizeof(int)) size_t; }" "class X { void *operator new(std::size_t); };", - methodDecl(ofClass(hasName("X"))), true, "-std=gnu++98")); + cxxMethodDecl(ofClass(hasName("X"))), true, "-std=gnu++98")); EXPECT_TRUE(matches("class X { void operator delete(void*); };", - methodDecl(ofClass(hasName("X"))))); + cxxMethodDecl(ofClass(hasName("X"))))); // Fails in C++11 mode EXPECT_TRUE(matchesConditionally( "namespace std { typedef typeof(sizeof(int)) size_t; }" "class X { void operator delete[](void*, std::size_t); };", - methodDecl(ofClass(hasName("X"))), true, "-std=gnu++98")); + cxxMethodDecl(ofClass(hasName("X"))), true, "-std=gnu++98")); } TEST(HasObjectExpression, DoesNotMatchMember) { @@ -2822,6 +3040,15 @@ TEST(Field, MatchesField) { EXPECT_TRUE(matches("class X { int m; };", fieldDecl(hasName("m")))); } +TEST(IsVolatileQualified, QualifiersMatch) { + EXPECT_TRUE(matches("volatile int i = 42;", + varDecl(hasType(isVolatileQualified())))); + EXPECT_TRUE(notMatches("volatile int *i;", + varDecl(hasType(isVolatileQualified())))); + EXPECT_TRUE(matches("typedef volatile int v_int; v_int i = 42;", + varDecl(hasType(isVolatileQualified())))); +} + TEST(IsConstQualified, MatchesConstInt) { EXPECT_TRUE(matches("const int i = 42;", varDecl(hasType(isConstQualified())))); @@ -2868,59 +3095,59 @@ TEST(CastExpression, DoesNotMatchNonCasts) { TEST(ReinterpretCast, MatchesSimpleCase) { EXPECT_TRUE(matches("char* p = reinterpret_cast<char*>(&p);", - reinterpretCastExpr())); + cxxReinterpretCastExpr())); } TEST(ReinterpretCast, DoesNotMatchOtherCasts) { - EXPECT_TRUE(notMatches("char* p = (char*)(&p);", reinterpretCastExpr())); + EXPECT_TRUE(notMatches("char* p = (char*)(&p);", cxxReinterpretCastExpr())); EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);", - reinterpretCastExpr())); + cxxReinterpretCastExpr())); EXPECT_TRUE(notMatches("void* p = static_cast<void*>(&p);", - reinterpretCastExpr())); + cxxReinterpretCastExpr())); EXPECT_TRUE(notMatches("struct B { virtual ~B() {} }; struct D : B {};" "B b;" "D* p = dynamic_cast<D*>(&b);", - reinterpretCastExpr())); + cxxReinterpretCastExpr())); } TEST(FunctionalCast, MatchesSimpleCase) { std::string foo_class = "class Foo { public: Foo(const char*); };"; EXPECT_TRUE(matches(foo_class + "void r() { Foo f = Foo(\"hello world\"); }", - functionalCastExpr())); + cxxFunctionalCastExpr())); } TEST(FunctionalCast, DoesNotMatchOtherCasts) { std::string FooClass = "class Foo { public: Foo(const char*); };"; EXPECT_TRUE( notMatches(FooClass + "void r() { Foo f = (Foo) \"hello world\"; }", - functionalCastExpr())); + cxxFunctionalCastExpr())); EXPECT_TRUE( notMatches(FooClass + "void r() { Foo f = \"hello world\"; }", - functionalCastExpr())); + cxxFunctionalCastExpr())); } TEST(DynamicCast, MatchesSimpleCase) { EXPECT_TRUE(matches("struct B { virtual ~B() {} }; struct D : B {};" "B b;" "D* p = dynamic_cast<D*>(&b);", - dynamicCastExpr())); + cxxDynamicCastExpr())); } TEST(StaticCast, MatchesSimpleCase) { EXPECT_TRUE(matches("void* p(static_cast<void*>(&p));", - staticCastExpr())); + cxxStaticCastExpr())); } TEST(StaticCast, DoesNotMatchOtherCasts) { - EXPECT_TRUE(notMatches("char* p = (char*)(&p);", staticCastExpr())); + EXPECT_TRUE(notMatches("char* p = (char*)(&p);", cxxStaticCastExpr())); EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);", - staticCastExpr())); + cxxStaticCastExpr())); EXPECT_TRUE(notMatches("void* p = reinterpret_cast<char*>(&p);", - staticCastExpr())); + cxxStaticCastExpr())); EXPECT_TRUE(notMatches("struct B { virtual ~B() {} }; struct D : B {};" "B b;" "D* p = dynamic_cast<D*>(&b);", - staticCastExpr())); + cxxStaticCastExpr())); } TEST(CStyleCast, MatchesSimpleCase) { @@ -2939,7 +3166,7 @@ TEST(CStyleCast, DoesNotMatchOtherCasts) { TEST(HasDestinationType, MatchesSimpleCase) { EXPECT_TRUE(matches("char* p = static_cast<char*>(0);", - staticCastExpr(hasDestinationType( + cxxStaticCastExpr(hasDestinationType( pointsTo(TypeMatcher(anything())))))); } @@ -3142,7 +3369,7 @@ TEST(HasSourceExpression, MatchesImplicitCasts) { EXPECT_TRUE(matches("class string {}; class URL { public: URL(string s); };" "void r() {string a_string; URL url = a_string; }", implicitCastExpr( - hasSourceExpression(constructExpr())))); + hasSourceExpression(cxxConstructExpr())))); } TEST(HasSourceExpression, MatchesExplicitCasts) { @@ -3314,21 +3541,26 @@ TEST(SwitchCase, MatchesEachCase) { TEST(ForEachConstructorInitializer, MatchesInitializers) { EXPECT_TRUE(matches( "struct X { X() : i(42), j(42) {} int i, j; };", - constructorDecl(forEachConstructorInitializer(ctorInitializer())))); + cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer())))); } TEST(ExceptionHandling, SimpleCases) { - EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", catchStmt())); - EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", tryStmt())); - EXPECT_TRUE(notMatches("void foo() try { } catch(int X) { }", throwExpr())); + EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", cxxCatchStmt())); + EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", cxxTryStmt())); + EXPECT_TRUE( + notMatches("void foo() try { } catch(int X) { }", cxxThrowExpr())); EXPECT_TRUE(matches("void foo() try { throw; } catch(int X) { }", - throwExpr())); + cxxThrowExpr())); EXPECT_TRUE(matches("void foo() try { throw 5;} catch(int X) { }", - throwExpr())); + cxxThrowExpr())); EXPECT_TRUE(matches("void foo() try { throw; } catch(...) { }", - catchStmt(isCatchAll()))); + cxxCatchStmt(isCatchAll()))); EXPECT_TRUE(notMatches("void foo() try { throw; } catch(int) { }", - catchStmt(isCatchAll()))); + cxxCatchStmt(isCatchAll()))); + EXPECT_TRUE(matches("void foo() try {} catch(int X) { }", + varDecl(isExceptionVariable()))); + EXPECT_TRUE(notMatches("void foo() try { int X; } catch (...) { }", + varDecl(isExceptionVariable()))); } TEST(HasConditionVariableStatement, DoesNotMatchCondition) { @@ -3460,12 +3692,12 @@ TEST(LoopingMatchers, DoNotOverwritePreviousMatchResultOnFailure) { new VerifyIdIsBoundTo<Decl>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( "class X { void f(); void g(); };", - recordDecl(decl().bind("x"), hasMethod(hasName("g"))), + cxxRecordDecl(decl().bind("x"), hasMethod(hasName("g"))), new VerifyIdIsBoundTo<Decl>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( "class X { X() : a(1), b(2) {} double a; int b; };", recordDecl(decl().bind("x"), - has(constructorDecl( + has(cxxConstructorDecl( hasAnyConstructorInitializer(forField(hasName("b")))))), new VerifyIdIsBoundTo<Decl>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( @@ -3489,12 +3721,12 @@ TEST(LoopingMatchers, DoNotOverwritePreviousMatchResultOnFailure) { new VerifyIdIsBoundTo<Decl>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( "class A{}; class B{}; class C : B, A {};", - recordDecl(decl().bind("x"), isDerivedFrom("::A")), + cxxRecordDecl(decl().bind("x"), isDerivedFrom("::A")), new VerifyIdIsBoundTo<Decl>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( "class A{}; typedef A B; typedef A C; typedef A D;" "class E : A {};", - recordDecl(decl().bind("x"), isDerivedFrom("C")), + cxxRecordDecl(decl().bind("x"), isDerivedFrom("C")), new VerifyIdIsBoundTo<Decl>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( "class A { class B { void f() {} }; };", @@ -3513,8 +3745,8 @@ TEST(LoopingMatchers, DoNotOverwritePreviousMatchResultOnFailure) { new VerifyIdIsBoundTo<Decl>("x", 1))); EXPECT_TRUE(matchAndVerifyResultTrue( "class A { A() : s(), i(42) {} const char *s; int i; };", - constructorDecl(hasName("::A::A"), decl().bind("x"), - forEachConstructorInitializer(forField(hasName("i")))), + cxxConstructorDecl(hasName("::A::A"), decl().bind("x"), + forEachConstructorInitializer(forField(hasName("i")))), new VerifyIdIsBoundTo<Decl>("x", 1))); } @@ -3588,11 +3820,11 @@ TEST(IsTemplateInstantiation, MatchesImplicitClassTemplateInstantiation) { EXPECT_TRUE(matches( "template <typename T> class X {}; class A {}; X<A> x;", - recordDecl(hasName("::X"), isTemplateInstantiation()))); + cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); EXPECT_TRUE(matches( "template <typename T> class X { T t; }; class A {}; X<A> x;", - recordDecl(isTemplateInstantiation(), hasDescendant( + cxxRecordDecl(isTemplateInstantiation(), hasDescendant( fieldDecl(hasType(recordDecl(hasName("A")))))))); } @@ -3607,7 +3839,7 @@ TEST(IsTemplateInstantiation, MatchesExplicitClassTemplateInstantiation) { EXPECT_TRUE(matches( "template <typename T> class X { T t; }; class A {};" "template class X<A>;", - recordDecl(isTemplateInstantiation(), hasDescendant( + cxxRecordDecl(isTemplateInstantiation(), hasDescendant( fieldDecl(hasType(recordDecl(hasName("A")))))))); } @@ -3616,7 +3848,7 @@ TEST(IsTemplateInstantiation, EXPECT_TRUE(matches( "template <typename T> class X {};" "template <typename T> class X<T*> {}; class A {}; X<A*> x;", - recordDecl(hasName("::X"), isTemplateInstantiation()))); + cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); } TEST(IsTemplateInstantiation, @@ -3627,7 +3859,7 @@ TEST(IsTemplateInstantiation, " template <typename U> class Y { U u; };" " Y<A> y;" "};", - recordDecl(hasName("::X::Y"), isTemplateInstantiation()))); + cxxRecordDecl(hasName("::X::Y"), isTemplateInstantiation()))); } TEST(IsTemplateInstantiation, DoesNotMatchInstantiationsInsideOfInstantiation) { @@ -3640,31 +3872,31 @@ TEST(IsTemplateInstantiation, DoesNotMatchInstantiationsInsideOfInstantiation) { " template <typename U> class Y { U u; };" " Y<T> y;" "}; X<A> x;", - recordDecl(hasName("::X<A>::Y"), unless(isTemplateInstantiation())))); + cxxRecordDecl(hasName("::X<A>::Y"), unless(isTemplateInstantiation())))); } TEST(IsTemplateInstantiation, DoesNotMatchExplicitClassTemplateSpecialization) { EXPECT_TRUE(notMatches( "template <typename T> class X {}; class A {};" "template <> class X<A> {}; X<A> x;", - recordDecl(hasName("::X"), isTemplateInstantiation()))); + cxxRecordDecl(hasName("::X"), isTemplateInstantiation()))); } TEST(IsTemplateInstantiation, DoesNotMatchNonTemplate) { EXPECT_TRUE(notMatches( "class A {}; class Y { A a; };", - recordDecl(isTemplateInstantiation()))); + cxxRecordDecl(isTemplateInstantiation()))); } TEST(IsInstantiated, MatchesInstantiation) { EXPECT_TRUE( matches("template<typename T> class A { T i; }; class Y { A<int> a; };", - recordDecl(isInstantiated()))); + cxxRecordDecl(isInstantiated()))); } TEST(IsInstantiated, NotMatchesDefinition) { EXPECT_TRUE(notMatches("template<typename T> class A { T i; };", - recordDecl(isInstantiated()))); + cxxRecordDecl(isInstantiated()))); } TEST(IsInTemplateInstantiation, MatchesInstantiationStmt) { @@ -3716,7 +3948,7 @@ TEST(IsExplicitTemplateSpecialization, DoesNotMatchPrimaryTemplate) { EXPECT_TRUE(notMatches( "template <typename T> class X {};", - recordDecl(isExplicitTemplateSpecialization()))); + cxxRecordDecl(isExplicitTemplateSpecialization()))); EXPECT_TRUE(notMatches( "template <typename T> void f(T t);", functionDecl(isExplicitTemplateSpecialization()))); @@ -3727,7 +3959,7 @@ TEST(IsExplicitTemplateSpecialization, EXPECT_TRUE(notMatches( "template <typename T> class X {};" "template class X<int>; extern template class X<long>;", - recordDecl(isExplicitTemplateSpecialization()))); + cxxRecordDecl(isExplicitTemplateSpecialization()))); EXPECT_TRUE(notMatches( "template <typename T> void f(T t) {}" "template void f(int t); extern template void f(long t);", @@ -3738,7 +3970,7 @@ TEST(IsExplicitTemplateSpecialization, DoesNotMatchImplicitTemplateInstantiations) { EXPECT_TRUE(notMatches( "template <typename T> class X {}; X<int> x;", - recordDecl(isExplicitTemplateSpecialization()))); + cxxRecordDecl(isExplicitTemplateSpecialization()))); EXPECT_TRUE(notMatches( "template <typename T> void f(T t); void g() { f(10); }", functionDecl(isExplicitTemplateSpecialization()))); @@ -3749,7 +3981,7 @@ TEST(IsExplicitTemplateSpecialization, EXPECT_TRUE(matches( "template <typename T> class X {};" "template<> class X<int> {};", - recordDecl(isExplicitTemplateSpecialization()))); + cxxRecordDecl(isExplicitTemplateSpecialization()))); EXPECT_TRUE(matches( "template <typename T> void f(T t) {}" "template<> void f(int t) {}", @@ -3831,7 +4063,7 @@ TEST(HasAncestor, MatchesInTemplateInstantiations) { TEST(HasAncestor, MatchesInImplicitCode) { EXPECT_TRUE(matches( "struct X {}; struct A { A() {} X x; };", - constructorDecl( + cxxConstructorDecl( hasAnyConstructorInitializer(withInitializer(expr( hasAncestor(recordDecl(hasName("A"))))))))); } @@ -3854,8 +4086,9 @@ TEST(HasAncestor, MatchesAllAncestors) { "void t() { C<int>::f(); }", integerLiteral( equals(42), - allOf(hasAncestor(recordDecl(isTemplateInstantiation())), - hasAncestor(recordDecl(unless(isTemplateInstantiation()))))))); + allOf( + hasAncestor(cxxRecordDecl(isTemplateInstantiation())), + hasAncestor(cxxRecordDecl(unless(isTemplateInstantiation()))))))); } TEST(HasParent, MatchesAllParents) { @@ -3865,23 +4098,23 @@ TEST(HasParent, MatchesAllParents) { integerLiteral( equals(42), hasParent(compoundStmt(hasParent(functionDecl( - hasParent(recordDecl(isTemplateInstantiation()))))))))); - EXPECT_TRUE(matches( - "template <typename T> struct C { static void f() { 42; } };" - "void t() { C<int>::f(); }", - integerLiteral( - equals(42), - hasParent(compoundStmt(hasParent(functionDecl( - hasParent(recordDecl(unless(isTemplateInstantiation())))))))))); + hasParent(cxxRecordDecl(isTemplateInstantiation()))))))))); + EXPECT_TRUE( + matches("template <typename T> struct C { static void f() { 42; } };" + "void t() { C<int>::f(); }", + integerLiteral( + equals(42), + hasParent(compoundStmt(hasParent(functionDecl(hasParent( + cxxRecordDecl(unless(isTemplateInstantiation())))))))))); EXPECT_TRUE(matches( "template <typename T> struct C { static void f() { 42; } };" "void t() { C<int>::f(); }", integerLiteral(equals(42), - hasParent(compoundStmt(allOf( - hasParent(functionDecl( - hasParent(recordDecl(isTemplateInstantiation())))), - hasParent(functionDecl(hasParent(recordDecl( - unless(isTemplateInstantiation()))))))))))); + hasParent(compoundStmt( + allOf(hasParent(functionDecl(hasParent( + cxxRecordDecl(isTemplateInstantiation())))), + hasParent(functionDecl(hasParent(cxxRecordDecl( + unless(isTemplateInstantiation()))))))))))); EXPECT_TRUE( notMatches("template <typename T> struct C { static void f() {} };" "void t() { C<int>::f(); }", @@ -3913,9 +4146,16 @@ TEST(TypeMatching, MatchesTypes) { EXPECT_TRUE(matches("struct S {};", qualType().bind("loc"))); } +TEST(TypeMatching, MatchesBool) { + EXPECT_TRUE(matches("struct S { bool func(); };", + cxxMethodDecl(returns(booleanType())))); + EXPECT_TRUE(notMatches("struct S { void func(); };", + cxxMethodDecl(returns(booleanType())))); +} + TEST(TypeMatching, MatchesVoid) { - EXPECT_TRUE( - matches("struct S { void func(); };", methodDecl(returns(voidType())))); + EXPECT_TRUE(matches("struct S { void func(); };", + cxxMethodDecl(returns(voidType())))); } TEST(TypeMatching, MatchesArrayTypes) { @@ -3952,6 +4192,11 @@ TEST(TypeMatching, MatchesArrayTypes) { EXPECT_TRUE(matches("const int a = 0;", qualType(isInteger()))); } +TEST(TypeMatching, DecayedType) { + EXPECT_TRUE(matches("void f(int i[]);", valueDecl(hasType(decayedType(hasDecayedType(pointerType())))))); + EXPECT_TRUE(notMatches("int i[7];", decayedType())); +} + TEST(TypeMatching, MatchesComplexTypes) { EXPECT_TRUE(matches("_Complex float f;", complexType())); EXPECT_TRUE(matches( @@ -4247,6 +4492,18 @@ TEST(ElaboratedTypeNarrowing, namesType) { elaboratedType(elaboratedType(namesType(typedefType()))))); } +TEST(TypeMatching, MatchesSubstTemplateTypeParmType) { + const std::string code = "template <typename T>" + "int F() {" + " return 1 + T();" + "}" + "int i = F<int>();"; + EXPECT_FALSE(matches(code, binaryOperator(hasLHS( + expr(hasType(substTemplateTypeParmType())))))); + EXPECT_TRUE(matches(code, binaryOperator(hasRHS( + expr(hasType(substTemplateTypeParmType())))))); +} + TEST(NNS, MatchesNestedNameSpecifiers) { EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;", nestedNameSpecifier())); @@ -4254,6 +4511,8 @@ TEST(NNS, MatchesNestedNameSpecifiers) { nestedNameSpecifier())); EXPECT_TRUE(matches("struct A { void f(); }; void A::f() {}", nestedNameSpecifier())); + EXPECT_TRUE(matches("namespace a { namespace b {} } namespace ab = a::b;", + nestedNameSpecifier())); EXPECT_TRUE(matches( "struct A { static void f() {} }; void g() { A::f(); }", @@ -4268,6 +4527,16 @@ TEST(NullStatement, SimpleCases) { EXPECT_TRUE(notMatches("void f() {int i;}", nullStmt())); } +TEST(NS, Anonymous) { + EXPECT_TRUE(notMatches("namespace N {}", namespaceDecl(isAnonymous()))); + EXPECT_TRUE(matches("namespace {}", namespaceDecl(isAnonymous()))); +} + +TEST(NS, Alias) { + EXPECT_TRUE(matches("namespace test {} namespace alias = ::test;", + namespaceAliasDecl(hasName("alias")))); +} + TEST(NNS, MatchesTypes) { NestedNameSpecifierMatcher Matcher = nestedNameSpecifier( specifiesType(hasDeclaration(recordDecl(hasName("A"))))); @@ -4480,6 +4749,16 @@ public: decl(has(decl(equalsNode(TypedNode)))).bind(""))), *Node, Context)) != nullptr; } + bool verify(const BoundNodes &Nodes, ASTContext &Context, const Type *Node) { + // Use the original typed pointer to verify we can pass pointers to subtypes + // to equalsNode. + const T *TypedNode = cast<T>(Node); + const auto *Dec = Nodes.getNodeAs<FieldDecl>("decl"); + return selectFirst<T>( + "", match(fieldDecl(hasParent(decl(has(fieldDecl( + hasType(type(equalsNode(TypedNode)).bind(""))))))), + *Dec, Context)) != nullptr; + } }; TEST(IsEqualTo, MatchesNodesByIdentity) { @@ -4489,6 +4768,10 @@ TEST(IsEqualTo, MatchesNodesByIdentity) { EXPECT_TRUE(matchAndVerifyResultTrue( "void f() { if (true) if(true) {} }", ifStmt().bind(""), new VerifyAncestorHasChildIsEqual<IfStmt>())); + EXPECT_TRUE(matchAndVerifyResultTrue( + "class X { class Y {} y; };", + fieldDecl(hasName("y"), hasType(type().bind(""))).bind("decl"), + new VerifyAncestorHasChildIsEqual<Type>())); } TEST(MatchFinder, CheckProfiling) { @@ -4656,12 +4939,12 @@ TEST(EqualsBoundNodeMatcher, UnlessDescendantsOfAncestorsMatch) { "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")))), + cxxMemberCallExpr( + callee(cxxMethodDecl(hasName("data"))), + on(declRefExpr(to( + varDecl(hasType(recordDecl(hasName("StringRef")))).bind("var")))), + unless(hasAncestor(stmt(hasDescendant(cxxMemberCallExpr( + callee(cxxMethodDecl(anyOf(hasName("size"), hasName("length")))), on(declRefExpr(to(varDecl(equalsBoundNode("var"))))))))))) .bind("data"), new VerifyIdIsBoundTo<Expr>("data", 1))); @@ -4672,12 +4955,12 @@ TEST(EqualsBoundNodeMatcher, UnlessDescendantsOfAncestorsMatch) { " 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")))), + cxxMemberCallExpr( + callee(cxxMethodDecl(hasName("data"))), + on(declRefExpr(to( + varDecl(hasType(recordDecl(hasName("StringRef")))).bind("var")))), + unless(hasAncestor(stmt(hasDescendant(cxxMemberCallExpr( + callee(cxxMethodDecl(anyOf(hasName("size"), hasName("length")))), on(declRefExpr(to(varDecl(equalsBoundNode("var"))))))))))) .bind("data"))); } @@ -4687,6 +4970,13 @@ TEST(TypeDefDeclMatcher, Match) { typedefDecl(hasName("typedefDeclTest")))); } +TEST(IsInlineMatcher, IsInline) { + EXPECT_TRUE(matches("void g(); inline void f();", + functionDecl(isInline(), hasName("f")))); + EXPECT_TRUE(matches("namespace n { inline namespace m {} }", + namespaceDecl(isInline(), hasName("m")))); +} + // FIXME: Figure out how to specify paths so the following tests pass on Windows. #ifndef LLVM_ON_WIN32 @@ -4774,6 +5064,9 @@ TEST(ObjCMessageExprMatcher, SimpleExprs) { objcMessageExpr(hasSelector("contents"), hasUnarySelector()))); EXPECT_TRUE(matchesObjC( Objc1String, + objcMessageExpr(hasSelector("contents"), numSelectorArgs(0)))); + EXPECT_TRUE(matchesObjC( + Objc1String, objcMessageExpr(matchesSelector("uppercase*"), argumentCountIs(0) ))); diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h index 403a305db2440..68824e61ac693 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.h +++ b/unittests/ASTMatchers/ASTMatchersTest.h @@ -120,6 +120,19 @@ testing::AssertionResult matchesObjC(const std::string &Code, } template <typename T> +testing::AssertionResult matchesC(const std::string &Code, const T &AMatcher) { + return matchesConditionally(Code, AMatcher, true, "", FileContentMappings(), + "input.c"); +} + +template <typename T> +testing::AssertionResult notMatchesC(const std::string &Code, + const T &AMatcher) { + return matchesConditionally(Code, AMatcher, false, "", FileContentMappings(), + "input.c"); +} + +template <typename T> testing::AssertionResult notMatchesObjC(const std::string &Code, const T &AMatcher) { return matchesConditionally( @@ -165,6 +178,7 @@ testing::AssertionResult matchesConditionallyWithCuda( Args.push_back("-xcuda"); Args.push_back("-fno-ms-extensions"); Args.push_back("--cuda-host-only"); + Args.push_back("-nocudainc"); Args.push_back(CompileArg); if (!runToolOnCodeWithArgs(Factory->create(), CudaHeader + Code, Args)) { diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp index 45b0910ab0a2d..0de6242a67b08 100644 --- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp +++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp @@ -50,7 +50,7 @@ public: } VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, - const SourceRange &NameRange, + SourceRange NameRange, StringRef BindID, ArrayRef<ParserValue> Args, Diagnostics *Error) override { @@ -102,7 +102,7 @@ TEST(ParserTest, ParseString) { EXPECT_EQ("1:1: Error parsing string token: <\"Baz>", Sema.Errors[2]); } -bool matchesRange(const SourceRange &Range, unsigned StartLine, +bool matchesRange(SourceRange Range, unsigned StartLine, unsigned EndLine, unsigned StartColumn, unsigned EndColumn) { EXPECT_EQ(StartLine, Range.Start.Line); EXPECT_EQ(EndLine, Range.End.Line); @@ -301,12 +301,12 @@ TEST(ParserTest, CompletionNamedValues) { EXPECT_EQ("String nameX", Comps[0].MatcherDecl); // Can complete if there are names in the expression. - Code = "methodDecl(hasName(nameX), "; + Code = "cxxMethodDecl(hasName(nameX), "; Comps = Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues); EXPECT_LT(0u, Comps.size()); // Can complete names and registry together. - Code = "methodDecl(hasP"; + Code = "cxxMethodDecl(hasP"; Comps = Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues); ASSERT_EQ(3u, Comps.size()); EXPECT_EQ("aramA", Comps[0].TypedText); @@ -318,8 +318,10 @@ TEST(ParserTest, CompletionNamedValues) { Comps[1].MatcherDecl); EXPECT_EQ("arent(", Comps[2].TypedText); - EXPECT_EQ("Matcher<Decl> hasParent(Matcher<Decl|Stmt>)", - Comps[2].MatcherDecl); + EXPECT_EQ( + "Matcher<Decl> " + "hasParent(Matcher<TemplateArgument|NestedNameSpecifierLoc|Decl|...>)", + Comps[2].MatcherDecl); } } // end anonymous namespace diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp index a6b0a1b41d6b3..8e97566f69202 100644 --- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -129,7 +129,7 @@ TEST_F(RegistryTest, CanConstructNoArgs) { Matcher<Stmt> IsArrowValue = constructMatcher( "memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>(); Matcher<Stmt> BoolValue = - constructMatcher("boolLiteral").getTypedMatcher<Stmt>(); + constructMatcher("cxxBoolLiteral").getTypedMatcher<Stmt>(); const std::string ClassSnippet = "struct Foo { int x; };\n" "Foo *foo = new Foo;\n" @@ -195,7 +195,7 @@ TEST_F(RegistryTest, OverloadedMatchers) { "callExpr", constructMatcher( "callee", - constructMatcher("methodDecl", + constructMatcher("cxxMethodDecl", constructMatcher("hasName", StringRef("x"))))) .getTypedMatcher<Stmt>(); @@ -255,11 +255,11 @@ TEST_F(RegistryTest, PolymorphicMatchers) { EXPECT_FALSE(matches("void Foo(){};", RecordDecl)); Matcher<Stmt> ConstructExpr = constructMatcher( - "constructExpr", + "cxxConstructExpr", constructMatcher( "hasDeclaration", constructMatcher( - "methodDecl", + "cxxMethodDecl", constructMatcher( "ofClass", constructMatcher("hasName", StringRef("Foo")))))) .getTypedMatcher<Stmt>(); @@ -300,7 +300,7 @@ TEST_F(RegistryTest, TypeTraversal) { TEST_F(RegistryTest, CXXCtorInitializer) { Matcher<Decl> CtorDecl = constructMatcher( - "constructorDecl", + "cxxConstructorDecl", constructMatcher( "hasAnyConstructorInitializer", constructMatcher("forField", @@ -416,9 +416,10 @@ TEST_F(RegistryTest, Errors) { "(Actual = String)", Error->toString()); Error.reset(new Diagnostics()); - EXPECT_TRUE(constructMatcher("recordDecl", constructMatcher("recordDecl"), - constructMatcher("parameterCountIs", 3), - Error.get()).isNull()); + EXPECT_TRUE( + constructMatcher("cxxRecordDecl", constructMatcher("cxxRecordDecl"), + constructMatcher("parameterCountIs", 3), Error.get()) + .isNull()); EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != " "(Actual = Matcher<FunctionDecl>)", Error->toString()); @@ -432,7 +433,7 @@ TEST_F(RegistryTest, Errors) { Error->toString()); Error.reset(new Diagnostics()); EXPECT_TRUE(constructMatcher( - "recordDecl", + "cxxRecordDecl", constructMatcher("allOf", constructMatcher("isDerivedFrom", StringRef("FOO")), constructMatcher("isArrow")), @@ -447,15 +448,17 @@ TEST_F(RegistryTest, Completion) { CompVector Comps = getCompletions(); // Overloaded EXPECT_TRUE(hasCompletion( - Comps, "hasParent(", "Matcher<Decl|Stmt> hasParent(Matcher<Decl|Stmt>)")); + Comps, "hasParent(", + "Matcher<TemplateArgument|NestedNameSpecifierLoc|Decl|...> " + "hasParent(Matcher<TemplateArgument|NestedNameSpecifierLoc|Decl|...>)")); // Variadic. EXPECT_TRUE(hasCompletion(Comps, "whileStmt(", "Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)")); // Polymorphic. EXPECT_TRUE(hasCompletion( Comps, "hasDescendant(", - "Matcher<NestedNameSpecifier|NestedNameSpecifierLoc|QualType|...> " - "hasDescendant(Matcher<CXXCtorInitializer|NestedNameSpecifier|" + "Matcher<TemplateArgument|NestedNameSpecifier|NestedNameSpecifierLoc|...>" + " hasDescendant(Matcher<TemplateArgument|NestedNameSpecifier|" "NestedNameSpecifierLoc|...>)")); CompVector WhileComps = getCompletions("whileStmt", 0); @@ -463,7 +466,9 @@ TEST_F(RegistryTest, Completion) { EXPECT_TRUE(hasCompletion(WhileComps, "hasBody(", "Matcher<WhileStmt> hasBody(Matcher<Stmt>)")); EXPECT_TRUE(hasCompletion(WhileComps, "hasParent(", - "Matcher<Stmt> hasParent(Matcher<Decl|Stmt>)")); + "Matcher<Stmt> " + "hasParent(Matcher<TemplateArgument|" + "NestedNameSpecifierLoc|Decl|...>)")); EXPECT_TRUE( hasCompletion(WhileComps, "allOf(", "Matcher<T> allOf(Matcher<T>...)")); diff --git a/unittests/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp index 494c27a2f1cdf..5a1a393fbf02a 100644 --- a/unittests/Basic/SourceManagerTest.cpp +++ b/unittests/Basic/SourceManagerTest.cpp @@ -66,7 +66,7 @@ class VoidModuleLoader : public ModuleLoader { GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override { return nullptr; } bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override - { return 0; }; + { return 0; } }; TEST_F(SourceManagerTest, isBeforeInTranslationUnit) { diff --git a/unittests/Basic/VirtualFileSystemTest.cpp b/unittests/Basic/VirtualFileSystemTest.cpp index 71d2d2b60c04c..ac07035d3e1f2 100644 --- a/unittests/Basic/VirtualFileSystemTest.cpp +++ b/unittests/Basic/VirtualFileSystemTest.cpp @@ -14,11 +14,24 @@ #include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" #include <map> + using namespace clang; using namespace llvm; using llvm::sys::fs::UniqueID; namespace { +struct DummyFile : public vfs::File { + vfs::Status S; + explicit DummyFile(vfs::Status S) : S(S) {} + llvm::ErrorOr<vfs::Status> status() override { return S; } + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> + getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator, + bool IsVolatile) override { + llvm_unreachable("unimplemented"); + } + virtual std::error_code close() override { return std::error_code(); } +}; + class DummyFileSystem : public vfs::FileSystem { int FSID; // used to produce UniqueIDs int FileID; // used to produce UniqueIDs @@ -41,7 +54,16 @@ public: } ErrorOr<std::unique_ptr<vfs::File>> openFileForRead(const Twine &Path) override { - llvm_unreachable("unimplemented"); + auto S = status(Path); + if (S) + return std::unique_ptr<vfs::File>(new DummyFile{*S}); + return S.getError(); + } + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override { + return std::string(); + } + std::error_code setCurrentWorkingDirectory(const Twine &Path) override { + return std::error_code(); } struct DirIterImpl : public clang::vfs::detail::DirIterImpl { @@ -92,20 +114,20 @@ public: } 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); + vfs::Status S(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); + vfs::Status S(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); + vfs::Status S(Path, UniqueID(FSID, FileID++), sys::TimeValue::now(), 0, 0, + 0, sys::fs::file_type::symlink_file, sys::fs::all_all); addEntry(Path, S); } }; @@ -279,7 +301,7 @@ struct ScopedDir { } operator StringRef() { return Path.str(); } }; -} +} // end anonymous namespace TEST(VirtualFileSystemTest, BasicRealFSIteration) { ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true); @@ -515,6 +537,128 @@ TEST(VirtualFileSystemTest, HiddenInIteration) { } } +class InMemoryFileSystemTest : public ::testing::Test { +protected: + clang::vfs::InMemoryFileSystem FS; + clang::vfs::InMemoryFileSystem NormalizedFS; + + InMemoryFileSystemTest() + : FS(/*UseNormalizedPaths=*/false), + NormalizedFS(/*UseNormalizedPaths=*/true) {} +}; + +TEST_F(InMemoryFileSystemTest, IsEmpty) { + auto Stat = FS.status("/a"); + ASSERT_EQ(Stat.getError(),errc::no_such_file_or_directory) << FS.toString(); + Stat = FS.status("/"); + ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString(); +} + +TEST_F(InMemoryFileSystemTest, WindowsPath) { + FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer("")); + auto Stat = FS.status("c:"); +#if !defined(_WIN32) + ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString(); +#endif + Stat = FS.status("c:/windows/system128/foo.cpp"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString(); + FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer("")); + Stat = FS.status("d:/windows/foo.cpp"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString(); +} + +TEST_F(InMemoryFileSystemTest, OverlayFile) { + FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")); + NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")); + auto Stat = FS.status("/"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString(); + Stat = FS.status("/."); + ASSERT_FALSE(Stat); + Stat = NormalizedFS.status("/."); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString(); + Stat = FS.status("/a"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_EQ("/a", Stat->getName()); +} + +TEST_F(InMemoryFileSystemTest, OverlayFileNoOwn) { + auto Buf = MemoryBuffer::getMemBuffer("a"); + FS.addFileNoOwn("/a", 0, Buf.get()); + auto Stat = FS.status("/a"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_EQ("/a", Stat->getName()); +} + +TEST_F(InMemoryFileSystemTest, OpenFileForRead) { + FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")); + FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c")); + FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d")); + NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")); + NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c")); + NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d")); + auto File = FS.openFileForRead("/a"); + ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer()); + File = FS.openFileForRead("/a"); // Open again. + ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer()); + File = NormalizedFS.openFileForRead("/././a"); // Open again. + ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer()); + File = FS.openFileForRead("/"); + ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString(); + File = FS.openFileForRead("/b"); + ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString(); + File = FS.openFileForRead("./c"); + ASSERT_FALSE(File); + File = FS.openFileForRead("e/../d"); + ASSERT_FALSE(File); + File = NormalizedFS.openFileForRead("./c"); + ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer()); + File = NormalizedFS.openFileForRead("e/../d"); + ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer()); +} + +TEST_F(InMemoryFileSystemTest, DuplicatedFile) { + ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"))); + ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a"))); + ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"))); + ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b"))); +} + +TEST_F(InMemoryFileSystemTest, DirectoryIteration) { + FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("")); + FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer("")); + + std::error_code EC; + vfs::directory_iterator I = FS.dir_begin("/", EC); + ASSERT_FALSE(EC); + ASSERT_EQ("/a", I->getName()); + I.increment(EC); + ASSERT_FALSE(EC); + ASSERT_EQ("/b", I->getName()); + I.increment(EC); + ASSERT_FALSE(EC); + ASSERT_EQ(vfs::directory_iterator(), I); + + I = FS.dir_begin("/b", EC); + ASSERT_FALSE(EC); + ASSERT_EQ("/b/c", I->getName()); + I.increment(EC); + ASSERT_FALSE(EC); + ASSERT_EQ(vfs::directory_iterator(), I); +} + +TEST_F(InMemoryFileSystemTest, WorkingDirectory) { + FS.setCurrentWorkingDirectory("/b"); + FS.addFile("c", 0, MemoryBuffer::getMemBuffer("")); + + auto Stat = FS.status("/b/c"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); + ASSERT_EQ("c", Stat->getName()); + ASSERT_EQ("/b", *FS.getCurrentWorkingDirectory()); + + Stat = FS.status("c"); + ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString(); +} + // 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 { @@ -589,10 +733,20 @@ TEST_F(VFSFromYAMLTest, MappedFiles) { ErrorOr<vfs::Status> S = O->status("//root/file1"); ASSERT_FALSE(S.getError()); EXPECT_EQ("//root/foo/bar/a", S->getName()); + EXPECT_TRUE(S->IsVFSMapped); ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a"); EXPECT_EQ("//root/foo/bar/a", SLower->getName()); EXPECT_TRUE(S->equivalent(*SLower)); + EXPECT_FALSE(SLower->IsVFSMapped); + + // file after opening + auto OpenedF = O->openFileForRead("//root/file1"); + ASSERT_FALSE(OpenedF.getError()); + auto OpenedS = (*OpenedF)->status(); + ASSERT_FALSE(OpenedS.getError()); + EXPECT_EQ("//root/foo/bar/a", OpenedS->getName()); + EXPECT_TRUE(OpenedS->IsVFSMapped); // directory S = O->status("//root/"); @@ -906,7 +1060,7 @@ TEST_F(VFSFromYAMLTest, DirectoryIteration) { "]\n" "}", Lower); - ASSERT_TRUE(FS.get() != NULL); + ASSERT_TRUE(FS.get() != nullptr); IntrusiveRefCntPtr<vfs::OverlayFileSystem> O( new vfs::OverlayFileSystem(Lower)); diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 6636d82db74d5..b85ec7e6dfa09 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -25,6 +25,6 @@ add_subdirectory(Sema) add_subdirectory(CodeGen) # FIXME: libclang unit tests are disabled on Windows due # to failures, mostly in libclang.VirtualFileOverlay_*. -if(NOT WIN32) +if(NOT WIN32 AND CLANG_TOOL_LIBCLANG_BUILD) add_subdirectory(libclang) endif() diff --git a/unittests/CodeGen/BufferSourceTest.cpp b/unittests/CodeGen/BufferSourceTest.cpp index e80e83bd28870..85df768aa1b44 100644 --- a/unittests/CodeGen/BufferSourceTest.cpp +++ b/unittests/CodeGen/BufferSourceTest.cpp @@ -67,7 +67,7 @@ TEST(BufferSourceTest, EmitCXXGlobalInitFunc) { compiler.getCodeGenOpts(), llvm::getGlobalContext()))); - compiler.createSema(clang::TU_Prefix,NULL); + compiler.createSema(clang::TU_Prefix, nullptr); clang::SourceManager &sm = compiler.getSourceManager(); sm.setMainFileID(sm.createFileID( @@ -76,4 +76,4 @@ TEST(BufferSourceTest, EmitCXXGlobalInitFunc) { clang::ParseAST(compiler.getSema(), false, false); } -} +} // end anonymous namespace diff --git a/unittests/Driver/CMakeLists.txt b/unittests/Driver/CMakeLists.txt index 8cc963b33a21b..2df1eb24fd44e 100644 --- a/unittests/Driver/CMakeLists.txt +++ b/unittests/Driver/CMakeLists.txt @@ -3,9 +3,11 @@ set(LLVM_LINK_COMPONENTS ) add_clang_unittest(ClangDriverTests + ToolChainTest.cpp MultilibTest.cpp ) target_link_libraries(ClangDriverTests clangDriver + clangBasic ) diff --git a/unittests/Driver/ToolChainTest.cpp b/unittests/Driver/ToolChainTest.cpp new file mode 100644 index 0000000000000..ef21e2d17c6c8 --- /dev/null +++ b/unittests/Driver/ToolChainTest.cpp @@ -0,0 +1,120 @@ +//===- unittests/Driver/ToolChainTest.cpp --- ToolChain 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 ToolChains. +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/ToolChain.h" +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" +using namespace clang; +using namespace clang::driver; + +namespace { + +TEST(ToolChainTest, VFSGCCInstallation) { + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); + + IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); + struct TestDiagnosticConsumer : public DiagnosticConsumer {}; + DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); + IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( + new vfs::InMemoryFileSystem); + Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags, + InMemoryFileSystem); + + const char *EmptyFiles[] = { + "foo.cpp", + "/bin/clang", + "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o", + "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtend.o", + "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtbegin.o", + "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtend.o", + "/usr/lib/arm-linux-gnueabi/crt1.o", + "/usr/lib/arm-linux-gnueabi/crti.o", + "/usr/lib/arm-linux-gnueabi/crtn.o", + "/usr/lib/arm-linux-gnueabihf/crt1.o", + "/usr/lib/arm-linux-gnueabihf/crti.o", + "/usr/lib/arm-linux-gnueabihf/crtn.o", + "/usr/include/arm-linux-gnueabi/.keep", + "/usr/include/arm-linux-gnueabihf/.keep", + "/lib/arm-linux-gnueabi/.keep", + "/lib/arm-linux-gnueabihf/.keep"}; + + for (const char *Path : EmptyFiles) + InMemoryFileSystem->addFile(Path, 0, + llvm::MemoryBuffer::getMemBuffer("\n")); + + std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( + {"-fsyntax-only", "--gcc-toolchain=", "foo.cpp"})); + + std::string S; + { + llvm::raw_string_ostream OS(S); + C->getDefaultToolChain().printVerboseInfo(OS); + } +#if LLVM_ON_WIN32 + std::replace(S.begin(), S.end(), '\\', '/'); +#endif + EXPECT_EQ( + "Found candidate GCC installation: " + "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n" + "Selected GCC installation: /usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n" + "Candidate multilib: .;@m32\n" + "Selected multilib: .;@m32\n", + S); +} + +TEST(ToolChainTest, VFSGCCInstallationRelativeDir) { + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); + + IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); + struct TestDiagnosticConsumer : public DiagnosticConsumer {}; + DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); + IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( + new vfs::InMemoryFileSystem); + Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags, + InMemoryFileSystem); + + const char *EmptyFiles[] = { + "foo.cpp", "/home/test/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o", + "/home/test/include/arm-linux-gnueabi/.keep"}; + + for (const char *Path : EmptyFiles) + InMemoryFileSystem->addFile(Path, 0, + llvm::MemoryBuffer::getMemBuffer("\n")); + + std::unique_ptr<Compilation> C(TheDriver.BuildCompilation( + {"-fsyntax-only", "--gcc-toolchain=", "foo.cpp"})); + + std::string S; + { + llvm::raw_string_ostream OS(S); + C->getDefaultToolChain().printVerboseInfo(OS); + } +#if LLVM_ON_WIN32 + std::replace(S.begin(), S.end(), '\\', '/'); +#endif + EXPECT_EQ("Found candidate GCC installation: " + "/home/test/lib/gcc/arm-linux-gnueabi/4.6.1\n" + "Selected GCC installation: " + "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n" + "Candidate multilib: .;@m32\n" + "Selected multilib: .;@m32\n", + S); +} + +} // end anonymous namespace diff --git a/unittests/Format/CMakeLists.txt b/unittests/Format/CMakeLists.txt index 6d48cf871335c..01af435fffced 100644 --- a/unittests/Format/CMakeLists.txt +++ b/unittests/Format/CMakeLists.txt @@ -8,6 +8,7 @@ add_clang_unittest(FormatTests FormatTestJS.cpp FormatTestProto.cpp FormatTestSelective.cpp + SortIncludesTest.cpp ) target_link_libraries(FormatTests diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index d61dc7f662c2f..6a0506d89732b 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -313,7 +313,7 @@ TEST_F(FormatTest, FormatIfWithoutCompoundStatement) { " f();\n" "}", AllowsMergedIf); - verifyFormat("if (a) {/* Never merge this */\n" + verifyFormat("if (a) { /* Never merge this */\n" " f();\n" "}", AllowsMergedIf); @@ -756,6 +756,9 @@ TEST_F(FormatTest, ShortCaseLabels) { "case 7:\n" " // comment\n" " return;\n" + "case 8:\n" + " x = 8; // comment\n" + " break;\n" "default: y = 1; break;\n" "}", Style); @@ -1194,6 +1197,13 @@ TEST_F(FormatTest, AlignsBlockComments) { "comment */")); } +TEST_F(FormatTest, CommentReflowingCanBeTurnedOff) { + FormatStyle Style = getLLVMStyleWithColumns(20); + Style.ReflowComments = false; + verifyFormat("// aaaaaaaaa aaaaaaaaaa aaaaaaaaaa", Style); + verifyFormat("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa */", Style); +} + TEST_F(FormatTest, CorrectlyHandlesLengthOfBlockComments) { EXPECT_EQ("double *x; /* aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa */", @@ -1864,11 +1874,21 @@ TEST_F(FormatTest, UnderstandsAccessSpecifiers) { "};"); verifyFormat("class A {\n" "public slots:\n" - " void f() {}\n" + " void f1() {}\n" "public Q_SLOTS:\n" - " void f() {}\n" + " void f2() {}\n" + "protected slots:\n" + " void f3() {}\n" + "protected Q_SLOTS:\n" + " void f4() {}\n" + "private slots:\n" + " void f5() {}\n" + "private Q_SLOTS:\n" + " void f6() {}\n" "signals:\n" - " void g();\n" + " void g1();\n" + "Q_SIGNALS:\n" + " void g2();\n" "};"); // Don't interpret 'signals' the wrong way. @@ -2189,6 +2209,13 @@ TEST_F(FormatTest, FormatsNamespaces) { "} // my_namespace\n" "#endif // HEADER_GUARD")); + EXPECT_EQ("namespace A::B {\n" + "class C {};\n" + "}", + format("namespace A::B {\n" + "class C {};\n" + "}")); + FormatStyle Style = getLLVMStyle(); Style.NamespaceIndentation = FormatStyle::NI_All; EXPECT_EQ("namespace out {\n" @@ -2329,13 +2356,16 @@ TEST_F(FormatTest, IncompleteTryCatchBlocks) { TEST_F(FormatTest, FormatTryCatchBraceStyles) { FormatStyle Style = getLLVMStyle(); - Style.BreakBeforeBraces = FormatStyle::BS_Attach; - verifyFormat("try {\n" - " // something\n" - "} catch (...) {\n" - " // something\n" - "}", - Style); + for (auto BraceStyle : {FormatStyle::BS_Attach, FormatStyle::BS_Mozilla, + FormatStyle::BS_WebKit}) { + Style.BreakBeforeBraces = BraceStyle; + verifyFormat("try {\n" + " // something\n" + "} catch (...) {\n" + " // something\n" + "}", + Style); + } Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup; verifyFormat("try {\n" " // something\n" @@ -2378,6 +2408,15 @@ TEST_F(FormatTest, FormatTryCatchBraceStyles) { " // something\n" " }", Style); + Style.BreakBeforeBraces = FormatStyle::BS_Custom; + Style.BraceWrapping.BeforeCatch = true; + verifyFormat("try {\n" + " // something\n" + "}\n" + "catch (...) {\n" + " // something\n" + "}", + Style); } TEST_F(FormatTest, FormatObjCTryCatch) { @@ -2905,6 +2944,8 @@ TEST_F(FormatTest, MacroCallsWithoutTrailingSemicolon) { " EXCLUSIVE_LOCK_FUNCTION(mu_);\n" "};", getLLVMStyleWithColumns(40))); + + verifyFormat("MACRO(>)"); } TEST_F(FormatTest, LayoutMacroDefinitionsStatementsSpanningBlocks) { @@ -3073,10 +3114,12 @@ TEST_F(FormatTest, LayoutBlockInsideParens) { " int i;\n" " int j;\n" "});"); - verifyFormat("functionCall({\n" - " int i;\n" - " int j;\n" - "}, aaaa, bbbb, cccc);"); + verifyFormat("functionCall(\n" + " {\n" + " int i;\n" + " int j;\n" + " },\n" + " aaaa, bbbb, cccc);"); verifyFormat("functionA(functionB({\n" " int i;\n" " int j;\n" @@ -3183,9 +3226,11 @@ TEST_F(FormatTest, LayoutNestedBlocks) { "});"); FormatStyle Style = getGoogleStyle(); Style.ColumnLimit = 45; - verifyFormat("Debug(aaaaa, {\n" - " if (aaaaaaaaaaaaaaaaaaaaaaaa) return;\n" - "}, a);", + verifyFormat("Debug(aaaaa,\n" + " {\n" + " if (aaaaaaaaaaaaaaaaaaaaaaaa) return;\n" + " },\n" + " a);", Style); verifyFormat("SomeFunction({MACRO({ return output; }), b});"); @@ -3296,7 +3341,7 @@ TEST_F(FormatTest, LineBreakingInBinaryExpressions) { verifyFormat("aaaaaa = aaaaaaa(aaaaaaa, // break\n" " aaaaaa) >>\n" " bbbbbb;"); - verifyFormat("Whitespaces.addUntouchableComment(\n" + verifyFormat("aa = Whitespaces.addUntouchableComment(\n" " SourceMgr.getSpellingColumnNumber(\n" " TheLine.Last->FormatTok.Tok.getLocation()) -\n" " 1);"); @@ -3484,7 +3529,7 @@ TEST_F(FormatTest, NoOperandAlignment) { " * cccccccccccccccccccccccccccccccccccc;", Style); - Style.AlignAfterOpenBracket = false; + Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign; verifyFormat("return (a > b\n" " // comment1\n" " // comment2\n" @@ -3512,6 +3557,10 @@ TEST_F(FormatTest, ConstructorInitializers) { " : Inttializer(FitsOnTheLine) {}", getLLVMStyleWithColumns(43)); + verifyFormat("template <typename T>\n" + "Constructor() : Initializer(FitsOnTheLine) {}", + getLLVMStyleWithColumns(45)); + verifyFormat( "SomeClass::Constructor()\n" " : aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaaaa(aaaaaaaaaaaa) {}"); @@ -3524,6 +3573,9 @@ TEST_F(FormatTest, ConstructorInitializers) { "SomeClass::Constructor()\n" " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n" " aaaaaaaaaaaaaaa(aaaaaaaaaaaa) {}"); + verifyFormat("Constructor(aaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" + " aaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n" + " : aaaaaaaaaa(aaaaaa) {}"); verifyFormat("Constructor()\n" " : aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa),\n" @@ -3581,6 +3633,11 @@ TEST_F(FormatTest, ConstructorInitializers) { " : aaaaa(aaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaa,\n" " aaaaaaaaaaaaaaaaaaaaaa) {}", OnePerLine); + OnePerLine.ColumnLimit = 60; + verifyFormat("Constructor()\n" + " : aaaaaaaaaaaaaaaaaaaa(a),\n" + " bbbbbbbbbbbbbbbbbbbbbbbb(b) {}", + OnePerLine); EXPECT_EQ("Constructor()\n" " : // Comment forcing unwanted break.\n" @@ -3893,6 +3950,8 @@ TEST_F(FormatTest, BreaksFunctionDeclarationsWithTrailingTokens) { TEST_F(FormatTest, FunctionAnnotations) { verifyFormat("DEPRECATED(\"Use NewClass::NewFunction instead.\")\n" + "int OldFunction(const string ¶meter) {}"); + verifyFormat("DEPRECATED(\"Use NewClass::NewFunction instead.\")\n" "string OldFunction(const string ¶meter) {}"); verifyFormat("template <typename T>\n" "DEPRECATED(\"Use NewClass::NewFunction instead.\")\n" @@ -4038,7 +4097,8 @@ TEST_F(FormatTest, FormatsOneParameterPerLineIfNecessary) { verifyFormat("std::vector<aaaaaaaaaaaaaaaaaaaaaaa,\n" " aaaaaaaaaaaaaaaaaaaaaaa,\n" - " aaaaaaaaaaaaaaaaaaaaaaa> aaaaaaaaaaaaaaaaaa;", + " aaaaaaaaaaaaaaaaaaaaaaa>\n" + " aaaaaaaaaaaaaaaaaa;", NoBinPacking); verifyFormat("a(\"a\"\n" " \"a\",\n" @@ -4097,10 +4157,14 @@ TEST_F(FormatTest, FormatsBuilderPattern) { verifyFormat("return aaaaaaaaaaaaaaaaa->aaaaa().aaaaaaaaaaaaa().aaaaaa() <\n" " aaaaaaaaaaaaaaa->aaaaa().aaaaaaaaaaaaa().aaaaaa();"); verifyFormat( - "aaaaaaa->aaaaaaa->aaaaaaaaaaaaaaaa(\n" + "aaaaaaa->aaaaaaa->aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n" " ->aaaaaaaa(aaaaaaaaaaaaaaa);"); verifyFormat( + "aaaaaaa->aaaaaaa\n" + " ->aaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n" + " ->aaaaaaaa(aaaaaaaaaaaaaaa);"); + verifyFormat( "aaaaaaaaaaaaaaaaaaa()->aaaaaa(bbbbb)->aaaaaaaaaaaaaaaaaaa( // break\n" " aaaaaaaaaaaaaa);"); verifyFormat( @@ -4164,6 +4228,12 @@ TEST_F(FormatTest, FormatsBuilderPattern) { // Prefer not to break after empty parentheses. verifyFormat("FirstToken->WhitespaceRange.getBegin().getLocWithOffset(\n" " First->LastNewlineOffset);"); + + // Prefer not to create "hanging" indents. + verifyFormat( + "return !soooooooooooooome_map\n" + " .insert(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n" + " .second;"); } TEST_F(FormatTest, BreaksAccordingToOperatorPrecedence) { @@ -4279,7 +4349,7 @@ TEST_F(FormatTest, AlignsAfterOpenBracket) { "SomeLongVariableName->someFunction(foooooooo(aaaaaaaaaaaaaaa,\n" " aaaaaaaaaaaaaaaaaaaaa));"); FormatStyle Style = getLLVMStyle(); - Style.AlignAfterOpenBracket = false; + Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign; verifyFormat("void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" " aaaaaaaaaaa aaaaaaaa, aaaaaaaaa aaaaaaa) {}", Style); @@ -4301,6 +4371,26 @@ TEST_F(FormatTest, AlignsAfterOpenBracket) { "SomeLongVariableName->someFunction(foooooooo(aaaaaaaaaaaaaaa,\n" " aaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa));", Style); + + Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak; + Style.BinPackArguments = false; + Style.BinPackParameters = false; + verifyFormat("void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" + " aaaaaaaaaaa aaaaaaaa,\n" + " aaaaaaaaa aaaaaaa,\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}", + Style); + verifyFormat("SomeLongVariableName->someVeryLongFunctionName(\n" + " aaaaaaaaaaa aaaaaaaaa,\n" + " aaaaaaaaaaa aaaaaaaaa,\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);", + Style); + verifyFormat("SomeLongVariableName->someFunction(\n" + " foooooooo(\n" + " aaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa));", + Style); } TEST_F(FormatTest, ParenthesesAndOperandAlignment) { @@ -4308,17 +4398,17 @@ TEST_F(FormatTest, ParenthesesAndOperandAlignment) { verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n" " bbbbbbbbbbbbbbbbbbbbbb);", Style); - Style.AlignAfterOpenBracket = true; + Style.AlignAfterOpenBracket = FormatStyle::BAS_Align; Style.AlignOperands = false; verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n" " bbbbbbbbbbbbbbbbbbbbbb);", Style); - Style.AlignAfterOpenBracket = false; + Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign; Style.AlignOperands = true; verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n" " bbbbbbbbbbbbbbbbbbbbbb);", Style); - Style.AlignAfterOpenBracket = false; + Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign; Style.AlignOperands = false; verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n" " bbbbbbbbbbbbbbbbbbbbbb);", @@ -4642,28 +4732,82 @@ TEST_F(FormatTest, AlignsStringLiterals) { " \"c\";"); } -TEST_F(FormatTest, DefinitionReturnTypeBreakingStyle) { +TEST_F(FormatTest, ReturnTypeBreakingStyle) { FormatStyle Style = getLLVMStyle(); - Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_TopLevel; - verifyFormat("class C {\n" + // No declarations or definitions should be moved to own line. + Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; + verifyFormat("class A {\n" " int f() { return 1; }\n" + " int g();\n" + "};\n" + "int f() { return 1; }\n" + "int g();\n", + Style); + + // All declarations and definitions should have the return type moved to its + // own + // line. + Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_All; + verifyFormat("class E {\n" + " int\n" + " f() {\n" + " return 1;\n" + " }\n" + " int\n" + " g();\n" "};\n" "int\n" "f() {\n" " return 1;\n" - "}", + "}\n" + "int\n" + "g();\n", Style); - Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All; + + // Top-level definitions, and no kinds of declarations should have the + // return type moved to its own line. + Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevelDefinitions; + verifyFormat("class B {\n" + " int f() { return 1; }\n" + " int g();\n" + "};\n" + "int\n" + "f() {\n" + " return 1;\n" + "}\n" + "int g();\n", + Style); + + // Top-level definitions and declarations should have the return type moved + // to its own line. + Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevel; verifyFormat("class C {\n" + " int f() { return 1; }\n" + " int g();\n" + "};\n" + "int\n" + "f() {\n" + " return 1;\n" + "}\n" + "int\n" + "g();\n", + Style); + + // All definitions should have the return type moved to its own line, but no + // kinds of declarations. + Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions; + verifyFormat("class D {\n" " int\n" " f() {\n" " return 1;\n" " }\n" + " int g();\n" "};\n" "int\n" "f() {\n" " return 1;\n" - "}", + "}\n" + "int g();\n", Style); verifyFormat("const char *\n" "f(void) {\n" // Break here. @@ -4678,6 +4822,32 @@ TEST_F(FormatTest, DefinitionReturnTypeBreakingStyle) { "}\n" "template <class T> T *f(T &c);\n", // No break here. Style); + verifyFormat("class C {\n" + " int\n" + " operator+() {\n" + " return 1;\n" + " }\n" + " int\n" + " operator()() {\n" + " return 1;\n" + " }\n" + "};\n", + Style); + verifyFormat("void\n" + "A::operator()() {}\n" + "void\n" + "A::operator>>() {}\n" + "void\n" + "A::operator+() {}\n", + Style); + verifyFormat("void *operator new(std::size_t s);", // No break here. + Style); + verifyFormat("void *\n" + "operator new(std::size_t s) {}", + Style); + verifyFormat("void *\n" + "operator delete[](void *ptr) {}", + Style); Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup; verifyFormat("const char *\n" "f(void)\n" // Break here. @@ -5135,6 +5305,8 @@ TEST_F(FormatTest, UnderstandsTemplateParameters) { EXPECT_EQ("A<A<A<A>>> a;", format("A<A<A<A>> > a;", getGoogleStyle())); EXPECT_EQ("A<::A<int>> a;", format("A< ::A<int>> a;", getGoogleStyle())); EXPECT_EQ("A<::A<int>> a;", format("A<::A<int> > a;", getGoogleStyle())); + EXPECT_EQ("auto x = [] { A<A<A<A>>> a; };", + format("auto x=[]{A<A<A<A> >> a;};", getGoogleStyle())); verifyFormat("A<A>> a;", getChromiumStyle(FormatStyle::LK_Cpp)); @@ -5280,36 +5452,44 @@ TEST_F(FormatTest, UnderstandsOverloadedOperators) { verifyGoogleFormat("operator ::A();"); verifyFormat("using A::operator+;"); + verifyFormat("inline A operator^(const A &lhs, const A &rhs) {}\n" + "int i;"); } TEST_F(FormatTest, UnderstandsFunctionRefQualification) { - verifyFormat("Deleted &operator=(const Deleted &)& = default;"); - verifyFormat("Deleted &operator=(const Deleted &)&& = delete;"); - verifyFormat("SomeType MemberFunction(const Deleted &)& = delete;"); - verifyFormat("SomeType MemberFunction(const Deleted &)&& = delete;"); - verifyFormat("Deleted &operator=(const Deleted &)&;"); - verifyFormat("Deleted &operator=(const Deleted &)&&;"); - verifyFormat("SomeType MemberFunction(const Deleted &)&;"); - verifyFormat("SomeType MemberFunction(const Deleted &)&&;"); + verifyFormat("Deleted &operator=(const Deleted &) & = default;"); + verifyFormat("Deleted &operator=(const Deleted &) && = delete;"); + verifyFormat("SomeType MemberFunction(const Deleted &) & = delete;"); + verifyFormat("SomeType MemberFunction(const Deleted &) && = delete;"); + verifyFormat("Deleted &operator=(const Deleted &) &;"); + verifyFormat("Deleted &operator=(const Deleted &) &&;"); + verifyFormat("SomeType MemberFunction(const Deleted &) &;"); + verifyFormat("SomeType MemberFunction(const Deleted &) &&;"); + verifyFormat("SomeType MemberFunction(const Deleted &) && {}"); + verifyFormat("SomeType MemberFunction(const Deleted &) && final {}"); + verifyFormat("SomeType MemberFunction(const Deleted &) && override {}"); - verifyGoogleFormat("Deleted& operator=(const Deleted&)& = default;"); - verifyGoogleFormat("SomeType MemberFunction(const Deleted&)& = delete;"); - verifyGoogleFormat("Deleted& operator=(const Deleted&)&;"); - verifyGoogleFormat("SomeType MemberFunction(const Deleted&)&;"); + FormatStyle AlignLeft = getLLVMStyle(); + AlignLeft.PointerAlignment = FormatStyle::PAS_Left; + verifyFormat("Deleted& operator=(const Deleted&) & = default;", AlignLeft); + verifyFormat("SomeType MemberFunction(const Deleted&) & = delete;", + AlignLeft); + verifyFormat("Deleted& operator=(const Deleted&) &;", AlignLeft); + verifyFormat("SomeType MemberFunction(const Deleted&) &;", AlignLeft); FormatStyle Spaces = getLLVMStyle(); Spaces.SpacesInCStyleCastParentheses = true; - verifyFormat("Deleted &operator=(const Deleted &)& = default;", Spaces); - verifyFormat("SomeType MemberFunction(const Deleted &)& = delete;", Spaces); - verifyFormat("Deleted &operator=(const Deleted &)&;", Spaces); - verifyFormat("SomeType MemberFunction(const Deleted &)&;", Spaces); + verifyFormat("Deleted &operator=(const Deleted &) & = default;", Spaces); + verifyFormat("SomeType MemberFunction(const Deleted &) & = delete;", Spaces); + verifyFormat("Deleted &operator=(const Deleted &) &;", Spaces); + verifyFormat("SomeType MemberFunction(const Deleted &) &;", Spaces); Spaces.SpacesInCStyleCastParentheses = false; Spaces.SpacesInParentheses = true; - verifyFormat("Deleted &operator=( const Deleted & )& = default;", Spaces); - verifyFormat("SomeType MemberFunction( const Deleted & )& = delete;", Spaces); - verifyFormat("Deleted &operator=( const Deleted & )&;", Spaces); - verifyFormat("SomeType MemberFunction( const Deleted & )&;", Spaces); + verifyFormat("Deleted &operator=( const Deleted & ) & = default;", Spaces); + verifyFormat("SomeType MemberFunction( const Deleted & ) & = delete;", Spaces); + verifyFormat("Deleted &operator=( const Deleted & ) &;", Spaces); + verifyFormat("SomeType MemberFunction( const Deleted & ) &;", Spaces); } TEST_F(FormatTest, UnderstandsNewAndDelete) { @@ -5370,6 +5550,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { verifyIndependentOfContext("return (int **&)a;"); verifyIndependentOfContext("f((*PointerToArray)[10]);"); verifyFormat("void f(Type (*parameter)[10]) {}"); + verifyFormat("void f(Type (¶meter)[10]) {}"); verifyGoogleFormat("return sizeof(int**);"); verifyIndependentOfContext("Type **A = static_cast<Type **>(P);"); verifyGoogleFormat("Type** A = static_cast<Type**>(P);"); @@ -5377,6 +5558,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { verifyFormat("auto PointerBinding = [](const char *S) {};"); verifyFormat("typedef typeof(int(int, int)) *MyFunc;"); verifyFormat("[](const decltype(*a) &value) {}"); + verifyFormat("decltype(a * b) F();"); verifyFormat("#define MACRO() [](A *a) { return 1; }"); verifyIndependentOfContext("typedef void (*f)(int *a);"); verifyIndependentOfContext("int i{a * b};"); @@ -5430,6 +5612,8 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { FormatStyle Left = getLLVMStyle(); Left.PointerAlignment = FormatStyle::PAS_Left; verifyFormat("x = *a(x) = *a(y);", Left); + verifyFormat("for (;; * = b) {\n}", Left); + verifyFormat("return *this += 1;", Left); verifyIndependentOfContext("a = *(x + y);"); verifyIndependentOfContext("a = &(x + y);"); @@ -5513,6 +5697,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { // verifyIndependentOfContext("MACRO(A *a);"); verifyFormat("DatumHandle const *operator->() const { return input_; }"); + verifyFormat("return options != nullptr && operator==(*options);"); EXPECT_EQ("#define OP(x) \\\n" " ostream &operator<<(ostream &s, const A &a) { \\\n" @@ -5558,7 +5743,7 @@ TEST_F(FormatTest, UnderstandsAttributes) { verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa __attribute__((unused))\n" "aaaaaaaaaaaaaaaaaaaaaaa(int i);"); FormatStyle AfterType = getLLVMStyle(); - AfterType.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All; + AfterType.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions; verifyFormat("__attribute__((nodebug)) void\n" "foo() {}\n", AfterType); @@ -5596,6 +5781,15 @@ TEST_F(FormatTest, AdaptivelyFormatsPointersAndReferences) { "int * a;\n" "int * a;", getGoogleStyle())); + EXPECT_EQ("auto x = [] {\n" + " int *a;\n" + " int *a;\n" + " int *a;\n" + "};", + format("auto x=[]{int *a;\n" + "int * a;\n" + "int * a;};", + getGoogleStyle())); } TEST_F(FormatTest, UnderstandsRvalueReferences) { @@ -5700,6 +5894,8 @@ TEST_F(FormatTest, FormatsCasts) { verifyFormat("virtual void foo(int *a, char *) const;"); verifyFormat("int a = sizeof(int *) + b;"); verifyFormat("int a = alignof(int *) + b;", getGoogleStyle()); + verifyFormat("bool b = f(g<int>) && c;"); + verifyFormat("typedef void (*f)(int i) func;"); verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *foo = (aaaaaaaaaaaaaaaaa *)\n" " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;"); @@ -5732,6 +5928,7 @@ TEST_F(FormatTest, FormatsFunctionTypes) { verifyFormat("#define DEREF_AND_CALL_F(x) f(*x)"); verifyFormat("some_var = function(*some_pointer_var)[0];"); verifyFormat("void f() { function(*some_pointer_var)[0] = 10; }"); + verifyFormat("int x = f(&h)();"); } TEST_F(FormatTest, FormatsPointersToArrayTypes) { @@ -5848,6 +6045,8 @@ TEST_F(FormatTest, BreaksLongDeclarations) { TEST_F(FormatTest, FormatsArrays) { verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaa[aaaaaaaaaaaaaaaaaaaaaaaaa]\n" " [bbbbbbbbbbbbbbbbbbbbbbbbb] = c;"); + verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaa[aaaaaaaaaaa(aaaaaaaaaaaa)]\n" + " [bbbbbbbbbbb(bbbbbbbbbbbb)] = c;"); verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" " [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb] = ccccccccccc;"); verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" @@ -6098,6 +6297,7 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) { " void f() { int i{2}; }\n" " };\n" "};"); + verifyFormat("#define A {a, a},"); // In combination with BinPackArguments = false. FormatStyle NoBinPacking = getLLVMStyle(); @@ -6307,6 +6507,11 @@ TEST_F(FormatTest, FormatsBracedListsInColumnLayout) { " 1111111111, 2222222222, 33333333333, 4444444444, //\n" " 111111111, 222222222, 3333333333, 444444444, //\n" " 11111111, 22222222, 333333333, 44444444};"); + // Trailing comment in the last line. + verifyFormat("int aaaaa[] = {\n" + " 1, 2, 3, // comment\n" + " 4, 5, 6 // comment\n" + "};"); // With nested lists, we should either format one item per line or all nested // lists one on line. @@ -6331,6 +6536,12 @@ TEST_F(FormatTest, FormatsBracedListsInColumnLayout) { " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb};"); verifyNoCrash("a<,"); + + // No braced initializer here. + verifyFormat("void f() {\n" + " struct Dummy {};\n" + " f(v);\n" + "}"); } TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) { @@ -6509,6 +6720,8 @@ TEST_F(FormatTest, DoNotInterfereWithErrorAndWarning) { TEST_F(FormatTest, FormatHashIfExpressions) { verifyFormat("#if AAAA && BBBB"); + verifyFormat("#if (AAAA && BBBB)"); + verifyFormat("#elif (AAAA && BBBB)"); // FIXME: Come up with a better indentation for #elif. verifyFormat( "#if !defined(AAAAAAA) && (defined CCCCCC || defined DDDDDD) && \\\n" @@ -7074,6 +7287,22 @@ TEST_F(FormatTest, FormatObjCMethodDeclarations) { " y:(id<yyyyyyyyyyyyyyyyyyyy>)y\n" " NS_DESIGNATED_INITIALIZER;", getLLVMStyleWithColumns(60)); + + // Continuation indent width should win over aligning colons if the function + // name is long. + FormatStyle continuationStyle = getGoogleStyle(); + continuationStyle.ColumnLimit = 40; + continuationStyle.IndentWrappedFunctionNames = true; + verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n" + " dontAlignNamef:(NSRect)theRect {\n" + "}", + continuationStyle); + + // Make sure we don't break aligning for short parameter names. + verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n" + " aShortf:(NSRect)theRect {\n" + "}", + continuationStyle); } TEST_F(FormatTest, FormatObjCMethodExpr) { @@ -7238,8 +7467,8 @@ TEST_F(FormatTest, FormatObjCMethodExpr) { " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa];"); verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaa[aaaaaaaaaaaaaaaaaaaaa]\n" " aaaaaaaaaaaaaaaaaaaaaa];"); - verifyFormat("[call aaaaaaaa.aaaaaa.aaaaaaaa.aaaaaaaa.aaaaaaaa.aaaaaaaa\n" - " .aaaaaaaa];", // FIXME: Indentation seems off. + verifyFormat("[call aaaaaaaa.aaaaaa.aaaaaaaa.aaaaaaaa.aaaaaaaa\n" + " .aaaaaaaa.aaaaaaaa];", // FIXME: Indentation seems off. getLLVMStyleWithColumns(60)); verifyFormat( @@ -7345,6 +7574,19 @@ TEST_F(FormatTest, ObjCSnippets) { "@import baz;"); } +TEST_F(FormatTest, ObjCForIn) { + verifyFormat("- (void)test {\n" + " for (NSString *n in arrayOfStrings) {\n" + " foo(n);\n" + " }\n" + "}"); + verifyFormat("- (void)test {\n" + " for (NSString *n in (__bridge NSArray *)arrayOfStrings) {\n" + " foo(n);\n" + " }\n" + "}"); +} + TEST_F(FormatTest, ObjCLiterals) { verifyFormat("@\"String\""); verifyFormat("@1"); @@ -7417,6 +7659,13 @@ TEST_F(FormatTest, ObjCDictLiterals) { " bbbbbbbbbbbbbbbbbb : bbbbb,\n" " cccccccccccccccc : ccccccccccccccc\n" " }];"); + + // Ensure that casts before the key are kept on the same line as the key. + verifyFormat( + "NSDictionary *d = @{\n" + " (aaaaaaaa id)aaaaaaaaa : (aaaaaaaa id)aaaaaaaaaaaaaaaaaaaaaaaa,\n" + " (aaaaaaaa id)aaaaaaaaaaaaaa : (aaaaaaaa id)aaaaaaaaaaaaaa,\n" + "};"); } TEST_F(FormatTest, ObjCArrayLiterals) { @@ -7625,6 +7874,13 @@ TEST_F(FormatTest, BreaksStringLiterals) { format("#define A \"some text other\";", AlignLeft)); } +TEST_F(FormatTest, FullyRemoveEmptyLines) { + FormatStyle NoEmptyLines = getLLVMStyleWithColumns(80); + NoEmptyLines.MaxEmptyLinesToKeep = 0; + EXPECT_EQ("int i = a(b());", + format("int i=a(\n\n b(\n\n\n )\n\n);", NoEmptyLines)); +} + TEST_F(FormatTest, BreaksStringLiteralsWithTabs) { EXPECT_EQ( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" @@ -8028,11 +8284,13 @@ TEST_F(FormatTest, ConfigurableUseOfTab) { "};", Tab); verifyFormat("{\n" - "\tQ({\n" - "\t\tint a;\n" - "\t\tsomeFunction(aaaaaaaa,\n" - "\t\t bbbbbbb);\n" - "\t}, p);\n" + "\tQ(\n" + "\t {\n" + "\t\t int a;\n" + "\t\t someFunction(aaaaaaaa,\n" + "\t\t bbbbbbb);\n" + "\t },\n" + "\t p);\n" "}", Tab); EXPECT_EQ("{\n" @@ -8210,6 +8468,8 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeParens) { verifyFormat("static_assert(sizeof(char) == 1, \"Impossible!\");", NoSpace); verifyFormat("int f() throw(Deprecated);", NoSpace); verifyFormat("typedef void (*cb)(int);", NoSpace); + verifyFormat("T A::operator()();", NoSpace); + verifyFormat("X A::operator++(T);", NoSpace); FormatStyle Space = getLLVMStyle(); Space.SpaceBeforeParens = FormatStyle::SBPO_Always; @@ -8255,6 +8515,8 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeParens) { verifyFormat("static_assert (sizeof (char) == 1, \"Impossible!\");", Space); verifyFormat("int f () throw (Deprecated);", Space); verifyFormat("typedef void (*cb) (int);", Space); + verifyFormat("T A::operator() ();", Space); + verifyFormat("X A::operator++ (T);", Space); } TEST_F(FormatTest, ConfigurableSpacesInParentheses) { @@ -8264,6 +8526,8 @@ TEST_F(FormatTest, ConfigurableSpacesInParentheses) { verifyFormat("call( x, y, z );", Spaces); verifyFormat("call();", Spaces); verifyFormat("std::function<void( int, int )> callback;", Spaces); + verifyFormat("void inFunction() { std::function<void( int, int )> fct; }", + Spaces); verifyFormat("while ( (bool)1 )\n" " continue;", Spaces); @@ -8439,6 +8703,10 @@ TEST_F(FormatTest, AlignConsecutiveAssignments) { "int oneTwoThree = 123;\n" "int oneTwo = 12;", Alignment); + verifyFormat("int oneTwoThree = 123;\n" + "int oneTwo = 12;\n" + "method();\n", + Alignment); verifyFormat("int oneTwoThree = 123; // comment\n" "int oneTwo = 12; // comment", Alignment); @@ -8502,7 +8770,7 @@ TEST_F(FormatTest, AlignConsecutiveAssignments) { Alignment); verifyFormat("class C {\n" "public:\n" - " int i = 1;\n" + " int i = 1;\n" " virtual void f() = 0;\n" "};", Alignment); @@ -8531,6 +8799,19 @@ TEST_F(FormatTest, AlignConsecutiveAssignments) { " someLooooooooooooooooongFunction();\n" "int j = 2;", Alignment); + + verifyFormat("auto lambda = []() {\n" + " auto i = 0;\n" + " return 0;\n" + "};\n" + "int i = 0;\n" + "auto v = type{\n" + " i = 1, //\n" + " (i = 2), //\n" + " i = 3 //\n" + "};", + Alignment); + // FIXME: Should align all three assignments verifyFormat( "int i = 1;\n" @@ -8538,6 +8819,260 @@ TEST_F(FormatTest, AlignConsecutiveAssignments) { " loooooooooooooooooooooongParameterB);\n" "int j = 2;", Alignment); + + verifyFormat("template <typename T, typename T_0 = very_long_type_name_0,\n" + " typename B = very_long_type_name_1,\n" + " typename T_2 = very_long_type_name_2>\n" + "auto foo() {}\n", + Alignment); + verifyFormat("int a, b = 1;\n" + "int c = 2;\n" + "int dd = 3;\n", + Alignment); + verifyFormat("int aa = ((1 > 2) ? 3 : 4);\n" + "float b[1][] = {{3.f}};\n", + Alignment); +} + +TEST_F(FormatTest, AlignConsecutiveDeclarations) { + FormatStyle Alignment = getLLVMStyle(); + Alignment.AlignConsecutiveDeclarations = false; + verifyFormat("float const a = 5;\n" + "int oneTwoThree = 123;", + Alignment); + verifyFormat("int a = 5;\n" + "float const oneTwoThree = 123;", + Alignment); + + Alignment.AlignConsecutiveDeclarations = true; + verifyFormat("float const a = 5;\n" + "int oneTwoThree = 123;", + Alignment); + verifyFormat("int a = method();\n" + "float const oneTwoThree = 133;", + Alignment); + verifyFormat("int i = 1, j = 10;\n" + "something = 2000;", + Alignment); + verifyFormat("something = 2000;\n" + "int i = 1, j = 10;\n", + Alignment); + verifyFormat("float something = 2000;\n" + "double another = 911;\n" + "int i = 1, j = 10;\n" + "const int *oneMore = 1;\n" + "unsigned i = 2;", + Alignment); + verifyFormat("float a = 5;\n" + "int one = 1;\n" + "method();\n" + "const double oneTwoThree = 123;\n" + "const unsigned int oneTwo = 12;", + Alignment); + verifyFormat("int oneTwoThree{0}; // comment\n" + "unsigned oneTwo; // comment", + Alignment); + EXPECT_EQ("float const a = 5;\n" + "\n" + "int oneTwoThree = 123;", + format("float const a = 5;\n" + "\n" + "int oneTwoThree= 123;", + Alignment)); + EXPECT_EQ("float a = 5;\n" + "int one = 1;\n" + "\n" + "unsigned oneTwoThree = 123;", + format("float a = 5;\n" + "int one = 1;\n" + "\n" + "unsigned oneTwoThree = 123;", + Alignment)); + EXPECT_EQ("float a = 5;\n" + "int one = 1;\n" + "\n" + "unsigned oneTwoThree = 123;\n" + "int oneTwo = 12;", + format("float a = 5;\n" + "int one = 1;\n" + "\n" + "unsigned oneTwoThree = 123;\n" + "int oneTwo = 12;", + Alignment)); + Alignment.AlignConsecutiveAssignments = true; + verifyFormat("float something = 2000;\n" + "double another = 911;\n" + "int i = 1, j = 10;\n" + "const int *oneMore = 1;\n" + "unsigned i = 2;", + Alignment); + verifyFormat("int oneTwoThree = {0}; // comment\n" + "unsigned oneTwo = 0; // comment", + Alignment); + EXPECT_EQ("void SomeFunction(int parameter = 0) {\n" + " int const i = 1;\n" + " int * j = 2;\n" + " int big = 10000;\n" + "\n" + " unsigned oneTwoThree = 123;\n" + " int oneTwo = 12;\n" + " method();\n" + " float k = 2;\n" + " int ll = 10000;\n" + "}", + format("void SomeFunction(int parameter= 0) {\n" + " int const i= 1;\n" + " int *j=2;\n" + " int big = 10000;\n" + "\n" + "unsigned oneTwoThree =123;\n" + "int oneTwo = 12;\n" + " method();\n" + "float k= 2;\n" + "int ll=10000;\n" + "}", + Alignment)); + Alignment.AlignConsecutiveAssignments = false; + Alignment.AlignEscapedNewlinesLeft = true; + verifyFormat("#define A \\\n" + " int aaaa = 12; \\\n" + " float b = 23; \\\n" + " const int ccc = 234; \\\n" + " unsigned dddddddddd = 2345;", + Alignment); + Alignment.AlignEscapedNewlinesLeft = false; + Alignment.ColumnLimit = 30; + verifyFormat("#define A \\\n" + " int aaaa = 12; \\\n" + " float b = 23; \\\n" + " const int ccc = 234; \\\n" + " int dddddddddd = 2345;", + Alignment); + Alignment.ColumnLimit = 80; + verifyFormat("void SomeFunction(int parameter = 1, int i = 2, int j = 3, int " + "k = 4, int l = 5,\n" + " int m = 6) {\n" + " const int j = 10;\n" + " otherThing = 1;\n" + "}", + Alignment); + verifyFormat("void SomeFunction(int parameter = 0) {\n" + " int const i = 1;\n" + " int * j = 2;\n" + " int big = 10000;\n" + "}", + Alignment); + verifyFormat("class C {\n" + "public:\n" + " int i = 1;\n" + " virtual void f() = 0;\n" + "};", + Alignment); + verifyFormat("float i = 1;\n" + "if (SomeType t = getSomething()) {\n" + "}\n" + "const unsigned j = 2;\n" + "int big = 10000;", + Alignment); + verifyFormat("float j = 7;\n" + "for (int k = 0; k < N; ++k) {\n" + "}\n" + "unsigned j = 2;\n" + "int big = 10000;\n" + "}", + Alignment); + Alignment.BreakBeforeBinaryOperators = FormatStyle::BOS_All; + verifyFormat("float i = 1;\n" + "LooooooooooongType loooooooooooooooooooooongVariable\n" + " = someLooooooooooooooooongFunction();\n" + "int j = 2;", + Alignment); + Alignment.BreakBeforeBinaryOperators = FormatStyle::BOS_None; + verifyFormat("int i = 1;\n" + "LooooooooooongType loooooooooooooooooooooongVariable =\n" + " someLooooooooooooooooongFunction();\n" + "int j = 2;", + Alignment); + + Alignment.AlignConsecutiveAssignments = true; + verifyFormat("auto lambda = []() {\n" + " auto ii = 0;\n" + " float j = 0;\n" + " return 0;\n" + "};\n" + "int i = 0;\n" + "float i2 = 0;\n" + "auto v = type{\n" + " i = 1, //\n" + " (i = 2), //\n" + " i = 3 //\n" + "};", + Alignment); + Alignment.AlignConsecutiveAssignments = false; + + // FIXME: Should align all three declarations + verifyFormat( + "int i = 1;\n" + "SomeType a = SomeFunction(looooooooooooooooooooooongParameterA,\n" + " loooooooooooooooooooooongParameterB);\n" + "int j = 2;", + Alignment); + + // Test interactions with ColumnLimit and AlignConsecutiveAssignments: + // We expect declarations and assignments to align, as long as it doesn't + // exceed the column limit, starting a new alignemnt sequence whenever it + // happens. + Alignment.AlignConsecutiveAssignments = true; + Alignment.ColumnLimit = 30; + verifyFormat("float ii = 1;\n" + "unsigned j = 2;\n" + "int someVerylongVariable = 1;\n" + "AnotherLongType ll = 123456;\n" + "VeryVeryLongType k = 2;\n" + "int myvar = 1;", + Alignment); + Alignment.ColumnLimit = 80; + Alignment.AlignConsecutiveAssignments = false; + + verifyFormat( + "template <typename LongTemplate, typename VeryLongTemplateTypeName,\n" + " typename LongType, typename B>\n" + "auto foo() {}\n", + Alignment); + verifyFormat("float a, b = 1;\n" + "int c = 2;\n" + "int dd = 3;\n", + Alignment); + verifyFormat("int aa = ((1 > 2) ? 3 : 4);\n" + "float b[1][] = {{3.f}};\n", + Alignment); + Alignment.AlignConsecutiveAssignments = true; + verifyFormat("float a, b = 1;\n" + "int c = 2;\n" + "int dd = 3;\n", + Alignment); + verifyFormat("int aa = ((1 > 2) ? 3 : 4);\n" + "float b[1][] = {{3.f}};\n", + Alignment); + Alignment.AlignConsecutiveAssignments = false; + + Alignment.ColumnLimit = 30; + Alignment.BinPackParameters = false; + verifyFormat("void foo(float a,\n" + " float b,\n" + " int c,\n" + " uint32_t *d) {\n" + " int * e = 0;\n" + " float f = 0;\n" + " double g = 0;\n" + "}\n" + "void bar(ino_t a,\n" + " int b,\n" + " uint32_t *c,\n" + " bool d) {}\n", + Alignment); + Alignment.BinPackParameters = true; + Alignment.ColumnLimit = 80; } TEST_F(FormatTest, LinuxBraceBreaking) { @@ -8552,6 +9087,8 @@ TEST_F(FormatTest, LinuxBraceBreaking) { " if (true) {\n" " a();\n" " b();\n" + " } else {\n" + " a();\n" " }\n" " }\n" " void g() { return; }\n" @@ -8994,6 +9531,45 @@ TEST_F(FormatTest, GNUBraceBreaking) { "#endif", GNUBraceStyle); } + +TEST_F(FormatTest, WebKitBraceBreaking) { + FormatStyle WebKitBraceStyle = getLLVMStyle(); + WebKitBraceStyle.BreakBeforeBraces = FormatStyle::BS_WebKit; + verifyFormat("namespace a {\n" + "class A {\n" + " void f()\n" + " {\n" + " if (true) {\n" + " a();\n" + " b();\n" + " }\n" + " }\n" + " void g() { return; }\n" + "};\n" + "enum E {\n" + " A,\n" + " // foo\n" + " B,\n" + " C\n" + "};\n" + "struct B {\n" + " int x;\n" + "};\n" + "}\n", + WebKitBraceStyle); + verifyFormat("struct S {\n" + " int Type;\n" + " union {\n" + " int x;\n" + " double y;\n" + " } Value;\n" + " class C {\n" + " MyFavoriteType Value;\n" + " } Class;\n" + "};\n", + WebKitBraceStyle); +} + TEST_F(FormatTest, CatchExceptionReferenceBinding) { verifyFormat("void f() {\n" " try {\n" @@ -9119,6 +9695,20 @@ TEST_F(FormatTest, GetsCorrectBasedOnStyle) { #define CHECK_PARSE_BOOL(FIELD) CHECK_PARSE_BOOL_FIELD(FIELD, #FIELD) +#define CHECK_PARSE_NESTED_BOOL_FIELD(STRUCT, FIELD, CONFIG_NAME) \ + Style.STRUCT.FIELD = false; \ + EXPECT_EQ(0, \ + parseConfiguration(#STRUCT ":\n " CONFIG_NAME ": true", &Style) \ + .value()); \ + EXPECT_TRUE(Style.STRUCT.FIELD); \ + EXPECT_EQ(0, \ + parseConfiguration(#STRUCT ":\n " CONFIG_NAME ": false", &Style) \ + .value()); \ + EXPECT_FALSE(Style.STRUCT.FIELD); + +#define CHECK_PARSE_NESTED_BOOL(STRUCT, FIELD) \ + CHECK_PARSE_NESTED_BOOL_FIELD(STRUCT, FIELD, #FIELD) + #define CHECK_PARSE(TEXT, FIELD, VALUE) \ EXPECT_NE(VALUE, Style.FIELD); \ EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value()); \ @@ -9127,30 +9717,33 @@ TEST_F(FormatTest, GetsCorrectBasedOnStyle) { TEST_F(FormatTest, ParsesConfigurationBools) { FormatStyle Style = {}; Style.Language = FormatStyle::LK_Cpp; - CHECK_PARSE_BOOL(AlignAfterOpenBracket); CHECK_PARSE_BOOL(AlignEscapedNewlinesLeft); CHECK_PARSE_BOOL(AlignOperands); CHECK_PARSE_BOOL(AlignTrailingComments); CHECK_PARSE_BOOL(AlignConsecutiveAssignments); + CHECK_PARSE_BOOL(AlignConsecutiveDeclarations); CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine); CHECK_PARSE_BOOL(AllowShortBlocksOnASingleLine); CHECK_PARSE_BOOL(AllowShortCaseLabelsOnASingleLine); CHECK_PARSE_BOOL(AllowShortIfStatementsOnASingleLine); CHECK_PARSE_BOOL(AllowShortLoopsOnASingleLine); CHECK_PARSE_BOOL(AlwaysBreakTemplateDeclarations); - CHECK_PARSE_BOOL(BinPackParameters); CHECK_PARSE_BOOL(BinPackArguments); + CHECK_PARSE_BOOL(BinPackParameters); CHECK_PARSE_BOOL(BreakBeforeTernaryOperators); CHECK_PARSE_BOOL(BreakConstructorInitializersBeforeComma); CHECK_PARSE_BOOL(ConstructorInitializerAllOnOneLineOrOnePerLine); CHECK_PARSE_BOOL(DerivePointerAlignment); CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding"); + CHECK_PARSE_BOOL(DisableFormat); CHECK_PARSE_BOOL(IndentCaseLabels); CHECK_PARSE_BOOL(IndentWrappedFunctionNames); CHECK_PARSE_BOOL(KeepEmptyLinesAtTheStartOfBlocks); CHECK_PARSE_BOOL(ObjCSpaceAfterProperty); CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList); CHECK_PARSE_BOOL(Cpp11BracedListStyle); + CHECK_PARSE_BOOL(ReflowComments); + CHECK_PARSE_BOOL(SortIncludes); CHECK_PARSE_BOOL(SpacesInParentheses); CHECK_PARSE_BOOL(SpacesInSquareBrackets); CHECK_PARSE_BOOL(SpacesInAngles); @@ -9159,6 +9752,18 @@ TEST_F(FormatTest, ParsesConfigurationBools) { CHECK_PARSE_BOOL(SpacesInCStyleCastParentheses); CHECK_PARSE_BOOL(SpaceAfterCStyleCast); CHECK_PARSE_BOOL(SpaceBeforeAssignmentOperators); + + CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterClass); + CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterControlStatement); + CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterEnum); + CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterFunction); + CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterNamespace); + CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterObjCDeclaration); + CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterStruct); + CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterUnion); + CHECK_PARSE_NESTED_BOOL(BraceWrapping, BeforeCatch); + CHECK_PARSE_NESTED_BOOL(BraceWrapping, BeforeElse); + CHECK_PARSE_NESTED_BOOL(BraceWrapping, IndentBraces); } #undef CHECK_PARSE_BOOL @@ -9217,6 +9822,19 @@ TEST_F(FormatTest, ParsesConfiguration) { CHECK_PARSE("BreakBeforeBinaryOperators: true", BreakBeforeBinaryOperators, FormatStyle::BOS_All); + Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak; + CHECK_PARSE("AlignAfterOpenBracket: Align", AlignAfterOpenBracket, + FormatStyle::BAS_Align); + CHECK_PARSE("AlignAfterOpenBracket: DontAlign", AlignAfterOpenBracket, + FormatStyle::BAS_DontAlign); + CHECK_PARSE("AlignAfterOpenBracket: AlwaysBreak", AlignAfterOpenBracket, + FormatStyle::BAS_AlwaysBreak); + // For backward compatibility: + CHECK_PARSE("AlignAfterOpenBracket: false", AlignAfterOpenBracket, + FormatStyle::BAS_DontAlign); + CHECK_PARSE("AlignAfterOpenBracket: true", AlignAfterOpenBracket, + FormatStyle::BAS_Align); + Style.UseTab = FormatStyle::UT_ForIndentation; CHECK_PARSE("UseTab: Never", UseTab, FormatStyle::UT_Never); CHECK_PARSE("UseTab: ForIndentation", UseTab, FormatStyle::UT_ForIndentation); @@ -9270,6 +9888,23 @@ TEST_F(FormatTest, ParsesConfiguration) { CHECK_PARSE("BreakBeforeBraces: Allman", BreakBeforeBraces, FormatStyle::BS_Allman); CHECK_PARSE("BreakBeforeBraces: GNU", BreakBeforeBraces, FormatStyle::BS_GNU); + CHECK_PARSE("BreakBeforeBraces: WebKit", BreakBeforeBraces, + FormatStyle::BS_WebKit); + CHECK_PARSE("BreakBeforeBraces: Custom", BreakBeforeBraces, + FormatStyle::BS_Custom); + + Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_All; + CHECK_PARSE("AlwaysBreakAfterReturnType: None", AlwaysBreakAfterReturnType, + FormatStyle::RTBS_None); + CHECK_PARSE("AlwaysBreakAfterReturnType: All", AlwaysBreakAfterReturnType, + FormatStyle::RTBS_All); + CHECK_PARSE("AlwaysBreakAfterReturnType: TopLevel", + AlwaysBreakAfterReturnType, FormatStyle::RTBS_TopLevel); + CHECK_PARSE("AlwaysBreakAfterReturnType: AllDefinitions", + AlwaysBreakAfterReturnType, FormatStyle::RTBS_AllDefinitions); + CHECK_PARSE("AlwaysBreakAfterReturnType: TopLevelDefinitions", + AlwaysBreakAfterReturnType, + FormatStyle::RTBS_TopLevelDefinitions); Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All; CHECK_PARSE("AlwaysBreakAfterDefinitionReturnType: None", @@ -9288,6 +9923,8 @@ TEST_F(FormatTest, ParsesConfiguration) { CHECK_PARSE("NamespaceIndentation: All", NamespaceIndentation, FormatStyle::NI_All); + // FIXME: This is required because parsing a configuration simply overwrites + // the first N elements of the list instead of resetting it. Style.ForEachMacros.clear(); std::vector<std::string> BoostForeach; BoostForeach.push_back("BOOST_FOREACH"); @@ -9297,6 +9934,16 @@ TEST_F(FormatTest, ParsesConfiguration) { BoostAndQForeach.push_back("Q_FOREACH"); CHECK_PARSE("ForEachMacros: [BOOST_FOREACH, Q_FOREACH]", ForEachMacros, BoostAndQForeach); + + Style.IncludeCategories.clear(); + std::vector<FormatStyle::IncludeCategory> ExpectedCategories = {{"abc/.*", 2}, + {".*", 1}}; + CHECK_PARSE("IncludeCategories:\n" + " - Regex: abc/.*\n" + " Priority: 2\n" + " - Regex: .*\n" + " Priority: 1", + IncludeCategories, ExpectedCategories); } TEST_F(FormatTest, ParsesConfigurationWithLanguages) { @@ -9497,6 +10144,11 @@ TEST_F(FormatTest, SplitsUTF8Strings) { "\"八九十\tqq\"", format("\"一\t二 \t三 四 五\t六 \t七 八九十\tqq\"", getLLVMStyleWithColumns(11))); + + // UTF8 character in an escape sequence. + EXPECT_EQ("\"aaaaaa\"\n" + "\"\\\xC2\x8D\"", + format("\"aaaaaa\\\xC2\x8D\"", getLLVMStyleWithColumns(10))); } TEST_F(FormatTest, HandlesDoubleWidthCharsInMultiLineStrings) { @@ -9875,6 +10527,9 @@ TEST_F(FormatTest, FormatsLambdas) { verifyFormat("SomeFunction({[&] {\n" " // comment\n" "}});"); + verifyFormat("virtual aaaaaaaaaaaaaaaa(std::function<bool()> bbbbbbbbbbbb =\n" + " [&]() { return true; },\n" + " aaaaa aaaaaaaaa);"); // Lambdas with return types. verifyFormat("int c = []() -> int { return 2; }();\n"); @@ -9885,6 +10540,7 @@ TEST_F(FormatTest, FormatsLambdas) { verifyGoogleFormat("auto a = [&b, c](D* d) -> pair<D*, D*> {};"); verifyGoogleFormat("auto a = [&b, c](D* d) -> D& {};"); verifyGoogleFormat("auto a = [&b, c](D* d) -> const D* {};"); + verifyFormat("[a, a]() -> a<1> {};"); verifyFormat("auto aaaaaaaa = [](int i, // break for some reason\n" " int j) -> int {\n" " return ffffffffffffffffffffffffffffffffffffffffffff(i * j);\n" @@ -10191,6 +10847,9 @@ TEST_F(FormatTest, SpacesInAngles) { verifyFormat("f< int, float >();", Spaces); verifyFormat("template <> g() {}", Spaces); verifyFormat("template < std::vector< int > > f() {}", Spaces); + verifyFormat("std::function< void(int, int) > fct;", Spaces); + verifyFormat("void inFunction() { std::function< void(int, int) > fct; }", + Spaces); Spaces.Standard = FormatStyle::LS_Cpp03; Spaces.SpacesInAngles = true; @@ -10362,6 +11021,12 @@ TEST_F(FormatTest, DoNotCrashOnInvalidInput) { verifyNoCrash("#define a\\\n /**/}"); } +TEST_F(FormatTest, FormatsTableGenCode) { + FormatStyle Style = getLLVMStyle(); + Style.Language = FormatStyle::LK_TableGen; + verifyFormat("include \"a.td\"\ninclude \"b.td\"", Style); +} + } // end namespace } // end namespace format } // end namespace clang diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp index d068d35d7d393..cba2ce3370c9e 100644 --- a/unittests/Format/FormatTestJS.cpp +++ b/unittests/Format/FormatTestJS.cpp @@ -49,7 +49,8 @@ protected: static void verifyFormat( llvm::StringRef Code, const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript)) { - EXPECT_EQ(Code.str(), format(test::messUp(Code), Style)); + std::string result = format(test::messUp(Code), Style); + EXPECT_EQ(Code.str(), result) << "Formatted:\n" << result; } }; @@ -79,8 +80,8 @@ TEST_F(FormatTestJS, UnderstandsJavaScriptOperators) { " q();", getGoogleJSStyleWithColumns(20)); verifyFormat("var x = aaaaaaaaaa ?\n" - " bbbbbb :\n" - " ccc;", + " bbbbbb :\n" + " ccc;", getGoogleJSStyleWithColumns(20)); verifyFormat("var b = a.map((x) => x + 1);"); @@ -99,9 +100,31 @@ TEST_F(FormatTestJS, LiteralOperatorsCanBeKeywords) { verifyFormat("not.and.or.not_eq = 1;"); } +TEST_F(FormatTestJS, ReservedWords) { + // JavaScript reserved words (aka keywords) are only illegal when used as + // Identifiers, but are legal as IdentifierNames. + verifyFormat("x.class.struct = 1;"); + verifyFormat("x.case = 1;"); + verifyFormat("x.interface = 1;"); + verifyFormat("x = {\n" + " a: 12,\n" + " interface: 1,\n" + " switch: 1,\n" + "};"); + verifyFormat("var struct = 2;"); + verifyFormat("var union = 2;"); +} + +TEST_F(FormatTestJS, CppKeywords) { + // Make sure we don't mess stuff up because of C++ keywords. + verifyFormat("return operator && (aa);"); +} + TEST_F(FormatTestJS, ES6DestructuringAssignment) { verifyFormat("var [a, b, c] = [1, 2, 3];"); + verifyFormat("let [a, b, c] = [1, 2, 3];"); verifyFormat("var {a, b} = {a: 1, b: 2};"); + verifyFormat("let {a, b} = {a: 1, b: 2};"); } TEST_F(FormatTestJS, ContainerLiterals) { @@ -236,6 +259,8 @@ TEST_F(FormatTestJS, GoogModules) { getGoogleJSStyleWithColumns(40)); verifyFormat("var long = goog.require('this.is.really.absurdly.long');", getGoogleJSStyleWithColumns(40)); + verifyFormat("goog.setTestOnly('this.is.really.absurdly.long');", + getGoogleJSStyleWithColumns(40)); // These should be wrapped normally. verifyFormat( @@ -263,31 +288,43 @@ TEST_F(FormatTestJS, ArrayLiterals) { " bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n" " ccccccccccccccccccccccccccc\n" "];"); - verifyFormat("var someVariable = SomeFuntion([\n" + verifyFormat("var someVariable = SomeFunction([\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" " bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n" " ccccccccccccccccccccccccccc\n" "]);"); - verifyFormat("var someVariable = SomeFuntion([\n" + verifyFormat("var someVariable = SomeFunction([\n" " [aaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbb],\n" "]);", getGoogleJSStyleWithColumns(51)); - verifyFormat("var someVariable = SomeFuntion(aaaa, [\n" + verifyFormat("var someVariable = SomeFunction(aaaa, [\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" " bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n" " ccccccccccccccccccccccccccc\n" "]);"); - verifyFormat("var someVariable = SomeFuntion(aaaa,\n" - " [\n" - " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" - " bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n" - " ccccccccccccccccccccccccccc\n" - " ],\n" - " aaaa);"); + verifyFormat("var someVariable = SomeFunction(\n" + " aaaa,\n" + " [\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n" + " ccccccccccccccccccccccccccc\n" + " ],\n" + " aaaa);"); verifyFormat("someFunction([], {a: a});"); } +TEST_F(FormatTestJS, ColumnLayoutForArrayLiterals) { + verifyFormat("var array = [\n" + " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n" + " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n" + "];"); + verifyFormat("var array = someFunction([\n" + " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n" + " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n" + "]);"); +} + TEST_F(FormatTestJS, FunctionLiterals) { verifyFormat("doFoo(function() {});"); verifyFormat("doFoo(function() { return 1; });"); @@ -305,14 +342,11 @@ TEST_F(FormatTestJS, FunctionLiterals) { " style: {direction: ''}\n" " }\n" "};"); - EXPECT_EQ("abc = xyz ?\n" - " function() {\n" - " return 1;\n" - " } :\n" - " function() {\n" - " return -1;\n" - " };", - format("abc=xyz?function(){return 1;}:function(){return -1;};")); + verifyFormat("abc = xyz ? function() {\n" + " return 1;\n" + "} : function() {\n" + " return -1;\n" + "};"); verifyFormat("var closure = goog.bind(\n" " function() { // comment\n" @@ -364,17 +398,13 @@ TEST_F(FormatTestJS, FunctionLiterals) { " someFunction();\n" " }, this), aaaaaaaaaaaaaaaaa);"); - // FIXME: This is not ideal yet. - verifyFormat("someFunction(goog.bind(\n" - " function() {\n" - " doSomething();\n" - " doSomething();\n" - " },\n" - " this),\n" - " goog.bind(function() {\n" - " doSomething();\n" - " doSomething();\n" - " }, this));"); + verifyFormat("someFunction(goog.bind(function() {\n" + " doSomething();\n" + " doSomething();\n" + "}, this), goog.bind(function() {\n" + " doSomething();\n" + " doSomething();\n" + "}, this));"); // FIXME: This is bad, we should be wrapping before "function() {". verifyFormat("someFunction(function() {\n" @@ -434,6 +464,12 @@ TEST_F(FormatTestJS, InliningFunctionLiterals) { " }\n" "}", Style); + + Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; + verifyFormat("var func = function() {\n" + " return 1;\n" + "};", + Style); } TEST_F(FormatTestJS, MultipleFunctionLiterals) { @@ -457,16 +493,16 @@ TEST_F(FormatTestJS, MultipleFunctionLiterals) { " doFoo();\n" " doBaz();\n" " });\n"); - // FIXME: Here, we should probably break right after the "(" for consistency. - verifyFormat("promise.then([],\n" - " function success() {\n" - " doFoo();\n" - " doBar();\n" - " },\n" - " function error() {\n" - " doFoo();\n" - " doBaz();\n" - " });\n"); + verifyFormat("promise.then(\n" + " [],\n" + " function success() {\n" + " doFoo();\n" + " doBar();\n" + " },\n" + " function error() {\n" + " doFoo();\n" + " doBaz();\n" + " });\n"); verifyFormat("getSomeLongPromise()\n" " .then(function(value) { body(); })\n" @@ -508,13 +544,13 @@ TEST_F(FormatTestJS, ArrowFunctions) { " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) =>\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" "};"); - verifyFormat( - "var a = a.aaaaaaa((a: a) => aaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) &&\n" - " aaaaaaaaaaaaaaaaaaaaa(bbbbbbb));"); - verifyFormat( - "var a = a.aaaaaaa((a: a) => aaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) ?\n" - " aaaaaaaaaaaaaaaaaaaaa(bbbbbbb) :\n" - " aaaaaaaaaaaaaaaaaaaaa(bbbbbbb));"); + verifyFormat("var a = a.aaaaaaa(\n" + " (a: a) => aaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) &&\n" + " aaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbb));"); + verifyFormat("var a = a.aaaaaaa(\n" + " (a: a) => aaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) ?\n" + " aaaaaaaaaaaaaaaaaaaaa(bbbbbbb) :\n" + " aaaaaaaaaaaaaaaaaaaaa(bbbbbbb));"); // FIXME: This is bad, we should be wrapping before "() => {". verifyFormat("someFunction(() => {\n" @@ -531,6 +567,11 @@ TEST_F(FormatTestJS, ReturnStatements) { "}"); } +TEST_F(FormatTestJS, ForLoops) { + verifyFormat("for (var i in [2, 3]) {\n" + "}"); +} + TEST_F(FormatTestJS, AutomaticSemicolonInsertion) { // The following statements must not wrap, as otherwise the program meaning // would change due to automatic semicolon insertion. @@ -564,7 +605,7 @@ TEST_F(FormatTestJS, TryCatch) { TEST_F(FormatTestJS, StringLiteralConcatenation) { verifyFormat("var literal = 'hello ' +\n" - " 'world';"); + " 'world';"); } TEST_F(FormatTestJS, RegexLiteralClassification) { @@ -585,6 +626,13 @@ TEST_F(FormatTestJS, RegexLiteralClassification) { // Not regex literals. verifyFormat("var a = a / 2 + b / 3;"); + verifyFormat("var a = a++ / 2;"); + // Prefix unary can operate on regex literals, not that it makes sense. + verifyFormat("var a = ++/a/;"); + + // This is a known issue, regular expressions are incorrectly detected if + // directly following a closing parenthesis. + verifyFormat("if (foo) / bar /.exec(baz);"); } TEST_F(FormatTestJS, RegexLiteralSpecialCharacters) { @@ -602,9 +650,18 @@ TEST_F(FormatTestJS, RegexLiteralSpecialCharacters) { verifyFormat("var regex = /x|y/;"); verifyFormat("var regex = /a{2}/;"); verifyFormat("var regex = /a{1,3}/;"); + verifyFormat("var regex = /[abc]/;"); verifyFormat("var regex = /[^abc]/;"); verifyFormat("var regex = /[\\b]/;"); + verifyFormat("var regex = /[/]/;"); + verifyFormat("var regex = /[\\/]/;"); + verifyFormat("var regex = /\\[/;"); + verifyFormat("var regex = /\\\\[/]/;"); + verifyFormat("var regex = /}[\"]/;"); + verifyFormat("var regex = /}[/\"]/;"); + verifyFormat("var regex = /}[\"/]/;"); + verifyFormat("var regex = /\\b/;"); verifyFormat("var regex = /\\B/;"); verifyFormat("var regex = /\\d/;"); @@ -705,12 +762,18 @@ TEST_F(FormatTestJS, ClassDeclarations) { TEST_F(FormatTestJS, InterfaceDeclarations) { verifyFormat("interface I {\n" " x: string;\n" + " enum: string[];\n" "}\n" "var y;"); // Ensure that state is reset after parsing the interface. verifyFormat("interface a {}\n" "export function b() {}\n" "var x;"); + + // Arrays of object type literals. + verifyFormat("interface I {\n" + " o: {}[];\n" + "}"); } TEST_F(FormatTestJS, EnumDeclarations) { @@ -818,7 +881,7 @@ TEST_F(FormatTestJS, TemplateStrings) { getGoogleJSStyleWithColumns(35)); // Barely fits. EXPECT_EQ("var x = `hello\n" " ${world}` >=\n" - " some();", + " some();", format("var x =\n" " `hello\n" " ${world}` >= some();", @@ -843,7 +906,7 @@ TEST_F(FormatTestJS, TemplateStrings) { // are first token in line. verifyFormat( "var a = aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n" - " `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`;"); + " `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`;"); // Two template strings. verifyFormat("var x = `hello` == `hello`;"); @@ -893,11 +956,20 @@ TEST_F(FormatTestJS, TypeArguments) { verifyFormat("function f(): List<any> {}"); verifyFormat("function aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa():\n" " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {}"); - verifyFormat("function aaaaaaaaaa(aaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaa,\n" - " aaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaa):\n" + verifyFormat("function aaaaaaaaaa(\n" + " aaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaa):\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa {}"); } +TEST_F(FormatTestJS, UserDefinedTypeGuards) { + verifyFormat( + "function foo(check: Object):\n" + " check is {foo: string, bar: string, baz: string, foobar: string} {\n" + " return 'bar' in check;\n" + "}\n"); +} + TEST_F(FormatTestJS, OptionalTypes) { verifyFormat("function x(a?: b, c?, d?) {}"); verifyFormat("class X {\n" @@ -920,5 +992,23 @@ TEST_F(FormatTestJS, IndexSignature) { verifyFormat("var x: {[k: string]: v};"); } +TEST_F(FormatTestJS, WrapAfterParen) { + verifyFormat("xxxxxxxxxxx(\n" + " aaa, aaa);", + getGoogleJSStyleWithColumns(20)); + verifyFormat("xxxxxxxxxxx(\n" + " aaa, aaa, aaa,\n" + " aaa, aaa, aaa);", + getGoogleJSStyleWithColumns(20)); + verifyFormat("xxxxxxxxxxx(\n" + " aaaaaaaaaaaaaaaaaaaaaaaa,\n" + " function(x) {\n" + " y(); //\n" + " });", + getGoogleJSStyleWithColumns(40)); + verifyFormat("while (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}"); +} + } // end namespace tooling } // end namespace clang diff --git a/unittests/Format/FormatTestJava.cpp b/unittests/Format/FormatTestJava.cpp index 8e590879f6e24..8fadfc09b3ed7 100644 --- a/unittests/Format/FormatTestJava.cpp +++ b/unittests/Format/FormatTestJava.cpp @@ -276,6 +276,10 @@ TEST_F(FormatTestJava, Annotations) { verifyFormat("void SomeFunction(@org.llvm.Nullable String something) {}"); verifyFormat("@Partial @Mock DataLoader loader;"); + verifyFormat("@Partial\n" + "@Mock\n" + "DataLoader loader;", + getChromiumStyle(FormatStyle::LK_Java)); verifyFormat("@SuppressWarnings(value = \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\")\n" "public static int iiiiiiiiiiiiiiiiiiiiiiii;"); @@ -393,6 +397,10 @@ TEST_F(FormatTestJava, SynchronizedKeyword) { "}"); } +TEST_F(FormatTestJava, AssertKeyword) { + verifyFormat("assert a && b;"); +} + TEST_F(FormatTestJava, PackageDeclarations) { verifyFormat("package some.really.loooooooooooooooooooooong.package;", getStyleWithColumns(50)); @@ -418,6 +426,7 @@ TEST_F(FormatTestJava, CppKeywords) { verifyFormat("public void union(Type a, Type b);"); verifyFormat("public void struct(Object o);"); verifyFormat("public void delete(Object o);"); + verifyFormat("return operator && (aa);"); } TEST_F(FormatTestJava, NeverAlignAfterReturn) { diff --git a/unittests/Format/FormatTestProto.cpp b/unittests/Format/FormatTestProto.cpp index 74f7005b219fb..cd2c0c8aa461d 100644 --- a/unittests/Format/FormatTestProto.cpp +++ b/unittests/Format/FormatTestProto.cpp @@ -73,6 +73,12 @@ TEST_F(FormatTestProto, FormatsEnums) { " TYPE_A = 1;\n" " TYPE_B = 2;\n" "};"); + verifyFormat("enum Type {\n" + " UNKNOWN = 0 [(some_options) = {\n" + " a: aa,\n" + " b: bb\n" + " }];\n" + "};"); } TEST_F(FormatTestProto, UnderstandsReturns) { @@ -156,5 +162,10 @@ TEST_F(FormatTestProto, FormatsService) { "};"); } +TEST_F(FormatTestProto, ExtendingMessage) { + verifyFormat("extend .foo.Bar {\n" + "}"); +} + } // end namespace tooling } // end namespace clang diff --git a/unittests/Format/FormatTestSelective.cpp b/unittests/Format/FormatTestSelective.cpp index 8d2cb5a2fcbd9..d53d1c0429211 100644 --- a/unittests/Format/FormatTestSelective.cpp +++ b/unittests/Format/FormatTestSelective.cpp @@ -45,8 +45,14 @@ TEST_F(FormatTestSelective, RemovesTrailingWhitespaceOfFormattedLine) { } TEST_F(FormatTestSelective, FormatsCorrectRegionForLeadingWhitespace) { - EXPECT_EQ("int b;\nint a;", format("int b;\n int a;", 7, 0)); - EXPECT_EQ("int b;\n int a;", format("int b;\n int a;", 6, 0)); + EXPECT_EQ("{int b;\n" + " int a;\n" + "}", + format("{int b;\n int a;}", 8, 0)); + EXPECT_EQ("{\n" + " int b;\n" + " int a;}", + format("{int b;\n int a;}", 7, 0)); Style.ColumnLimit = 12; EXPECT_EQ("#define A \\\n" @@ -84,11 +90,11 @@ TEST_F(FormatTestSelective, ReformatsMovedLines) { "template <typename T> T *getFETokenInfo() const {\n" " return static_cast<T *>(FETokenInfo);\n" "}\n" - " int a; // <- Should not be formatted", + "int a; // <- Should not be formatted", format( "template<typename T>\n" "T *getFETokenInfo() const { return static_cast<T*>(FETokenInfo); }\n" - " int a; // <- Should not be formatted", + "int a; // <- Should not be formatted", 9, 5)); } @@ -142,12 +148,12 @@ TEST_F(FormatTestSelective, FormatsCommentsLocally) { " // is\n" " // a\n" "\n" - " // This is unrelated", + "//This is unrelated", format("int a; // This\n" " // is\n" " // a\n" "\n" - " // This is unrelated", + "//This is unrelated", 0, 0)); EXPECT_EQ("int a;\n" "// This is\n" @@ -267,6 +273,27 @@ TEST_F(FormatTestSelective, IndividualStatementsOfNestedBlocks) { 0, 0)); } +TEST_F(FormatTestSelective, WrongIndent) { + EXPECT_EQ("namespace {\n" + "int i;\n" + "int j;\n" + "}", + format("namespace {\n" + " int i;\n" // Format here. + " int j;\n" + "}", + 15, 0)); + EXPECT_EQ("namespace {\n" + " int i;\n" + " int j;\n" + "}", + format("namespace {\n" + " int i;\n" + " int j;\n" // Format here. + "}", + 24, 0)); +} + TEST_F(FormatTestSelective, AlwaysFormatsEntireMacroDefinitions) { Style.AlignEscapedNewlinesLeft = true; EXPECT_EQ("int i;\n" @@ -310,13 +337,17 @@ TEST_F(FormatTestSelective, ReformatRegionAdjustsIndent) { EXPECT_EQ("{\n" "{\n" " a;\n" - "b;\n" + " b;\n" + " c;\n" + " d;\n" "}\n" "}", format("{\n" "{\n" " a;\n" - "b;\n" + " b;\n" + " c;\n" + " d;\n" "}\n" "}", 9, 2)); @@ -436,6 +467,27 @@ TEST_F(FormatTestSelective, UnderstandsTabs) { 21, 0)); } +TEST_F(FormatTestSelective, StopFormattingWhenLeavingScope) { + EXPECT_EQ( + "void f() {\n" + " if (a) {\n" + " g();\n" + " h();\n" + "}\n" + "\n" + "void g() {\n" + "}", + format("void f() {\n" + " if (a) {\n" // Assume this was added without the closing brace. + " g();\n" + " h();\n" + "}\n" + "\n" + "void g() {\n" // Make sure not to format this. + "}", + 15, 0)); +} + } // end namespace } // end namespace format } // end namespace clang diff --git a/unittests/Format/SortIncludesTest.cpp b/unittests/Format/SortIncludesTest.cpp new file mode 100644 index 0000000000000..dbe11749572bb --- /dev/null +++ b/unittests/Format/SortIncludesTest.cpp @@ -0,0 +1,255 @@ +//===- unittest/Format/SortIncludesTest.cpp - Include sort unit tests -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "FormatTestUtils.h" +#include "clang/Format/Format.h" +#include "llvm/Support/Debug.h" +#include "gtest/gtest.h" + +#define DEBUG_TYPE "format-test" + +namespace clang { +namespace format { +namespace { + +class SortIncludesTest : public ::testing::Test { +protected: + std::string sort(llvm::StringRef Code, StringRef FileName = "input.cpp") { + std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size())); + std::string Sorted = + applyAllReplacements(Code, sortIncludes(Style, Code, Ranges, FileName)); + return applyAllReplacements(Sorted, + reformat(Style, Sorted, Ranges, FileName)); + } + + unsigned newCursor(llvm::StringRef Code, unsigned Cursor) { + std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size())); + sortIncludes(Style, Code, Ranges, "input.cpp", &Cursor); + return Cursor; + } + + FormatStyle Style = getLLVMStyle(); + +}; + +TEST_F(SortIncludesTest, BasicSorting) { + EXPECT_EQ("#include \"a.h\"\n" + "#include \"b.h\"\n" + "#include \"c.h\"\n", + sort("#include \"a.h\"\n" + "#include \"c.h\"\n" + "#include \"b.h\"\n")); +} + +TEST_F(SortIncludesTest, SupportClangFormatOff) { + EXPECT_EQ("#include <a>\n" + "#include <b>\n" + "#include <c>\n" + "// clang-format off\n" + "#include <b>\n" + "#include <a>\n" + "#include <c>\n" + "// clang-format on\n", + sort("#include <b>\n" + "#include <a>\n" + "#include <c>\n" + "// clang-format off\n" + "#include <b>\n" + "#include <a>\n" + "#include <c>\n" + "// clang-format on\n")); +} + +TEST_F(SortIncludesTest, IncludeSortingCanBeDisabled) { + Style.SortIncludes = false; + EXPECT_EQ("#include \"a.h\"\n" + "#include \"c.h\"\n" + "#include \"b.h\"\n", + sort("#include \"a.h\"\n" + "#include \"c.h\"\n" + "#include \"b.h\"\n")); +} + +TEST_F(SortIncludesTest, MixIncludeAndImport) { + EXPECT_EQ("#include \"a.h\"\n" + "#import \"b.h\"\n" + "#include \"c.h\"\n", + sort("#include \"a.h\"\n" + "#include \"c.h\"\n" + "#import \"b.h\"\n")); +} + +TEST_F(SortIncludesTest, FixTrailingComments) { + EXPECT_EQ("#include \"a.h\" // comment\n" + "#include \"bb.h\" // comment\n" + "#include \"ccc.h\"\n", + sort("#include \"a.h\" // comment\n" + "#include \"ccc.h\"\n" + "#include \"bb.h\" // comment\n")); +} + +TEST_F(SortIncludesTest, LeadingWhitespace) { + EXPECT_EQ("#include \"a.h\"\n" + "#include \"b.h\"\n" + "#include \"c.h\"\n", + sort(" #include \"a.h\"\n" + " #include \"c.h\"\n" + " #include \"b.h\"\n")); + EXPECT_EQ("#include \"a.h\"\n" + "#include \"b.h\"\n" + "#include \"c.h\"\n", + sort("# include \"a.h\"\n" + "# include \"c.h\"\n" + "# include \"b.h\"\n")); +} + +TEST_F(SortIncludesTest, GreaterInComment) { + EXPECT_EQ("#include \"a.h\"\n" + "#include \"b.h\" // >\n" + "#include \"c.h\"\n", + sort("#include \"a.h\"\n" + "#include \"c.h\"\n" + "#include \"b.h\" // >\n")); +} + +TEST_F(SortIncludesTest, SortsLocallyInEachBlock) { + EXPECT_EQ("#include \"a.h\"\n" + "#include \"c.h\"\n" + "\n" + "#include \"b.h\"\n", + sort("#include \"a.h\"\n" + "#include \"c.h\"\n" + "\n" + "#include \"b.h\"\n")); +} + +TEST_F(SortIncludesTest, HandlesAngledIncludesAsSeparateBlocks) { + EXPECT_EQ("#include \"a.h\"\n" + "#include \"c.h\"\n" + "#include <b.h>\n" + "#include <d.h>\n", + sort("#include <d.h>\n" + "#include <b.h>\n" + "#include \"c.h\"\n" + "#include \"a.h\"\n")); + + Style = getGoogleStyle(FormatStyle::LK_Cpp); + EXPECT_EQ("#include <b.h>\n" + "#include <d.h>\n" + "#include \"a.h\"\n" + "#include \"c.h\"\n", + sort("#include <d.h>\n" + "#include <b.h>\n" + "#include \"c.h\"\n" + "#include \"a.h\"\n")); +} + +TEST_F(SortIncludesTest, HandlesMultilineIncludes) { + EXPECT_EQ("#include \"a.h\"\n" + "#include \"b.h\"\n" + "#include \"c.h\"\n", + sort("#include \"a.h\"\n" + "#include \\\n" + "\"c.h\"\n" + "#include \"b.h\"\n")); +} + +TEST_F(SortIncludesTest, LeavesMainHeaderFirst) { + EXPECT_EQ("#include \"llvm/a.h\"\n" + "#include \"b.h\"\n" + "#include \"c.h\"\n", + sort("#include \"llvm/a.h\"\n" + "#include \"c.h\"\n" + "#include \"b.h\"\n", + "a.cc")); + EXPECT_EQ("#include \"llvm/a.h\"\n" + "#include \"b.h\"\n" + "#include \"c.h\"\n", + sort("#include \"llvm/a.h\"\n" + "#include \"c.h\"\n" + "#include \"b.h\"\n", + "a_main.cc")); + EXPECT_EQ("#include \"llvm/input.h\"\n" + "#include \"b.h\"\n" + "#include \"c.h\"\n", + sort("#include \"llvm/input.h\"\n" + "#include \"c.h\"\n" + "#include \"b.h\"\n", + "input.mm")); + + // Don't do this in headers. + EXPECT_EQ("#include \"b.h\"\n" + "#include \"c.h\"\n" + "#include \"llvm/a.h\"\n", + sort("#include \"llvm/a.h\"\n" + "#include \"c.h\"\n" + "#include \"b.h\"\n", + "a.h")); + + // Only do this in the first #include block. + EXPECT_EQ("#include <a>\n" + "\n" + "#include \"b.h\"\n" + "#include \"c.h\"\n" + "#include \"llvm/a.h\"\n", + sort("#include <a>\n" + "\n" + "#include \"llvm/a.h\"\n" + "#include \"c.h\"\n" + "#include \"b.h\"\n", + "a.cc")); + + // Only recognize the first #include with a matching basename as main include. + EXPECT_EQ("#include \"a.h\"\n" + "#include \"b.h\"\n" + "#include \"c.h\"\n" + "#include \"llvm/a.h\"\n", + sort("#include \"b.h\"\n" + "#include \"a.h\"\n" + "#include \"c.h\"\n" + "#include \"llvm/a.h\"\n", + "a.cc")); +} + +TEST_F(SortIncludesTest, NegativePriorities) { + Style.IncludeCategories = {{".*important_os_header.*", -1}, {".*", 1}}; + EXPECT_EQ("#include \"important_os_header.h\"\n" + "#include \"c_main.h\"\n" + "#include \"a_other.h\"\n", + sort("#include \"c_main.h\"\n" + "#include \"a_other.h\"\n" + "#include \"important_os_header.h\"\n", + "c_main.cc")); + + // check stable when re-run + EXPECT_EQ("#include \"important_os_header.h\"\n" + "#include \"c_main.h\"\n" + "#include \"a_other.h\"\n", + sort("#include \"important_os_header.h\"\n" + "#include \"c_main.h\"\n" + "#include \"a_other.h\"\n", + "c_main.cc")); +} + +TEST_F(SortIncludesTest, CalculatesCorrectCursorPosition) { + std::string Code = "#include <ccc>\n" // Start of line: 0 + "#include <bbbbbb>\n" // Start of line: 15 + "#include <a>\n"; // Start of line: 33 + EXPECT_EQ(31u, newCursor(Code, 0)); + EXPECT_EQ(13u, newCursor(Code, 15)); + EXPECT_EQ(0u, newCursor(Code, 33)); + + EXPECT_EQ(41u, newCursor(Code, 10)); + EXPECT_EQ(23u, newCursor(Code, 25)); + EXPECT_EQ(10u, newCursor(Code, 43)); +} + +} // end namespace +} // end namespace format +} // end namespace clang diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp index b5a39b303d001..42f8eb5a5c7f8 100644 --- a/unittests/Lex/LexerTest.cpp +++ b/unittests/Lex/LexerTest.cpp @@ -42,7 +42,7 @@ class VoidModuleLoader : public ModuleLoader { GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override { return nullptr; } bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override - { return 0; }; + { return 0; } }; // The test fixture. diff --git a/unittests/Lex/PPCallbacksTest.cpp b/unittests/Lex/PPCallbacksTest.cpp index 94812fc93de97..cbce5c6e16769 100644 --- a/unittests/Lex/PPCallbacksTest.cpp +++ b/unittests/Lex/PPCallbacksTest.cpp @@ -47,7 +47,7 @@ class VoidModuleLoader : public ModuleLoader { GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override { return nullptr; } bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override - { return 0; }; + { return 0; } }; // Stub to collect data from InclusionDirective callbacks. @@ -88,7 +88,7 @@ public: unsigned State; } CallbackParameters; - PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {}; + PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {} void PragmaOpenCLExtension(clang::SourceLocation NameLoc, const clang::IdentifierInfo *Name, @@ -98,7 +98,7 @@ public: this->Name = Name->getName(); this->StateLoc = StateLoc; this->State = State; - }; + } SourceLocation NameLoc; SmallString<16> Name; @@ -110,15 +110,16 @@ public: class PPCallbacksTest : public ::testing::Test { protected: PPCallbacksTest() - : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()), - DiagOpts(new DiagnosticOptions()), + : InMemoryFileSystem(new vfs::InMemoryFileSystem), + FileMgr(FileSystemOptions(), InMemoryFileSystem), + DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()), Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()), SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) { TargetOpts->Triple = "x86_64-apple-darwin11.1.0"; Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); } - FileSystemOptions FileMgrOpts; + IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem; FileManager FileMgr; IntrusiveRefCntPtr<DiagnosticIDs> DiagID; IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; @@ -133,7 +134,8 @@ protected: void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath, bool IsSystemHeader) { // Tell FileMgr about header. - FileMgr.getVirtualFile(HeaderPath, 0, 0); + InMemoryFileSystem->addFile(HeaderPath, 0, + llvm::MemoryBuffer::getMemBuffer("\n")); // Add header's parent path to search path. StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath); diff --git a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp index d2e3640501057..9345fc2390266 100644 --- a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp +++ b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp @@ -66,7 +66,7 @@ class VoidModuleLoader : public ModuleLoader { GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override { return nullptr; } bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override - { return 0; }; + { return 0; } }; TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) { diff --git a/unittests/Tooling/CMakeLists.txt b/unittests/Tooling/CMakeLists.txt index 469e6a956b2db..33b2046ae9288 100644 --- a/unittests/Tooling/CMakeLists.txt +++ b/unittests/Tooling/CMakeLists.txt @@ -1,10 +1,12 @@ set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} Support ) add_clang_unittest(ToolingTests CommentHandlerTest.cpp CompilationDatabaseTest.cpp + LookupTest.cpp ToolingTest.cpp RecursiveASTVisitorTest.cpp RecursiveASTVisitorTestCallVisitor.cpp diff --git a/unittests/Tooling/CommentHandlerTest.cpp b/unittests/Tooling/CommentHandlerTest.cpp index da5604524cdaa..b42b28b9c9486 100644 --- a/unittests/Tooling/CommentHandlerTest.cpp +++ b/unittests/Tooling/CommentHandlerTest.cpp @@ -97,6 +97,10 @@ public: : Current(Comments.begin()), End(Comments.end()), PP(PP) { } + CommentVerifier(CommentVerifier &&C) : Current(C.Current), End(C.End), PP(C.PP) { + C.Current = C.End; + } + ~CommentVerifier() { if (Current != End) { EXPECT_TRUE(Current == End) << "Unexpected comment \"" diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp index 3e5a589caf171..380d86fc5660d 100644 --- a/unittests/Tooling/CompilationDatabaseTest.cpp +++ b/unittests/Tooling/CompilationDatabaseTest.cpp @@ -36,8 +36,14 @@ TEST(JSONCompilationDatabase, ErrsOnInvalidFormat) { expectFailure("[{[]:\"\"}]", "Incorrectly typed entry"); expectFailure("[{}]", "Empty entry"); expectFailure("[{\"directory\":\"\",\"command\":\"\"}]", "Missing file"); - expectFailure("[{\"directory\":\"\",\"file\":\"\"}]", "Missing command"); + expectFailure("[{\"directory\":\"\",\"file\":\"\"}]", "Missing command or arguments"); expectFailure("[{\"command\":\"\",\"file\":\"\"}]", "Missing directory"); + expectFailure("[{\"directory\":\"\",\"arguments\":[]}]", "Missing file"); + expectFailure("[{\"arguments\":\"\",\"file\":\"\"}]", "Missing directory"); + expectFailure("[{\"directory\":\"\",\"arguments\":\"\",\"file\":\"\"}]", "Arguments not array"); + expectFailure("[{\"directory\":\"\",\"command\":[],\"file\":\"\"}]", "Command not string"); + expectFailure("[{\"directory\":\"\",\"arguments\":[[]],\"file\":\"\"}]", + "Arguments contain non-string"); } static std::vector<std::string> getAllFiles(StringRef JSONDatabase, @@ -92,8 +98,8 @@ TEST(JSONCompilationDatabase, GetAllCompileCommands) { StringRef FileName1("file1"); StringRef Command1("command1"); StringRef Directory2("//net/dir2"); - StringRef FileName2("file1"); - StringRef Command2("command1"); + StringRef FileName2("file2"); + StringRef Command2("command2"); std::vector<CompileCommand> Commands = getAllCompileCommands( ("[{\"directory\":\"" + Directory1 + "\"," + @@ -105,11 +111,32 @@ TEST(JSONCompilationDatabase, GetAllCompileCommands) { ErrorMessage); EXPECT_EQ(2U, Commands.size()) << ErrorMessage; EXPECT_EQ(Directory1, Commands[0].Directory) << ErrorMessage; + EXPECT_EQ(FileName1, Commands[0].Filename) << ErrorMessage; ASSERT_EQ(1u, Commands[0].CommandLine.size()); EXPECT_EQ(Command1, Commands[0].CommandLine[0]) << ErrorMessage; EXPECT_EQ(Directory2, Commands[1].Directory) << ErrorMessage; + EXPECT_EQ(FileName2, Commands[1].Filename) << ErrorMessage; ASSERT_EQ(1u, Commands[1].CommandLine.size()); EXPECT_EQ(Command2, Commands[1].CommandLine[0]) << ErrorMessage; + + // Check that order is preserved. + Commands = getAllCompileCommands( + ("[{\"directory\":\"" + Directory2 + "\"," + + "\"command\":\"" + Command2 + "\"," + "\"file\":\"" + FileName2 + "\"}," + " {\"directory\":\"" + Directory1 + "\"," + + "\"command\":\"" + Command1 + "\"," + "\"file\":\"" + FileName1 + "\"}]").str(), + ErrorMessage); + EXPECT_EQ(2U, Commands.size()) << ErrorMessage; + EXPECT_EQ(Directory2, Commands[0].Directory) << ErrorMessage; + EXPECT_EQ(FileName2, Commands[0].Filename) << ErrorMessage; + ASSERT_EQ(1u, Commands[0].CommandLine.size()); + EXPECT_EQ(Command2, Commands[0].CommandLine[0]) << ErrorMessage; + EXPECT_EQ(Directory1, Commands[1].Directory) << ErrorMessage; + EXPECT_EQ(FileName1, Commands[1].Filename) << ErrorMessage; + ASSERT_EQ(1u, Commands[1].CommandLine.size()); + EXPECT_EQ(Command1, Commands[1].CommandLine[0]) << ErrorMessage; } static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName, @@ -126,6 +153,25 @@ static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName, return Commands[0]; } +TEST(JSONCompilationDatabase, ArgumentsPreferredOverCommand) { + StringRef Directory("//net/dir"); + StringRef FileName("//net/dir/filename"); + StringRef Command("command"); + StringRef Arguments = "arguments"; + Twine ArgumentsAccumulate; + std::string ErrorMessage; + CompileCommand FoundCommand = findCompileArgsInJsonDatabase( + FileName, + ("[{\"directory\":\"" + Directory + "\"," + "\"arguments\":[\"" + Arguments + "\"]," + "\"command\":\"" + Command + "\"," + "\"file\":\"" + FileName + "\"}]").str(), + ErrorMessage); + EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage; + EXPECT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage; + EXPECT_EQ(Arguments, FoundCommand.CommandLine[0]) << ErrorMessage; +} + struct FakeComparator : public PathComparator { ~FakeComparator() override {} bool equivalent(StringRef FileA, StringRef FileB) const override { @@ -402,14 +448,16 @@ TEST(FixedCompilationDatabase, ReturnsFixedCommandLine) { CommandLine.push_back("one"); CommandLine.push_back("two"); FixedCompilationDatabase Database(".", CommandLine); + StringRef FileName("source"); std::vector<CompileCommand> Result = - Database.getCompileCommands("source"); + Database.getCompileCommands(FileName); ASSERT_EQ(1ul, Result.size()); std::vector<std::string> ExpectedCommandLine(1, "clang-tool"); ExpectedCommandLine.insert(ExpectedCommandLine.end(), CommandLine.begin(), CommandLine.end()); ExpectedCommandLine.push_back("source"); EXPECT_EQ(".", Result[0].Directory); + EXPECT_EQ(FileName, Result[0].Filename); EXPECT_EQ(ExpectedCommandLine, Result[0].CommandLine); } diff --git a/unittests/Tooling/LookupTest.cpp b/unittests/Tooling/LookupTest.cpp new file mode 100644 index 0000000000000..d847a298fff23 --- /dev/null +++ b/unittests/Tooling/LookupTest.cpp @@ -0,0 +1,108 @@ +//===- unittest/Tooling/LookupTest.cpp ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TestVisitor.h" +#include "clang/Tooling/Core/Lookup.h" +using namespace clang; + +namespace { +struct GetDeclsVisitor : TestVisitor<GetDeclsVisitor> { + std::function<void(CallExpr *)> OnCall; + SmallVector<Decl *, 4> DeclStack; + + bool VisitCallExpr(CallExpr *Expr) { + OnCall(Expr); + return true; + } + + bool TraverseDecl(Decl *D) { + DeclStack.push_back(D); + bool Ret = TestVisitor::TraverseDecl(D); + DeclStack.pop_back(); + return Ret; + } +}; + +TEST(LookupTest, replaceNestedName) { + GetDeclsVisitor Visitor; + + auto replaceCallExpr = [&](const CallExpr *Expr, + StringRef ReplacementString) { + const auto *Callee = cast<DeclRefExpr>(Expr->getCallee()->IgnoreImplicit()); + const ValueDecl *FD = Callee->getDecl(); + return tooling::replaceNestedName( + Callee->getQualifier(), Visitor.DeclStack.back()->getDeclContext(), FD, + ReplacementString); + }; + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("bar", replaceCallExpr(Expr, "::bar")); + }; + Visitor.runOver("namespace a { void foo(); }\n" + "namespace a { void f() { foo(); } }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); + }; + Visitor.runOver("namespace a { void foo(); }\n" + "namespace a { void f() { foo(); } }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); + }; + Visitor.runOver("namespace a { void foo(); }\n" + "namespace b { void f() { a::foo(); } }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); + }; + Visitor.runOver("namespace a { void foo(); }\n" + "namespace b { namespace a { void foo(); }\n" + "void f() { a::foo(); } }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("c::bar", replaceCallExpr(Expr, "::a::c::bar")); + }; + Visitor.runOver("namespace a { namespace b { void foo(); }\n" + "void f() { b::foo(); } }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); + }; + Visitor.runOver("namespace a { namespace b { void foo(); }\n" + "void f() { b::foo(); } }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("bar", replaceCallExpr(Expr, "::bar")); + }; + Visitor.runOver("void foo(); void f() { foo(); }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("::bar", replaceCallExpr(Expr, "::bar")); + }; + Visitor.runOver("void foo(); void f() { ::foo(); }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); + }; + Visitor.runOver("namespace a { void foo(); }\nvoid f() { a::foo(); }\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("a::bar", replaceCallExpr(Expr, "::a::bar")); + }; + Visitor.runOver("namespace a { int foo(); }\nauto f = a::foo();\n"); + + Visitor.OnCall = [&](CallExpr *Expr) { + EXPECT_EQ("bar", replaceCallExpr(Expr, "::a::bar")); + }; + Visitor.runOver( + "namespace a { int foo(); }\nusing a::foo;\nauto f = foo();\n"); +} + +} // end anonymous namespace diff --git a/unittests/Tooling/RefactoringCallbacksTest.cpp b/unittests/Tooling/RefactoringCallbacksTest.cpp index c2b331c70afc6..ad8aa8f98febc 100644 --- a/unittests/Tooling/RefactoringCallbacksTest.cpp +++ b/unittests/Tooling/RefactoringCallbacksTest.cpp @@ -71,7 +71,7 @@ TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) { ReplaceStmtWithStmt Callback("always-false", "should-be"); expectRewritten(Code, Expected, id("always-false", conditionalOperator( - hasCondition(boolLiteral(equals(false))), + hasCondition(cxxBoolLiteral(equals(false))), hasFalseExpression(id("should-be", expr())))), Callback); } @@ -92,7 +92,7 @@ TEST(RefactoringCallbacksTest, RemovesEntireIfOnEmptyElse) { std::string Expected = "void f() { }"; ReplaceIfStmtWithItsBody Callback("id", false); expectRewritten(Code, Expected, - id("id", ifStmt(hasCondition(boolLiteral(equals(false))))), + id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false))))), Callback); } diff --git a/unittests/Tooling/RefactoringTest.cpp b/unittests/Tooling/RefactoringTest.cpp index 6c2c16b484d7e..ff11aeae117ab 100644 --- a/unittests/Tooling/RefactoringTest.cpp +++ b/unittests/Tooling/RefactoringTest.cpp @@ -176,8 +176,8 @@ TEST(ShiftedCodePositionTest, FindsNewCodePosition) { EXPECT_EQ(1u, shiftedCodePosition(Replaces, 2)); // i|t i; EXPECT_EQ(2u, shiftedCodePosition(Replaces, 3)); // in| i; EXPECT_EQ(3u, shiftedCodePosition(Replaces, 4)); // int| i; - EXPECT_EQ(4u, shiftedCodePosition(Replaces, 5)); // int | i; - EXPECT_EQ(4u, shiftedCodePosition(Replaces, 6)); // int |i; + EXPECT_EQ(3u, shiftedCodePosition(Replaces, 5)); // int | i; + EXPECT_EQ(3u, shiftedCodePosition(Replaces, 6)); // int |i; EXPECT_EQ(4u, shiftedCodePosition(Replaces, 7)); // int |; EXPECT_EQ(5u, shiftedCodePosition(Replaces, 8)); // int i| } @@ -195,8 +195,8 @@ TEST(ShiftedCodePositionTest, VectorFindsNewCodePositionWithInserts) { EXPECT_EQ(1u, shiftedCodePosition(Replaces, 2)); // i|t i; EXPECT_EQ(2u, shiftedCodePosition(Replaces, 3)); // in| i; EXPECT_EQ(3u, shiftedCodePosition(Replaces, 4)); // int| i; - EXPECT_EQ(4u, shiftedCodePosition(Replaces, 5)); // int | i; - EXPECT_EQ(4u, shiftedCodePosition(Replaces, 6)); // int |i; + EXPECT_EQ(3u, shiftedCodePosition(Replaces, 5)); // int | i; + EXPECT_EQ(3u, shiftedCodePosition(Replaces, 6)); // int |i; EXPECT_EQ(4u, shiftedCodePosition(Replaces, 7)); // int |; EXPECT_EQ(5u, shiftedCodePosition(Replaces, 8)); // int i| } @@ -205,8 +205,17 @@ TEST(ShiftedCodePositionTest, FindsNewCodePositionWithInserts) { Replacements Replaces; Replaces.insert(Replacement("", 4, 0, "\"\n\"")); // Assume '"12345678"' is turned into '"1234"\n"5678"'. - EXPECT_EQ(4u, shiftedCodePosition(Replaces, 4)); // "123|5678" - EXPECT_EQ(8u, shiftedCodePosition(Replaces, 5)); // "1234|678" + EXPECT_EQ(3u, shiftedCodePosition(Replaces, 3)); // "123|5678" + EXPECT_EQ(7u, shiftedCodePosition(Replaces, 4)); // "1234|678" + EXPECT_EQ(8u, shiftedCodePosition(Replaces, 5)); // "12345|78" +} + +TEST(ShiftedCodePositionTest, FindsNewCodePositionInReplacedText) { + Replacements Replaces; + // Replace the first four characters with "abcd". + Replaces.insert(Replacement("", 0, 4, "abcd")); + for (unsigned i = 0; i < 3; ++i) + EXPECT_EQ(i, shiftedCodePosition(Replaces, i)); } class FlushRewrittenFilesTest : public ::testing::Test { @@ -489,5 +498,98 @@ TEST(DeduplicateTest, detectsConflicts) { } } +class MergeReplacementsTest : public ::testing::Test { +protected: + void mergeAndTestRewrite(StringRef Code, StringRef Intermediate, + StringRef Result, const Replacements &First, + const Replacements &Second) { + // These are mainly to verify the test itself and make it easier to read. + std::string AfterFirst = applyAllReplacements(Code, First); + std::string InSequenceRewrite = applyAllReplacements(AfterFirst, Second); + EXPECT_EQ(Intermediate, AfterFirst); + EXPECT_EQ(Result, InSequenceRewrite); + + tooling::Replacements Merged = mergeReplacements(First, Second); + std::string MergedRewrite = applyAllReplacements(Code, Merged); + EXPECT_EQ(InSequenceRewrite, MergedRewrite); + if (InSequenceRewrite != MergedRewrite) + for (tooling::Replacement M : Merged) + llvm::errs() << M.getOffset() << " " << M.getLength() << " " + << M.getReplacementText() << "\n"; + } + void mergeAndTestRewrite(StringRef Code, const Replacements &First, + const Replacements &Second) { + std::string InSequenceRewrite = + applyAllReplacements(applyAllReplacements(Code, First), Second); + tooling::Replacements Merged = mergeReplacements(First, Second); + std::string MergedRewrite = applyAllReplacements(Code, Merged); + EXPECT_EQ(InSequenceRewrite, MergedRewrite); + if (InSequenceRewrite != MergedRewrite) + for (tooling::Replacement M : Merged) + llvm::errs() << M.getOffset() << " " << M.getLength() << " " + << M.getReplacementText() << "\n"; + } +}; + +TEST_F(MergeReplacementsTest, Offsets) { + mergeAndTestRewrite("aaa", "aabab", "cacabab", + {{"", 2, 0, "b"}, {"", 3, 0, "b"}}, + {{"", 0, 0, "c"}, {"", 1, 0, "c"}}); + mergeAndTestRewrite("aaa", "babaa", "babacac", + {{"", 0, 0, "b"}, {"", 1, 0, "b"}}, + {{"", 4, 0, "c"}, {"", 5, 0, "c"}}); + mergeAndTestRewrite("aaaa", "aaa", "aac", {{"", 1, 1, ""}}, + {{"", 2, 1, "c"}}); + + mergeAndTestRewrite("aa", "bbabba", "bbabcba", + {{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}, {{"", 4, 0, "c"}}); +} + +TEST_F(MergeReplacementsTest, Concatenations) { + // Basic concatenations. It is important to merge these into a single + // replacement to ensure the correct order. + EXPECT_EQ((Replacements{{"", 0, 0, "ab"}}), + mergeReplacements({{"", 0, 0, "a"}}, {{"", 1, 0, "b"}})); + EXPECT_EQ((Replacements{{"", 0, 0, "ba"}}), + mergeReplacements({{"", 0, 0, "a"}}, {{"", 0, 0, "b"}})); + mergeAndTestRewrite("", "a", "ab", {{"", 0, 0, "a"}}, {{"", 1, 0, "b"}}); + mergeAndTestRewrite("", "a", "ba", {{"", 0, 0, "a"}}, {{"", 0, 0, "b"}}); +} + +TEST_F(MergeReplacementsTest, NotChangingLengths) { + mergeAndTestRewrite("aaaa", "abba", "acca", {{"", 1, 2, "bb"}}, + {{"", 1, 2, "cc"}}); + mergeAndTestRewrite("aaaa", "abba", "abcc", {{"", 1, 2, "bb"}}, + {{"", 2, 2, "cc"}}); + mergeAndTestRewrite("aaaa", "abba", "ccba", {{"", 1, 2, "bb"}}, + {{"", 0, 2, "cc"}}); + mergeAndTestRewrite("aaaaaa", "abbdda", "abccda", + {{"", 1, 2, "bb"}, {"", 3, 2, "dd"}}, {{"", 2, 2, "cc"}}); +} + +TEST_F(MergeReplacementsTest, OverlappingRanges) { + mergeAndTestRewrite("aaa", "bbd", "bcbcd", + {{"", 0, 1, "bb"}, {"", 1, 2, "d"}}, + {{"", 1, 0, "c"}, {"", 2, 0, "c"}}); + + mergeAndTestRewrite("aaaa", "aabbaa", "acccca", {{"", 2, 0, "bb"}}, + {{"", 1, 4, "cccc"}}); + mergeAndTestRewrite("aaaa", "aababa", "acccca", + {{"", 2, 0, "b"}, {"", 3, 0, "b"}}, {{"", 1, 4, "cccc"}}); + mergeAndTestRewrite("aaaaaa", "abbbba", "abba", {{"", 1, 4, "bbbb"}}, + {{"", 2, 2, ""}}); + mergeAndTestRewrite("aaaa", "aa", "cc", {{"", 1, 1, ""}, {"", 2, 1, ""}}, + {{"", 0, 2, "cc"}}); + mergeAndTestRewrite("aa", "abbba", "abcbcba", {{"", 1, 0, "bbb"}}, + {{"", 2, 0, "c"}, {"", 3, 0, "c"}}); + + mergeAndTestRewrite("aaa", "abbab", "ccdd", + {{"", 0, 1, ""}, {"", 2, 0, "bb"}, {"", 3, 0, "b"}}, + {{"", 0, 2, "cc"}, {"", 2, 3, "dd"}}); + mergeAndTestRewrite("aa", "babbab", "ccdd", + {{"", 0, 0, "b"}, {"", 1, 0, "bb"}, {"", 2, 0, "b"}}, + {{"", 0, 3, "cc"}, {"", 3, 3, "dd"}}); +} + } // end namespace tooling } // end namespace clang diff --git a/unittests/Tooling/RewriterTestContext.h b/unittests/Tooling/RewriterTestContext.h index 112efac52ebca..eee7ea1873b80 100644 --- a/unittests/Tooling/RewriterTestContext.h +++ b/unittests/Tooling/RewriterTestContext.h @@ -34,15 +34,20 @@ namespace clang { /// methods, which help with writing tests that change files. class RewriterTestContext { public: - RewriterTestContext() - : DiagOpts(new DiagnosticOptions()), - Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), - &*DiagOpts), - DiagnosticPrinter(llvm::outs(), &*DiagOpts), - Files((FileSystemOptions())), - Sources(Diagnostics, Files), - Rewrite(Sources, Options) { + RewriterTestContext() + : DiagOpts(new DiagnosticOptions()), + Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), + &*DiagOpts), + DiagnosticPrinter(llvm::outs(), &*DiagOpts), + InMemoryFileSystem(new vfs::InMemoryFileSystem), + OverlayFileSystem( + new vfs::OverlayFileSystem(vfs::getRealFileSystem())), + Files(FileSystemOptions(), OverlayFileSystem), + Sources(Diagnostics, Files), Rewrite(Sources, Options) { Diagnostics.setClient(&DiagnosticPrinter, false); + // FIXME: To make these tests truly in-memory, we need to overlay the + // builtin headers. + OverlayFileSystem->pushOverlay(InMemoryFileSystem); } ~RewriterTestContext() {} @@ -50,9 +55,9 @@ class RewriterTestContext { FileID createInMemoryFile(StringRef Name, StringRef Content) { std::unique_ptr<llvm::MemoryBuffer> Source = llvm::MemoryBuffer::getMemBuffer(Content); - const FileEntry *Entry = - Files.getVirtualFile(Name, Source->getBufferSize(), 0); - Sources.overrideFileContents(Entry, std::move(Source)); + InMemoryFileSystem->addFile(Name, 0, std::move(Source)); + + const FileEntry *Entry = Files.getFile(Name); assert(Entry != nullptr); return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User); } @@ -109,6 +114,8 @@ class RewriterTestContext { IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; DiagnosticsEngine Diagnostics; TextDiagnosticPrinter DiagnosticPrinter; + IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem; + IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFileSystem; FileManager Files; SourceManager Sources; LangOptions Options; diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp index 4b14ebb2c300d..c4b174f183da8 100644 --- a/unittests/Tooling/ToolingTest.cpp +++ b/unittests/Tooling/ToolingTest.cpp @@ -18,6 +18,8 @@ #include "clang/Tooling/Tooling.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Config/llvm-config.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/TargetRegistry.h" #include "gtest/gtest.h" #include <algorithm> #include <string> @@ -147,8 +149,13 @@ TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) { } TEST(ToolInvocation, TestMapVirtualFile) { - IntrusiveRefCntPtr<clang::FileManager> Files( - new clang::FileManager(clang::FileSystemOptions())); + llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFileSystem( + new vfs::OverlayFileSystem(vfs::getRealFileSystem())); + llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( + new vfs::InMemoryFileSystem); + OverlayFileSystem->pushOverlay(InMemoryFileSystem); + llvm::IntrusiveRefCntPtr<FileManager> Files( + new FileManager(FileSystemOptions(), OverlayFileSystem)); std::vector<std::string> Args; Args.push_back("tool-executable"); Args.push_back("-Idef"); @@ -156,8 +163,10 @@ TEST(ToolInvocation, TestMapVirtualFile) { Args.push_back("test.cpp"); clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction, Files.get()); - Invocation.mapVirtualFile("test.cpp", "#include <abc>\n"); - Invocation.mapVirtualFile("def/abc", "\n"); + InMemoryFileSystem->addFile( + "test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("#include <abc>\n")); + InMemoryFileSystem->addFile("def/abc", 0, + llvm::MemoryBuffer::getMemBuffer("\n")); EXPECT_TRUE(Invocation.run()); } @@ -166,8 +175,13 @@ TEST(ToolInvocation, TestVirtualModulesCompilation) { // mapped module.map is found on the include path. In the future, expand this // test to run a full modules enabled compilation, so we make sure we can // rerun modules compilations with a virtual file system. - IntrusiveRefCntPtr<clang::FileManager> Files( - new clang::FileManager(clang::FileSystemOptions())); + llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFileSystem( + new vfs::OverlayFileSystem(vfs::getRealFileSystem())); + llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( + new vfs::InMemoryFileSystem); + OverlayFileSystem->pushOverlay(InMemoryFileSystem); + llvm::IntrusiveRefCntPtr<FileManager> Files( + new FileManager(FileSystemOptions(), OverlayFileSystem)); std::vector<std::string> Args; Args.push_back("tool-executable"); Args.push_back("-Idef"); @@ -175,11 +189,14 @@ TEST(ToolInvocation, TestVirtualModulesCompilation) { Args.push_back("test.cpp"); clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction, Files.get()); - Invocation.mapVirtualFile("test.cpp", "#include <abc>\n"); - Invocation.mapVirtualFile("def/abc", "\n"); + InMemoryFileSystem->addFile( + "test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("#include <abc>\n")); + InMemoryFileSystem->addFile("def/abc", 0, + llvm::MemoryBuffer::getMemBuffer("\n")); // Add a module.map file in the include directory of our header, so we trigger // the module.map header search logic. - Invocation.mapVirtualFile("def/module.map", "\n"); + InMemoryFileSystem->addFile("def/module.map", 0, + llvm::MemoryBuffer::getMemBuffer("\n")); EXPECT_TRUE(Invocation.run()); } @@ -271,7 +288,7 @@ TEST(ClangToolTest, ArgumentAdjusters) { bool Found = false; bool Ran = false; ArgumentsAdjuster CheckSyntaxOnlyAdjuster = - [&Found, &Ran](const CommandLineArguments &Args) { + [&Found, &Ran](const CommandLineArguments &Args, StringRef /*unused*/) { Ran = true; if (std::find(Args.begin(), Args.end(), "-fsyntax-only") != Args.end()) Found = true; @@ -291,6 +308,86 @@ TEST(ClangToolTest, ArgumentAdjusters) { EXPECT_FALSE(Found); } +namespace { +/// Find a target name such that looking for it in TargetRegistry by that name +/// returns the same target. We expect that there is at least one target +/// configured with this property. +std::string getAnyTarget() { + llvm::InitializeAllTargets(); + for (const auto &Target : llvm::TargetRegistry::targets()) { + std::string Error; + StringRef TargetName(Target.getName()); + if (TargetName == "x86-64") + TargetName = "x86_64"; + if (llvm::TargetRegistry::lookupTarget(TargetName, Error) == &Target) { + return TargetName; + } + } + return ""; +} +} + +TEST(addTargetAndModeForProgramName, AddsTargetAndMode) { + std::string Target = getAnyTarget(); + ASSERT_FALSE(Target.empty()); + + std::vector<std::string> Args = {"clang", "-foo"}; + addTargetAndModeForProgramName(Args, ""); + EXPECT_EQ((std::vector<std::string>{"clang", "-foo"}), Args); + addTargetAndModeForProgramName(Args, Target + "-g++"); + EXPECT_EQ((std::vector<std::string>{"clang", "-target", Target, + "--driver-mode=g++", "-foo"}), + Args); +} + +TEST(addTargetAndModeForProgramName, PathIgnored) { + std::string Target = getAnyTarget(); + ASSERT_FALSE(Target.empty()); + + SmallString<32> ToolPath; + llvm::sys::path::append(ToolPath, "foo", "bar", Target + "-g++"); + + std::vector<std::string> Args = {"clang", "-foo"}; + addTargetAndModeForProgramName(Args, ToolPath); + EXPECT_EQ((std::vector<std::string>{"clang", "-target", Target, + "--driver-mode=g++", "-foo"}), + Args); +} + +TEST(addTargetAndModeForProgramName, IgnoresExistingTarget) { + std::string Target = getAnyTarget(); + ASSERT_FALSE(Target.empty()); + + std::vector<std::string> Args = {"clang", "-foo", "-target", "something"}; + addTargetAndModeForProgramName(Args, Target + "-g++"); + EXPECT_EQ((std::vector<std::string>{"clang", "--driver-mode=g++", "-foo", + "-target", "something"}), + Args); + + std::vector<std::string> ArgsAlt = {"clang", "-foo", "-target=something"}; + addTargetAndModeForProgramName(ArgsAlt, Target + "-g++"); + EXPECT_EQ((std::vector<std::string>{"clang", "--driver-mode=g++", "-foo", + "-target=something"}), + ArgsAlt); +} + +TEST(addTargetAndModeForProgramName, IgnoresExistingMode) { + std::string Target = getAnyTarget(); + ASSERT_FALSE(Target.empty()); + + std::vector<std::string> Args = {"clang", "-foo", "--driver-mode=abc"}; + addTargetAndModeForProgramName(Args, Target + "-g++"); + EXPECT_EQ((std::vector<std::string>{"clang", "-target", Target, "-foo", + "--driver-mode=abc"}), + Args); + + std::vector<std::string> ArgsAlt = {"clang", "-foo", "--driver-mode", "abc"}; + addTargetAndModeForProgramName(ArgsAlt, Target + "-g++"); + EXPECT_EQ((std::vector<std::string>{"clang", "-target", Target, "-foo", + "--driver-mode", "abc"}), + ArgsAlt); +} + #ifndef LLVM_ON_WIN32 TEST(ClangToolTest, BuildASTs) { FixedCompilationDatabase Compilations("/", std::vector<std::string>()); diff --git a/unittests/libclang/LibclangTest.cpp b/unittests/libclang/LibclangTest.cpp index becebf076d61c..e190dec89a87b 100644 --- a/unittests/libclang/LibclangTest.cpp +++ b/unittests/libclang/LibclangTest.cpp @@ -379,8 +379,10 @@ public: Filename = Path.str(); Files.insert(Filename); } + llvm::sys::fs::create_directories(llvm::sys::path::parent_path(Filename)); std::ofstream OS(Filename); OS << Contents; + assert(OS.good()); } void DisplayDiagnostics() { unsigned NumDiagnostics = clang_getNumDiagnostics(ClangTU); @@ -465,3 +467,30 @@ TEST_F(LibclangReparseTest, ReparseWithModule) { ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */)); EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU)); } + +TEST_F(LibclangReparseTest, clang_parseTranslationUnit2FullArgv) { + // Provide a fake GCC 99.9.9 standard library that always overrides any local + // GCC installation. + std::string EmptyFiles[] = {"lib/gcc/arm-linux-gnueabi/99.9.9/crtbegin.o", + "include/arm-linux-gnueabi/.keep", + "include/c++/99.9.9/vector"}; + + for (auto &Name : EmptyFiles) + WriteFile(Name, "\n"); + + std::string Filename = "test.cc"; + WriteFile(Filename, "#include <vector>\n"); + + std::string Clang = "bin/clang"; + WriteFile(Clang, ""); + + const char *Argv[] = {Clang.c_str(), "-target", "arm-linux-gnueabi", + "--gcc-toolchain="}; + + EXPECT_EQ(CXError_Success, + clang_parseTranslationUnit2FullArgv(Index, Filename.c_str(), Argv, + sizeof(Argv) / sizeof(Argv[0]), + nullptr, 0, TUFlags, &ClangTU)); + EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU)); + DisplayDiagnostics(); +} |
