diff options
Diffstat (limited to 'unittests')
51 files changed, 3235 insertions, 997 deletions
diff --git a/unittests/AST/ASTTypeTraitsTest.cpp b/unittests/AST/ASTTypeTraitsTest.cpp index 0e73f7616923..eeb01ccad1df 100644 --- a/unittests/AST/ASTTypeTraitsTest.cpp +++ b/unittests/AST/ASTTypeTraitsTest.cpp @@ -26,6 +26,12 @@ template <typename T> static ASTNodeKind DNT() { return ASTNodeKind::getFromNodeKind<T>(); } +TEST(ASTNodeKind, IsNone) { + EXPECT_TRUE(ASTNodeKind().isNone()); + EXPECT_FALSE(DNT<Decl>().isNone()); + EXPECT_FALSE(DNT<VarDecl>().isNone()); +} + TEST(ASTNodeKind, Bases) { EXPECT_TRUE(DNT<Decl>().isBaseOf(DNT<VarDecl>())); EXPECT_FALSE(DNT<Decl>().isSame(DNT<VarDecl>())); @@ -60,6 +66,39 @@ TEST(ASTNodeKind, DiffBase) { EXPECT_FALSE(DNT<Type>().isSame(DNT<QualType>())); } +TEST(ASTNodeKind, MostDerivedType) { + EXPECT_TRUE(DNT<BinaryOperator>().isSame( + ASTNodeKind::getMostDerivedType(DNT<Expr>(), DNT<BinaryOperator>()))); + EXPECT_TRUE(DNT<BinaryOperator>().isSame( + ASTNodeKind::getMostDerivedType(DNT<BinaryOperator>(), DNT<Expr>()))); + EXPECT_TRUE(DNT<VarDecl>().isSame( + ASTNodeKind::getMostDerivedType(DNT<VarDecl>(), DNT<VarDecl>()))); + + // Not related. Returns nothing. + EXPECT_TRUE( + ASTNodeKind::getMostDerivedType(DNT<IfStmt>(), DNT<VarDecl>()).isNone()); + EXPECT_TRUE(ASTNodeKind::getMostDerivedType(DNT<IfStmt>(), + DNT<BinaryOperator>()).isNone()); +} + +TEST(ASTNodeKind, MostDerivedCommonAncestor) { + EXPECT_TRUE(DNT<Expr>().isSame(ASTNodeKind::getMostDerivedCommonAncestor( + DNT<Expr>(), DNT<BinaryOperator>()))); + EXPECT_TRUE(DNT<Expr>().isSame(ASTNodeKind::getMostDerivedCommonAncestor( + DNT<BinaryOperator>(), DNT<Expr>()))); + EXPECT_TRUE(DNT<VarDecl>().isSame(ASTNodeKind::getMostDerivedCommonAncestor( + DNT<VarDecl>(), DNT<VarDecl>()))); + + // A little related. Returns the ancestor. + EXPECT_TRUE( + DNT<NamedDecl>().isSame(ASTNodeKind::getMostDerivedCommonAncestor( + DNT<CXXMethodDecl>(), DNT<RecordDecl>()))); + + // Not related. Returns nothing. + EXPECT_TRUE(ASTNodeKind::getMostDerivedCommonAncestor( + DNT<IfStmt>(), DNT<VarDecl>()).isNone()); +} + struct Foo {}; TEST(ASTNodeKind, UnknownKind) { diff --git a/unittests/AST/ASTVectorTest.cpp b/unittests/AST/ASTVectorTest.cpp index ce6d0a07ce8b..55c06d0071fe 100644 --- a/unittests/AST/ASTVectorTest.cpp +++ b/unittests/AST/ASTVectorTest.cpp @@ -14,11 +14,79 @@ #include "llvm/Support/Compiler.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTVector.h" +#include "clang/Basic/Builtins.h" +#include "gtest/gtest.h" using namespace clang; -LLVM_ATTRIBUTE_UNUSED void CompileTest() { - ASTContext *C = nullptr; +namespace clang { +namespace ast { + +namespace { +class ASTVectorTest : public ::testing::Test { +protected: + ASTVectorTest() + : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()), + Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()), + SourceMgr(Diags, FileMgr), Idents(LangOpts, nullptr), + Ctxt(LangOpts, SourceMgr, Idents, Sels, Builtins) {} + + FileSystemOptions FileMgrOpts; + FileManager FileMgr; + IntrusiveRefCntPtr<DiagnosticIDs> DiagID; + DiagnosticsEngine Diags; + SourceManager SourceMgr; + LangOptions LangOpts; + IdentifierTable Idents; + SelectorTable Sels; + Builtin::Context Builtins; + ASTContext Ctxt; +}; +} // unnamed namespace + +TEST_F(ASTVectorTest, Compile) { ASTVector<int> V; - V.insert(*C, V.begin(), 0); + V.insert(Ctxt, V.begin(), 0); +} + +TEST_F(ASTVectorTest, InsertFill) { + ASTVector<double> V; + + // Ensure returned iterator points to first of inserted elements + auto I = V.insert(Ctxt, V.begin(), 5, 1.0); + ASSERT_EQ(V.begin(), I); + + // Check non-empty case as well + I = V.insert(Ctxt, V.begin() + 1, 5, 1.0); + ASSERT_EQ(V.begin() + 1, I); + + // And insert-at-end + I = V.insert(Ctxt, V.end(), 5, 1.0); + ASSERT_EQ(V.end() - 5, I); } + +TEST_F(ASTVectorTest, InsertEmpty) { + ASTVector<double> V; + + // Ensure no pointer overflow when inserting empty range + int Values[] = { 0, 1, 2, 3 }; + ArrayRef<int> IntVec(Values); + auto I = V.insert(Ctxt, V.begin(), IntVec.begin(), IntVec.begin()); + ASSERT_EQ(V.begin(), I); + ASSERT_TRUE(V.empty()); + + // Non-empty range + I = V.insert(Ctxt, V.begin(), IntVec.begin(), IntVec.end()); + ASSERT_EQ(V.begin(), I); + + // Non-Empty Vector, empty range + I = V.insert(Ctxt, V.end(), IntVec.begin(), IntVec.begin()); + ASSERT_EQ(V.begin() + IntVec.size(), I); + + // Non-Empty Vector, non-empty range + I = V.insert(Ctxt, V.end(), IntVec.begin(), IntVec.end()); + ASSERT_EQ(V.begin() + IntVec.size(), I); +} + +} // end namespace ast +} // end namespace clang diff --git a/unittests/AST/CommentLexer.cpp b/unittests/AST/CommentLexer.cpp index cb8de271803a..77ee22ffb43e 100644 --- a/unittests/AST/CommentLexer.cpp +++ b/unittests/AST/CommentLexer.cpp @@ -60,8 +60,8 @@ protected: void CommentLexerTest::lexString(const char *Source, std::vector<Token> &Toks) { - MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(Source); - FileID File = SourceMgr.createFileID(Buf); + std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Source); + FileID File = SourceMgr.createFileID(std::move(Buf)); SourceLocation Begin = SourceMgr.getLocForStartOfFile(File); Lexer L(Allocator, Diags, Traits, Begin, Source, Source + strlen(Source)); diff --git a/unittests/AST/CommentParser.cpp b/unittests/AST/CommentParser.cpp index ae1410f377fa..f6ef9b9b7cea 100644 --- a/unittests/AST/CommentParser.cpp +++ b/unittests/AST/CommentParser.cpp @@ -54,8 +54,8 @@ protected: }; FullComment *CommentParserTest::parseString(const char *Source) { - MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(Source); - FileID File = SourceMgr.createFileID(Buf); + std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Source); + FileID File = SourceMgr.createFileID(std::move(Buf)); SourceLocation Begin = SourceMgr.getLocForStartOfFile(File); Lexer L(Allocator, Diags, Traits, Begin, Source, Source + strlen(Source)); diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp index 5340756c03db..9f179c4a3f2d 100644 --- a/unittests/AST/DeclPrinterTest.cpp +++ b/unittests/AST/DeclPrinterTest.cpp @@ -268,8 +268,8 @@ TEST(DeclPrinter, TestCXXRecordDecl4) { "class Z { int a; };" "class A : Z { int b; };", "A", - "class A : Z {\n}")); - // Should be: with semicolon, with { ... }, without two spaces + "class A : Z {\n}")); + // Should be: with semicolon, with { ... } } TEST(DeclPrinter, TestCXXRecordDecl5) { @@ -277,8 +277,8 @@ TEST(DeclPrinter, TestCXXRecordDecl5) { "struct Z { int a; };" "struct A : Z { int b; };", "A", - "struct A : Z {\n}")); - // Should be: with semicolon, with { ... }, without two spaces + "struct A : Z {\n}")); + // Should be: with semicolon, with { ... } } TEST(DeclPrinter, TestCXXRecordDecl6) { @@ -313,8 +313,8 @@ TEST(DeclPrinter, TestCXXRecordDecl9) { "class Z { int a; };" "class A : virtual Z { int b; };", "A", - "class A : virtual Z {\n}")); - // Should be: with semicolon, with { ... }, without two spaces + "class A : virtual Z {\n}")); + // Should be: with semicolon, with { ... } } TEST(DeclPrinter, TestCXXRecordDecl10) { @@ -544,6 +544,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl10) { "};", constructorDecl(ofClass(hasName("A"))).bind("id"), "A<T...>(const A<T...> &a)")); + // WRONG; Should be: "A(const A<T...> &a);" } TEST(DeclPrinter, TestCXXConstructorDecl11) { @@ -553,8 +554,8 @@ TEST(DeclPrinter, TestCXXConstructorDecl11) { " A(T&&... ts) : T(ts)... {}" "};", constructorDecl(ofClass(hasName("A"))).bind("id"), - "A<T...>(T &&ts...) : T(ts)...")); - // WRONG; Should be: "A(T&&... ts) : T(ts)..." + "A<T...>(T &&...ts) : T(ts)...")); + // WRONG; Should be: "A(T &&...ts) : T(ts)... {}" } TEST(DeclPrinter, TestCXXDestructorDecl1) { @@ -1011,8 +1012,8 @@ TEST(DeclPrinter, TestClassTemplateDecl10) { "template<typename... T>" "struct A { int a; };", classTemplateDecl(hasName("A")).bind("id"), - "template <typename ... T> struct A {\n}")); - // Should be: with semicolon, with { ... }, without spaces before '...' + "template <typename ...T> struct A {\n}")); + // Should be: with semicolon, with { ... } } TEST(DeclPrinter, TestClassTemplateDecl11) { @@ -1020,8 +1021,8 @@ TEST(DeclPrinter, TestClassTemplateDecl11) { "template<typename... T>" "struct A : public T... { int a; };", classTemplateDecl(hasName("A")).bind("id"), - "template <typename ... T> struct A : public T... {\n}")); - // Should be: with semicolon, with { ... }, without spaces before '...' + "template <typename ...T> struct A : public T... {\n}")); + // Should be: with semicolon, with { ... } } TEST(DeclPrinter, TestClassTemplatePartialSpecializationDecl1) { @@ -1080,9 +1081,7 @@ TEST(DeclPrinter, TestFunctionTemplateDecl3) { "template<typename... T>" "void A(T... a);", functionTemplateDecl(hasName("A")).bind("id"), - "template <typename ... T> void A(T a...)")); - // WRONG; Should be: "template <typename ... T> void A(T... a)" - // (not "T a...") + "template <typename ...T> void A(T ...a)")); // Should be: with semicolon. } @@ -1239,7 +1238,7 @@ TEST(DeclPrinter, TestTemplateArgumentList13) { "};", "A", "Z<T...> A")); - // Should be: with semicolon, without extra space in "> >" + // Should be: with semicolon } TEST(DeclPrinter, TestTemplateArgumentList14) { @@ -1251,7 +1250,7 @@ TEST(DeclPrinter, TestTemplateArgumentList14) { "};", "A", "Z<Y<T>...> A")); - // Should be: with semicolon, without extra space in "> >" + // Should be: with semicolon } TEST(DeclPrinter, TestTemplateArgumentList15) { @@ -1262,7 +1261,7 @@ TEST(DeclPrinter, TestTemplateArgumentList15) { "};", "A", "Z<sizeof...(T)> A")); - // Should be: with semicolon, without extra space in "> >" + // Should be: with semicolon } TEST(DeclPrinter, TestObjCMethod1) { diff --git a/unittests/AST/EvaluateAsRValueTest.cpp b/unittests/AST/EvaluateAsRValueTest.cpp index 9120c936ed12..820edbc7c3e8 100644 --- a/unittests/AST/EvaluateAsRValueTest.cpp +++ b/unittests/AST/EvaluateAsRValueTest.cpp @@ -12,16 +12,14 @@ // //===----------------------------------------------------------------------===// -#include <map> -#include <string> - +#include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Tooling/Tooling.h" #include "gtest/gtest.h" - -#include "clang/AST/ASTConsumer.h" +#include <map> +#include <string> using namespace clang::tooling; @@ -59,9 +57,10 @@ class EvaluateConstantInitializersVisitor class EvaluateConstantInitializersAction : public clang::ASTFrontendAction { public: - clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &Compiler, - llvm::StringRef FilePath) override { - return new Consumer; + std::unique_ptr<clang::ASTConsumer> + CreateASTConsumer(clang::CompilerInstance &Compiler, + llvm::StringRef FilePath) override { + return llvm::make_unique<Consumer>(); } private: diff --git a/unittests/AST/ExternalASTSourceTest.cpp b/unittests/AST/ExternalASTSourceTest.cpp index 5cc2defe20fa..0cfde74cccce 100644 --- a/unittests/AST/ExternalASTSourceTest.cpp +++ b/unittests/AST/ExternalASTSourceTest.cpp @@ -35,9 +35,9 @@ private: return ASTFrontendAction::ExecuteAction(); } - virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { - return new ASTConsumer; + virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + return llvm::make_unique<ASTConsumer>(); } IntrusiveRefCntPtr<ExternalASTSource> Source; @@ -50,7 +50,7 @@ bool testExternalASTSource(ExternalASTSource *Source, CompilerInvocation *Invocation = new CompilerInvocation; Invocation->getPreprocessorOpts().addRemappedFile( - "test.cc", MemoryBuffer::getMemBuffer(FileContents)); + "test.cc", MemoryBuffer::getMemBuffer(FileContents).release()); const char *Args[] = { "test.cc" }; CompilerInvocation::CreateFromArgs(*Invocation, Args, Args + array_lengthof(Args), diff --git a/unittests/AST/MatchVerifier.h b/unittests/AST/MatchVerifier.h index 0265f4a24a14..e6593913b700 100644 --- a/unittests/AST/MatchVerifier.h +++ b/unittests/AST/MatchVerifier.h @@ -16,6 +16,9 @@ // //===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_UNITTESTS_AST_MATCHVERIFIER_H +#define LLVM_CLANG_UNITTESTS_AST_MATCHVERIFIER_H + #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" @@ -25,7 +28,14 @@ namespace clang { namespace ast_matchers { -enum Language { Lang_C, Lang_C89, Lang_CXX, Lang_CXX11, Lang_OpenCL }; +enum Language { + Lang_C, + Lang_C89, + Lang_CXX, + Lang_CXX11, + Lang_OpenCL, + Lang_OBJCXX +}; /// \brief Base class for verifying some property of nodes found by a matcher. template <typename NodeType> @@ -102,6 +112,10 @@ testing::AssertionResult MatchVerifier<NodeType>::match( break; case Lang_OpenCL: FileName = "input.cl"; + break; + case Lang_OBJCXX: + FileName = "input.mm"; + break; } // Default to failure in case callback is never called @@ -277,3 +291,5 @@ private: } // end namespace ast_matchers } // end namespace clang + +#endif diff --git a/unittests/AST/NamedDeclPrinterTest.cpp b/unittests/AST/NamedDeclPrinterTest.cpp index 4823b44862e5..f8fb98454bd7 100644 --- a/unittests/AST/NamedDeclPrinterTest.cpp +++ b/unittests/AST/NamedDeclPrinterTest.cpp @@ -68,8 +68,8 @@ PrintedNamedDeclMatches(StringRef Code, const std::vector<std::string> &Args, PrintMatch Printer(SuppressUnwrittenScope); MatchFinder Finder; Finder.addMatcher(NodeMatch, &Printer); - std::unique_ptr<FrontendActionFactory> Factory( - newFrontendActionFactory(&Finder)); + std::unique_ptr<FrontendActionFactory> Factory = + newFrontendActionFactory(&Finder); if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName)) return testing::AssertionFailure() diff --git a/unittests/AST/SourceLocationTest.cpp b/unittests/AST/SourceLocationTest.cpp index 82bba64334b9..ca5a8892a586 100644 --- a/unittests/AST/SourceLocationTest.cpp +++ b/unittests/AST/SourceLocationTest.cpp @@ -486,5 +486,17 @@ TEST(FriendDecl, InstantiationSourceRange) { friendDecl(hasParent(recordDecl(isTemplateInstantiation()))))); } +TEST(ObjCMessageExpr, CXXConstructExprRange) { + RangeVerifier<CXXConstructExpr> Verifier; + Verifier.expectRange(5, 25, 5, 27); + EXPECT_TRUE(Verifier.match( + "struct A { int a; };\n" + "@interface B {}\n" + "+ (void) f1: (A)arg;\n" + "@end\n" + "void f2() { A a; [B f1: (a)]; }\n", + constructExpr(), Lang_OBJCXX)); +} + } // end namespace ast_matchers } // end namespace clang diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp index bd7a5a6df8f3..d2e9ee19b2cf 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -375,6 +375,13 @@ TEST(DeclarationMatcher, hasDeclContext) { "}", recordDecl(hasDeclContext(namespaceDecl( hasName("M"), hasDeclContext(namespaceDecl())))))); + + EXPECT_TRUE(matches("class D{};", decl(hasDeclContext(decl())))); +} + +TEST(DeclarationMatcher, LinkageSpecification) { + EXPECT_TRUE(matches("extern \"C\" { void foo() {}; }", linkageSpecDecl())); + EXPECT_TRUE(notMatches("void foo() {};", linkageSpecDecl())); } TEST(ClassTemplate, DoesNotMatchClass) { @@ -455,6 +462,11 @@ TEST(DeclarationMatcher, MatchAnyOf) { EXPECT_TRUE(matches("class U {};", XOrYOrZOrUOrV)); EXPECT_TRUE(matches("class V {};", XOrYOrZOrUOrV)); EXPECT_TRUE(notMatches("class A {};", XOrYOrZOrUOrV)); + + StatementMatcher MixedTypes = stmt(anyOf(ifStmt(), binaryOperator())); + EXPECT_TRUE(matches("int F() { return 1 + 2; }", MixedTypes)); + EXPECT_TRUE(matches("int F() { if (true) return 1; }", MixedTypes)); + EXPECT_TRUE(notMatches("int F() { return 1; }", MixedTypes)); } TEST(DeclarationMatcher, MatchHas) { @@ -581,6 +593,11 @@ TEST(DeclarationMatcher, MatchNot) { EXPECT_TRUE(matches("class X { class Z {}; };", ClassXHasNotClassY)); EXPECT_TRUE(notMatches("class X { class Y {}; class Z {}; };", ClassXHasNotClassY)); + + DeclarationMatcher NamedNotRecord = + namedDecl(hasName("Foo"), unless(recordDecl())); + EXPECT_TRUE(matches("void Foo(){}", NamedNotRecord)); + EXPECT_TRUE(notMatches("struct Foo {};", NamedNotRecord)); } TEST(DeclarationMatcher, HasDescendant) { @@ -643,6 +660,45 @@ TEST(DeclarationMatcher, HasDescendant) { "};", ZDescendantClassXDescendantClassY)); } +TEST(DeclarationMatcher, HasDescendantMemoization) { + DeclarationMatcher CannotMemoize = + decl(hasDescendant(typeLoc().bind("x")), has(decl())); + EXPECT_TRUE(matches("void f() { int i; }", CannotMemoize)); +} + +TEST(DeclarationMatcher, HasDescendantMemoizationUsesRestrictKind) { + auto Name = hasName("i"); + auto VD = internal::Matcher<VarDecl>(Name).dynCastTo<Decl>(); + auto RD = internal::Matcher<RecordDecl>(Name).dynCastTo<Decl>(); + // Matching VD first should not make a cache hit for RD. + EXPECT_TRUE(notMatches("void f() { int i; }", + decl(hasDescendant(VD), hasDescendant(RD)))); + EXPECT_TRUE(notMatches("void f() { int i; }", + decl(hasDescendant(RD), hasDescendant(VD)))); + // Not matching RD first should not make a cache hit for VD either. + EXPECT_TRUE(matches("void f() { int i; }", + decl(anyOf(hasDescendant(RD), hasDescendant(VD))))); +} + +TEST(DeclarationMatcher, HasAttr) { + EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};", + decl(hasAttr(clang::attr::WarnUnused)))); + EXPECT_FALSE(matches("struct X {};", + decl(hasAttr(clang::attr::WarnUnused)))); +} + +TEST(DeclarationMatcher, MatchCudaDecl) { + EXPECT_TRUE(matchesWithCuda("__global__ void f() { }" + "void g() { f<<<1, 2>>>(); }", + CUDAKernelCallExpr())); + EXPECT_TRUE(matchesWithCuda("__attribute__((device)) void f() {}", + hasAttr(clang::attr::CUDADevice))); + EXPECT_TRUE(notMatchesWithCuda("void f() {}", + CUDAKernelCallExpr())); + EXPECT_FALSE(notMatchesWithCuda("__attribute__((global)) void f() {}", + hasAttr(clang::attr::CUDAGlobal))); +} + // Implements a run method that returns whether BoundNodes contains a // Decl bound to Id that can be dynamically cast to T. // Optionally checks that the check succeeded a specific number of times. @@ -681,7 +737,7 @@ public: EXPECT_EQ("", Name); } - virtual bool run(const BoundNodes *Nodes) { + virtual bool run(const BoundNodes *Nodes) override { const BoundNodes::IDToNodeMap &M = Nodes->getMap(); if (Nodes->getNodeAs<T>(Id)) { ++Count; @@ -703,7 +759,7 @@ public: return false; } - virtual bool run(const BoundNodes *Nodes, ASTContext *Context) { + virtual bool run(const BoundNodes *Nodes, ASTContext *Context) override { return run(Nodes); } @@ -771,6 +827,13 @@ TEST(Has, MatchesChildTypes) { varDecl(hasName("i"), hasType(qualType(has(pointerType())))))); } +TEST(ValueDecl, Matches) { + EXPECT_TRUE(matches("enum EnumType { EnumValue };", + valueDecl(hasType(asString("enum EnumType"))))); + EXPECT_TRUE(matches("void FunctionDecl();", + valueDecl(hasType(asString("void (void)"))))); +} + TEST(Enum, DoesNotMatchClasses) { EXPECT_TRUE(notMatches("class X {};", enumDecl(hasName("X")))); } @@ -1504,6 +1567,13 @@ TEST(IsExternC, MatchesExternCFunctionDeclarations) { EXPECT_TRUE(notMatches("void f() {}", functionDecl(isExternC()))); } +TEST(IsDeleted, MatchesDeletedFunctionDeclarations) { + EXPECT_TRUE( + notMatches("void Func();", functionDecl(hasName("Func"), isDeleted()))); + EXPECT_TRUE(matches("void Func() = delete;", + functionDecl(hasName("Func"), isDeleted()))); +} + TEST(HasAnyParameter, DoesntMatchIfInnerMatcherDoesntMatch) { EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };", methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X"))))))); @@ -1602,6 +1672,64 @@ TEST(Matcher, MatchesSpecificArgument) { 1, refersToType(asString("int")))))); } +TEST(TemplateArgument, Matches) { + EXPECT_TRUE(matches("template<typename T> struct C {}; C<int> c;", + classTemplateSpecializationDecl( + hasAnyTemplateArgument(templateArgument())))); + EXPECT_TRUE(matches( + "template<typename T> struct C {}; C<int> c;", + templateSpecializationType(hasAnyTemplateArgument(templateArgument())))); +} + +TEST(TemplateArgumentCountIs, Matches) { + EXPECT_TRUE( + matches("template<typename T> struct C {}; C<int> c;", + classTemplateSpecializationDecl(templateArgumentCountIs(1)))); + EXPECT_TRUE( + notMatches("template<typename T> struct C {}; C<int> c;", + classTemplateSpecializationDecl(templateArgumentCountIs(2)))); + + EXPECT_TRUE(matches("template<typename T> struct C {}; C<int> c;", + templateSpecializationType(templateArgumentCountIs(1)))); + EXPECT_TRUE( + notMatches("template<typename T> struct C {}; C<int> c;", + templateSpecializationType(templateArgumentCountIs(2)))); +} + +TEST(IsIntegral, Matches) { + EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;", + classTemplateSpecializationDecl( + hasAnyTemplateArgument(isIntegral())))); + EXPECT_TRUE(notMatches("template<typename T> struct C {}; C<int> c;", + classTemplateSpecializationDecl(hasAnyTemplateArgument( + templateArgument(isIntegral()))))); +} + +TEST(RefersToIntegralType, Matches) { + EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;", + classTemplateSpecializationDecl( + hasAnyTemplateArgument(refersToIntegralType( + asString("int")))))); + EXPECT_TRUE(notMatches("template<unsigned T> struct C {}; C<42> c;", + classTemplateSpecializationDecl(hasAnyTemplateArgument( + refersToIntegralType(asString("int")))))); +} + +TEST(EqualsIntegralValue, Matches) { + EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;", + classTemplateSpecializationDecl( + hasAnyTemplateArgument(equalsIntegralValue("42"))))); + EXPECT_TRUE(matches("template<int T> struct C {}; C<-42> c;", + classTemplateSpecializationDecl( + hasAnyTemplateArgument(equalsIntegralValue("-42"))))); + EXPECT_TRUE(matches("template<int T> struct C {}; C<-0042> c;", + classTemplateSpecializationDecl( + hasAnyTemplateArgument(equalsIntegralValue("-34"))))); + EXPECT_TRUE(notMatches("template<int T> struct C {}; C<42> c;", + classTemplateSpecializationDecl(hasAnyTemplateArgument( + equalsIntegralValue("0042"))))); +} + TEST(Matcher, MatchesAccessSpecDecls) { EXPECT_TRUE(matches("class C { public: int i; };", accessSpecDecl())); EXPECT_TRUE( @@ -3472,6 +3600,62 @@ TEST(IsTemplateInstantiation, DoesNotMatchNonTemplate) { recordDecl(isTemplateInstantiation()))); } +TEST(IsInstantiated, MatchesInstantiation) { + EXPECT_TRUE( + matches("template<typename T> class A { T i; }; class Y { A<int> a; };", + recordDecl(isInstantiated()))); +} + +TEST(IsInstantiated, NotMatchesDefinition) { + EXPECT_TRUE(notMatches("template<typename T> class A { T i; };", + recordDecl(isInstantiated()))); +} + +TEST(IsInTemplateInstantiation, MatchesInstantiationStmt) { + EXPECT_TRUE(matches("template<typename T> struct A { A() { T i; } };" + "class Y { A<int> a; }; Y y;", + declStmt(isInTemplateInstantiation()))); +} + +TEST(IsInTemplateInstantiation, NotMatchesDefinitionStmt) { + EXPECT_TRUE(notMatches("template<typename T> struct A { void x() { T i; } };", + declStmt(isInTemplateInstantiation()))); +} + +TEST(IsInstantiated, MatchesFunctionInstantiation) { + EXPECT_TRUE( + matches("template<typename T> void A(T t) { T i; } void x() { A(0); }", + functionDecl(isInstantiated()))); +} + +TEST(IsInstantiated, NotMatchesFunctionDefinition) { + EXPECT_TRUE(notMatches("template<typename T> void A(T t) { T i; }", + varDecl(isInstantiated()))); +} + +TEST(IsInTemplateInstantiation, MatchesFunctionInstantiationStmt) { + EXPECT_TRUE( + matches("template<typename T> void A(T t) { T i; } void x() { A(0); }", + declStmt(isInTemplateInstantiation()))); +} + +TEST(IsInTemplateInstantiation, NotMatchesFunctionDefinitionStmt) { + EXPECT_TRUE(notMatches("template<typename T> void A(T t) { T i; }", + declStmt(isInTemplateInstantiation()))); +} + +TEST(IsInTemplateInstantiation, Sharing) { + auto Matcher = binaryOperator(unless(isInTemplateInstantiation())); + // FIXME: Node sharing is an implementation detail, exposing it is ugly + // and makes the matcher behave in non-obvious ways. + EXPECT_TRUE(notMatches( + "int j; template<typename T> void A(T t) { j += 42; } void x() { A(0); }", + Matcher)); + EXPECT_TRUE(matches( + "int j; template<typename T> void A(T t) { j += t; } void x() { A(0); }", + Matcher)); +} + TEST(IsExplicitTemplateSpecialization, DoesNotMatchPrimaryTemplate) { EXPECT_TRUE(notMatches( @@ -3673,6 +3857,11 @@ TEST(TypeMatching, MatchesTypes) { EXPECT_TRUE(matches("struct S {};", qualType().bind("loc"))); } +TEST(TypeMatching, MatchesVoid) { + EXPECT_TRUE( + matches("struct S { void func(); };", methodDecl(returns(voidType())))); +} + TEST(TypeMatching, MatchesArrayTypes) { EXPECT_TRUE(matches("int a[] = {2,3};", arrayType())); EXPECT_TRUE(matches("int a[42];", arrayType())); @@ -4163,8 +4352,8 @@ public: virtual bool run(const BoundNodes *Nodes, ASTContext *Context) { const T *Node = Nodes->getNodeAs<T>(Id); - return selectFirst<const T>(InnerId, - match(InnerMatcher, *Node, *Context)) !=nullptr; + return selectFirst<T>(InnerId, match(InnerMatcher, *Node, *Context)) != + nullptr; } private: std::string Id; @@ -4221,7 +4410,7 @@ public: // Use the original typed pointer to verify we can pass pointers to subtypes // to equalsNode. const T *TypedNode = cast<T>(Node); - return selectFirst<const T>( + return selectFirst<T>( "", match(stmt(hasParent( stmt(has(stmt(equalsNode(TypedNode)))).bind(""))), *Node, Context)) != nullptr; @@ -4230,7 +4419,7 @@ public: // Use the original typed pointer to verify we can pass pointers to subtypes // to equalsNode. const T *TypedNode = cast<T>(Node); - return selectFirst<const T>( + return selectFirst<T>( "", match(decl(hasParent( decl(has(decl(equalsNode(TypedNode)))).bind(""))), *Node, Context)) != nullptr; @@ -4246,6 +4435,25 @@ TEST(IsEqualTo, MatchesNodesByIdentity) { new VerifyAncestorHasChildIsEqual<IfStmt>())); } +TEST(MatchFinder, CheckProfiling) { + MatchFinder::MatchFinderOptions Options; + llvm::StringMap<llvm::TimeRecord> Records; + Options.CheckProfiling.emplace(Records); + MatchFinder Finder(std::move(Options)); + + struct NamedCallback : public MatchFinder::MatchCallback { + void run(const MatchFinder::MatchResult &Result) override {} + StringRef getID() const override { return "MyID"; } + } Callback; + Finder.addMatcher(decl(), &Callback); + std::unique_ptr<FrontendActionFactory> Factory( + newFrontendActionFactory(&Finder)); + ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;")); + + EXPECT_EQ(1u, Records.size()); + EXPECT_EQ("MyID", Records.begin()->getKey()); +} + class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback { public: VerifyStartOfTranslationUnit() : Called(false) {} @@ -4422,5 +4630,58 @@ TEST(EqualsBoundNodeMatcher, UnlessDescendantsOfAncestorsMatch) { .bind("data"))); } +TEST(TypeDefDeclMatcher, Match) { + EXPECT_TRUE(matches("typedef int typedefDeclTest;", + typedefDecl(hasName("typedefDeclTest")))); +} + +// FIXME: Figure out how to specify paths so the following tests pass on Windows. +#ifndef LLVM_ON_WIN32 + +TEST(Matcher, IsExpansionInMainFileMatcher) { + EXPECT_TRUE(matches("class X {};", + recordDecl(hasName("X"), isExpansionInMainFile()))); + EXPECT_TRUE(notMatches("", recordDecl(isExpansionInMainFile()))); + FileContentMappings M; + M.push_back(std::make_pair("/other", "class X {};")); + EXPECT_TRUE(matchesConditionally("#include <other>\n", + recordDecl(isExpansionInMainFile()), false, + "-isystem/", M)); +} + +TEST(Matcher, IsExpansionInSystemHeader) { + FileContentMappings M; + M.push_back(std::make_pair("/other", "class X {};")); + EXPECT_TRUE(matchesConditionally( + "#include \"other\"\n", recordDecl(isExpansionInSystemHeader()), true, + "-isystem/", M)); + EXPECT_TRUE(matchesConditionally("#include \"other\"\n", + recordDecl(isExpansionInSystemHeader()), + false, "-I/", M)); + EXPECT_TRUE(notMatches("class X {};", + recordDecl(isExpansionInSystemHeader()))); + EXPECT_TRUE(notMatches("", recordDecl(isExpansionInSystemHeader()))); +} + +TEST(Matcher, IsExpansionInFileMatching) { + FileContentMappings M; + M.push_back(std::make_pair("/foo", "class A {};")); + M.push_back(std::make_pair("/bar", "class B {};")); + EXPECT_TRUE(matchesConditionally( + "#include <foo>\n" + "#include <bar>\n" + "class X {};", + recordDecl(isExpansionInFileMatching("b.*"), hasName("B")), true, + "-isystem/", M)); + EXPECT_TRUE(matchesConditionally( + "#include <foo>\n" + "#include <bar>\n" + "class X {};", + recordDecl(isExpansionInFileMatching("f.*"), hasName("X")), false, + "-isystem/", M)); +} + +#endif // LLVM_ON_WIN32 + } // end namespace ast_matchers } // end namespace clang diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h index 2e4ee2c5cbe9..a2ab9feee2a2 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.h +++ b/unittests/ASTMatchers/ASTMatchersTest.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H -#define LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H +#ifndef LLVM_CLANG_UNITTESTS_ASTMATCHERS_ASTMATCHERSTEST_H +#define LLVM_CLANG_UNITTESTS_ASTMATCHERS_ASTMATCHERSTEST_H #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Frontend/ASTUnit.h" @@ -22,6 +22,7 @@ using clang::tooling::buildASTFromCodeWithArgs; using clang::tooling::newFrontendActionFactory; using clang::tooling::runToolOnCodeWithArgs; using clang::tooling::FrontendActionFactory; +using clang::tooling::FileContentMappings; class BoundNodesCallback { public: @@ -39,7 +40,7 @@ public: VerifyMatch(BoundNodesCallback *FindResultVerifier, bool *Verified) : Verified(Verified), FindResultReviewer(FindResultVerifier) {} - virtual void run(const MatchFinder::MatchResult &Result) { + virtual void run(const MatchFinder::MatchResult &Result) override { if (FindResultReviewer != nullptr) { *Verified |= FindResultReviewer->run(&Result.Nodes, Result.Context); } else { @@ -58,10 +59,10 @@ private: }; template <typename T> -testing::AssertionResult matchesConditionally(const std::string &Code, - const T &AMatcher, - bool ExpectMatch, - llvm::StringRef CompileArg) { +testing::AssertionResult matchesConditionally( + const std::string &Code, const T &AMatcher, bool ExpectMatch, + llvm::StringRef CompileArg, + const FileContentMappings &VirtualMappedFiles = FileContentMappings()) { bool Found = false, DynamicFound = false; MatchFinder Finder; VerifyMatch VerifyFound(nullptr, &Found); @@ -73,7 +74,8 @@ testing::AssertionResult matchesConditionally(const std::string &Code, newFrontendActionFactory(&Finder)); // Some tests use typeof, which is a gnu extension. std::vector<std::string> Args(1, CompileArg); - if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) { + if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, "input.cc", + VirtualMappedFiles)) { return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; } if (Found != DynamicFound) { @@ -103,6 +105,75 @@ testing::AssertionResult notMatches(const std::string &Code, return matchesConditionally(Code, AMatcher, false, "-std=c++11"); } +// Function based on matchesConditionally with "-x cuda" argument added and +// small CUDA header prepended to the code string. +template <typename T> +testing::AssertionResult matchesConditionallyWithCuda( + const std::string &Code, const T &AMatcher, bool ExpectMatch, + llvm::StringRef CompileArg) { + const std::string CudaHeader = + "typedef unsigned int size_t;\n" + "#define __constant__ __attribute__((constant))\n" + "#define __device__ __attribute__((device))\n" + "#define __global__ __attribute__((global))\n" + "#define __host__ __attribute__((host))\n" + "#define __shared__ __attribute__((shared))\n" + "struct dim3 {" + " unsigned x, y, z;" + " __host__ __device__ dim3(unsigned x, unsigned y = 1, unsigned z = 1)" + " : x(x), y(y), z(z) {}" + "};" + "typedef struct cudaStream *cudaStream_t;" + "int cudaConfigureCall(dim3 gridSize, dim3 blockSize," + " size_t sharedSize = 0," + " cudaStream_t stream = 0);"; + + bool Found = false, DynamicFound = false; + MatchFinder Finder; + VerifyMatch VerifyFound(nullptr, &Found); + Finder.addMatcher(AMatcher, &VerifyFound); + VerifyMatch VerifyDynamicFound(nullptr, &DynamicFound); + if (!Finder.addDynamicMatcher(AMatcher, &VerifyDynamicFound)) + return testing::AssertionFailure() << "Could not add dynamic matcher"; + std::unique_ptr<FrontendActionFactory> Factory( + newFrontendActionFactory(&Finder)); + // Some tests use typeof, which is a gnu extension. + std::vector<std::string> Args; + Args.push_back("-xcuda"); + Args.push_back("-fno-ms-extensions"); + Args.push_back(CompileArg); + if (!runToolOnCodeWithArgs(Factory->create(), + CudaHeader + Code, Args)) { + return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; + } + if (Found != DynamicFound) { + return testing::AssertionFailure() << "Dynamic match result (" + << DynamicFound + << ") does not match static result (" + << Found << ")"; + } + if (!Found && ExpectMatch) { + return testing::AssertionFailure() + << "Could not find match in \"" << Code << "\""; + } else if (Found && !ExpectMatch) { + return testing::AssertionFailure() + << "Found unexpected match in \"" << Code << "\""; + } + return testing::AssertionSuccess(); +} + +template <typename T> +testing::AssertionResult matchesWithCuda(const std::string &Code, + const T &AMatcher) { + return matchesConditionallyWithCuda(Code, AMatcher, true, "-std=c++11"); +} + +template <typename T> +testing::AssertionResult notMatchesWithCuda(const std::string &Code, + const T &AMatcher) { + return matchesConditionallyWithCuda(Code, AMatcher, false, "-std=c++11"); +} + template <typename T> testing::AssertionResult matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher, diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp index 4e3239ff5a50..2a9a61b543d4 100644 --- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp +++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp @@ -26,9 +26,12 @@ public: virtual ~MockSema() {} uint64_t expectMatcher(StringRef MatcherName) { - ast_matchers::internal::Matcher<Stmt> M = stmt(); + // Optimizations on the matcher framework make simple matchers like + // 'stmt()' to be all the same matcher. + // Use a more complex expression to prevent that. + ast_matchers::internal::Matcher<Stmt> M = stmt(stmt(), stmt()); ExpectedMatchers.insert(std::make_pair(MatcherName, M)); - return M.getID(); + return M.getID().second; } void parse(StringRef Code) { @@ -125,8 +128,12 @@ TEST(ParserTest, ParseMatcher) { EXPECT_EQ("", Sema.Errors[i]); } + EXPECT_NE(ExpectedFoo, ExpectedBar); + EXPECT_NE(ExpectedFoo, ExpectedBaz); + EXPECT_NE(ExpectedBar, ExpectedBaz); + EXPECT_EQ(1ULL, Sema.Values.size()); - EXPECT_EQ(ExpectedFoo, getSingleMatcher(Sema.Values[0])->getID()); + EXPECT_EQ(ExpectedFoo, getSingleMatcher(Sema.Values[0])->getID().second); EXPECT_EQ(3ULL, Sema.Matchers.size()); const MockSema::MatcherInfo Bar = Sema.Matchers[0]; @@ -145,13 +152,21 @@ TEST(ParserTest, ParseMatcher) { EXPECT_EQ("Foo", Foo.MatcherName); EXPECT_TRUE(matchesRange(Foo.NameRange, 1, 2, 2, 12)); EXPECT_EQ(2ULL, Foo.Args.size()); - EXPECT_EQ(ExpectedBar, getSingleMatcher(Foo.Args[0].Value)->getID()); - EXPECT_EQ(ExpectedBaz, getSingleMatcher(Foo.Args[1].Value)->getID()); + EXPECT_EQ(ExpectedBar, getSingleMatcher(Foo.Args[0].Value)->getID().second); + EXPECT_EQ(ExpectedBaz, getSingleMatcher(Foo.Args[1].Value)->getID().second); EXPECT_EQ("Yo!", Foo.BoundID); } using ast_matchers::internal::Matcher; +Parser::NamedValueMap getTestNamedValues() { + Parser::NamedValueMap Values; + Values["nameX"] = std::string("x"); + Values["hasParamA"] = + VariantMatcher::SingleMatcher(hasParameter(0, hasName("a"))); + return Values; +} + TEST(ParserTest, FullParserTest) { Diagnostics Error; llvm::Optional<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression( @@ -174,21 +189,11 @@ TEST(ParserTest, FullParserTest) { EXPECT_FALSE(matches("void f(int x, int a);", M)); // Test named values. - struct NamedSema : public Parser::RegistrySema { - public: - virtual VariantValue getNamedValue(StringRef Name) { - if (Name == "nameX") - return std::string("x"); - if (Name == "param0") - return VariantMatcher::SingleMatcher(hasParameter(0, hasName("a"))); - return VariantValue(); - } - }; - NamedSema Sema; + auto NamedValues = getTestNamedValues(); llvm::Optional<DynTypedMatcher> HasParameterWithNamedValues( Parser::parseMatcherExpression( - "functionDecl(param0, hasParameter(1, hasName(nameX)))", &Sema, - &Error)); + "functionDecl(hasParamA, hasParameter(1, hasName(nameX)))", + nullptr, &NamedValues, &Error)); EXPECT_EQ("", Error.toStringFull()); M = HasParameterWithNamedValues->unconditionalConvertTo<Decl>(); @@ -270,7 +275,7 @@ TEST(ParserTest, OverloadErrors) { ParseWithError("callee(\"A\")")); } -TEST(ParserTest, Completion) { +TEST(ParserTest, CompletionRegistry) { std::vector<MatcherCompletion> Comps = Parser::completeExpression("while", 5); ASSERT_EQ(1u, Comps.size()); @@ -284,6 +289,38 @@ TEST(ParserTest, Completion) { EXPECT_EQ("bind", Comps[0].MatcherDecl); } +TEST(ParserTest, CompletionNamedValues) { + // Can complete non-matcher types. + auto NamedValues = getTestNamedValues(); + StringRef Code = "functionDecl(hasName("; + std::vector<MatcherCompletion> Comps = + Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues); + ASSERT_EQ(1u, Comps.size()); + EXPECT_EQ("nameX", Comps[0].TypedText); + EXPECT_EQ("String nameX", Comps[0].MatcherDecl); + + // Can complete if there are names in the expression. + Code = "methodDecl(hasName(nameX), "; + Comps = Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues); + EXPECT_LT(0u, Comps.size()); + + // Can complete names and registry together. + Code = "methodDecl(hasP"; + Comps = Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues); + ASSERT_EQ(3u, Comps.size()); + EXPECT_EQ("aramA", Comps[0].TypedText); + EXPECT_EQ("Matcher<FunctionDecl> hasParamA", Comps[0].MatcherDecl); + + EXPECT_EQ("arameter(", Comps[1].TypedText); + EXPECT_EQ( + "Matcher<FunctionDecl> hasParameter(unsigned, Matcher<ParmVarDecl>)", + Comps[1].MatcherDecl); + + EXPECT_EQ("arent(", Comps[2].TypedText); + EXPECT_EQ("Matcher<Decl> hasParent(Matcher<Decl|Stmt>)", + Comps[2].MatcherDecl); +} + } // end anonymous namespace } // end namespace dynamic } // end namespace ast_matchers diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp index e659b3a733d6..5483f8f35804 100644 --- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -82,8 +82,9 @@ public: typedef std::vector<MatcherCompletion> CompVector; CompVector getCompletions() { - return Registry::getCompletions( - ArrayRef<std::pair<MatcherCtor, unsigned> >()); + std::vector<std::pair<MatcherCtor, unsigned> > Context; + return Registry::getMatcherCompletions( + Registry::getAcceptedCompletionTypes(Context)); } CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1) { @@ -92,7 +93,8 @@ public: if (!Ctor) return CompVector(); Context.push_back(std::make_pair(*Ctor, ArgNo1)); - return Registry::getCompletions(Context); + return Registry::getMatcherCompletions( + Registry::getAcceptedCompletionTypes(Context)); } CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1, @@ -106,18 +108,16 @@ public: if (!Ctor) return CompVector(); Context.push_back(std::make_pair(*Ctor, ArgNo2)); - return Registry::getCompletions(Context); + return Registry::getMatcherCompletions( + Registry::getAcceptedCompletionTypes(Context)); } bool hasCompletion(const CompVector &Comps, StringRef TypedText, - StringRef MatcherDecl = StringRef(), - unsigned *Index = nullptr) { + StringRef MatcherDecl = StringRef()) { for (CompVector::const_iterator I = Comps.begin(), E = Comps.end(); I != E; ++I) { if (I->TypedText == TypedText && (MatcherDecl.empty() || I->MatcherDecl == MatcherDecl)) { - if (Index) - *Index = I - Comps.begin(); return true; } } @@ -347,7 +347,7 @@ TEST_F(RegistryTest, VariadicOp) { "anyOf", constructMatcher("recordDecl", constructMatcher("hasName", std::string("Foo"))), - constructMatcher("namedDecl", + constructMatcher("functionDecl", constructMatcher("hasName", std::string("foo")))) .getTypedMatcher<Decl>(); @@ -380,6 +380,13 @@ TEST_F(RegistryTest, VariadicOp) { EXPECT_FALSE(matches("class Bar{ int Foo; };", D)); EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D)); + + D = constructMatcher( + "namedDecl", constructMatcher("hasName", std::string("Foo")), + constructMatcher("unless", constructMatcher("recordDecl"))) + .getTypedMatcher<Decl>(); + EXPECT_TRUE(matches("void Foo(){}", D)); + EXPECT_TRUE(notMatches("struct Foo {};", D)); } TEST_F(RegistryTest, Errors) { @@ -438,24 +445,27 @@ TEST_F(RegistryTest, Errors) { TEST_F(RegistryTest, Completion) { CompVector Comps = getCompletions(); + // Overloaded EXPECT_TRUE(hasCompletion( Comps, "hasParent(", "Matcher<Decl|Stmt> hasParent(Matcher<Decl|Stmt>)")); + // 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|" + "NestedNameSpecifierLoc|...>)")); CompVector WhileComps = getCompletions("whileStmt", 0); - unsigned HasBodyIndex, HasParentIndex, AllOfIndex; EXPECT_TRUE(hasCompletion(WhileComps, "hasBody(", - "Matcher<WhileStmt> hasBody(Matcher<Stmt>)", - &HasBodyIndex)); + "Matcher<WhileStmt> hasBody(Matcher<Stmt>)")); EXPECT_TRUE(hasCompletion(WhileComps, "hasParent(", - "Matcher<Stmt> hasParent(Matcher<Decl|Stmt>)", - &HasParentIndex)); - EXPECT_TRUE(hasCompletion(WhileComps, "allOf(", - "Matcher<T> allOf(Matcher<T>...)", &AllOfIndex)); - EXPECT_GT(HasParentIndex, HasBodyIndex); - EXPECT_GT(AllOfIndex, HasParentIndex); + "Matcher<Stmt> hasParent(Matcher<Decl|Stmt>)")); + EXPECT_TRUE( + hasCompletion(WhileComps, "allOf(", "Matcher<T> allOf(Matcher<T>...)")); EXPECT_FALSE(hasCompletion(WhileComps, "whileStmt(")); EXPECT_FALSE(hasCompletion(WhileComps, "ifStmt(")); @@ -475,6 +485,20 @@ TEST_F(RegistryTest, Completion) { hasCompletion(NamedDeclComps, "isPublic()", "Matcher<Decl> isPublic()")); EXPECT_TRUE(hasCompletion(NamedDeclComps, "hasName(\"", "Matcher<NamedDecl> hasName(string)")); + + // Heterogeneous overloads. + Comps = getCompletions("classTemplateSpecializationDecl", 0); + EXPECT_TRUE(hasCompletion( + Comps, "isSameOrDerivedFrom(", + "Matcher<CXXRecordDecl> isSameOrDerivedFrom(string|Matcher<NamedDecl>)")); +} + +TEST_F(RegistryTest, HasArgs) { + Matcher<Decl> Value = constructMatcher( + "decl", constructMatcher("hasAttr", std::string("attr::WarnUnused"))) + .getTypedMatcher<Decl>(); + EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};", Value)); + EXPECT_FALSE(matches("struct X {};", Value)); } } // end anonymous namespace diff --git a/unittests/Basic/CMakeLists.txt b/unittests/Basic/CMakeLists.txt index b8f69bf357b4..3cb3cb8d3c80 100644 --- a/unittests/Basic/CMakeLists.txt +++ b/unittests/Basic/CMakeLists.txt @@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS add_clang_unittest(BasicTests CharInfoTest.cpp + DiagnosticTest.cpp FileManagerTest.cpp SourceManagerTest.cpp VirtualFileSystemTest.cpp diff --git a/unittests/Basic/DiagnosticTest.cpp b/unittests/Basic/DiagnosticTest.cpp new file mode 100644 index 000000000000..fa2b56e08341 --- /dev/null +++ b/unittests/Basic/DiagnosticTest.cpp @@ -0,0 +1,49 @@ +//===- unittests/Basic/DiagnosticTest.cpp -- Diagnostic engine tests ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticIDs.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace { + +// Check that DiagnosticErrorTrap works with SuppressAllDiagnostics. +TEST(DiagnosticTest, suppressAndTrap) { + DiagnosticsEngine Diags(new DiagnosticIDs(), + new DiagnosticOptions, + new IgnoringDiagConsumer()); + Diags.setSuppressAllDiagnostics(true); + + { + DiagnosticErrorTrap trap(Diags); + + // Diag that would set UncompilableErrorOccurred and ErrorOccurred. + Diags.Report(diag::err_target_unknown_triple) << "unknown"; + + // Diag that would set UnrecoverableErrorOccurred and ErrorOccurred. + Diags.Report(diag::err_cannot_open_file) << "file" << "error"; + + // Diag that would set FatalErrorOccurred + // (via non-note following a fatal error). + Diags.Report(diag::warn_mt_message) << "warning"; + + EXPECT_TRUE(trap.hasErrorOccurred()); + EXPECT_TRUE(trap.hasUnrecoverableErrorOccurred()); + } + + EXPECT_FALSE(Diags.hasErrorOccurred()); + EXPECT_FALSE(Diags.hasFatalErrorOccurred()); + EXPECT_FALSE(Diags.hasUncompilableErrorOccurred()); + EXPECT_FALSE(Diags.hasUnrecoverableErrorOccurred()); +} + +} diff --git a/unittests/Basic/FileManagerTest.cpp b/unittests/Basic/FileManagerTest.cpp index b3bc767949e8..dd8cf2410ad1 100644 --- a/unittests/Basic/FileManagerTest.cpp +++ b/unittests/Basic/FileManagerTest.cpp @@ -10,8 +10,8 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemOptions.h" #include "clang/Basic/FileSystemStatCache.h" -#include "gtest/gtest.h" #include "llvm/Config/llvm-config.h" +#include "gtest/gtest.h" using namespace llvm; using namespace clang; @@ -97,7 +97,7 @@ TEST_F(FileManagerTest, NoVirtualDirectoryExistsBeforeAVirtualFileIsAdded) { // FileManager to report "file/directory doesn't exist". This // avoids the possibility of the result of this test being affected // by what's in the real file system. - manager.addStatCache(new FakeStatCache); + manager.addStatCache(llvm::make_unique<FakeStatCache>()); EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir/foo")); EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir")); @@ -107,7 +107,7 @@ TEST_F(FileManagerTest, NoVirtualDirectoryExistsBeforeAVirtualFileIsAdded) { // When a virtual file is added, all of its ancestors should be created. TEST_F(FileManagerTest, getVirtualFileCreatesDirectoryEntriesForAncestors) { // Fake an empty real file system. - manager.addStatCache(new FakeStatCache); + manager.addStatCache(llvm::make_unique<FakeStatCache>()); manager.getVirtualFile("virtual/dir/bar.h", 100, 0); EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir/foo")); @@ -124,7 +124,7 @@ TEST_F(FileManagerTest, getVirtualFileCreatesDirectoryEntriesForAncestors) { // getFile() returns non-NULL if a real file exists at the given path. TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) { // Inject fake files into the file system. - FakeStatCache *statCache = new FakeStatCache; + auto statCache = llvm::make_unique<FakeStatCache>(); statCache->InjectDirectory("/tmp", 42); statCache->InjectFile("/tmp/test", 43); @@ -135,7 +135,7 @@ TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) { statCache->InjectFile(FileName, 45); #endif - manager.addStatCache(statCache); + manager.addStatCache(std::move(statCache)); const FileEntry *file = manager.getFile("/tmp/test"); ASSERT_TRUE(file != nullptr); @@ -158,7 +158,7 @@ TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) { // getFile() returns non-NULL if a virtual file exists at the given path. TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingVirtualFile) { // Fake an empty real file system. - manager.addStatCache(new FakeStatCache); + manager.addStatCache(llvm::make_unique<FakeStatCache>()); manager.getVirtualFile("virtual/dir/bar.h", 100, 0); const FileEntry *file = manager.getFile("virtual/dir/bar.h"); @@ -175,11 +175,11 @@ TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingVirtualFile) { TEST_F(FileManagerTest, getFileReturnsDifferentFileEntriesForDifferentFiles) { // Inject two fake files into the file system. Different inodes // mean the files are not symlinked together. - FakeStatCache *statCache = new FakeStatCache; + auto statCache = llvm::make_unique<FakeStatCache>(); statCache->InjectDirectory(".", 41); statCache->InjectFile("foo.cpp", 42); statCache->InjectFile("bar.cpp", 43); - manager.addStatCache(statCache); + manager.addStatCache(std::move(statCache)); const FileEntry *fileFoo = manager.getFile("foo.cpp"); const FileEntry *fileBar = manager.getFile("bar.cpp"); @@ -192,10 +192,10 @@ TEST_F(FileManagerTest, getFileReturnsDifferentFileEntriesForDifferentFiles) { // exists at the given path. TEST_F(FileManagerTest, getFileReturnsNULLForNonexistentFile) { // Inject a fake foo.cpp into the file system. - FakeStatCache *statCache = new FakeStatCache; + auto statCache = llvm::make_unique<FakeStatCache>(); statCache->InjectDirectory(".", 41); statCache->InjectFile("foo.cpp", 42); - manager.addStatCache(statCache); + manager.addStatCache(std::move(statCache)); // Create a virtual bar.cpp file. manager.getVirtualFile("bar.cpp", 200, 0); @@ -211,11 +211,11 @@ TEST_F(FileManagerTest, getFileReturnsNULLForNonexistentFile) { // getFile() returns the same FileEntry for real files that are aliases. TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedRealFiles) { // Inject two real files with the same inode. - FakeStatCache *statCache = new FakeStatCache; + auto statCache = llvm::make_unique<FakeStatCache>(); statCache->InjectDirectory("abc", 41); statCache->InjectFile("abc/foo.cpp", 42); statCache->InjectFile("abc/bar.cpp", 42); - manager.addStatCache(statCache); + manager.addStatCache(std::move(statCache)); EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp")); } @@ -224,11 +224,11 @@ TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedRealFiles) { // corresponding real files that are aliases. TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedVirtualFiles) { // Inject two real files with the same inode. - FakeStatCache *statCache = new FakeStatCache; + auto statCache = llvm::make_unique<FakeStatCache>(); statCache->InjectDirectory("abc", 41); statCache->InjectFile("abc/foo.cpp", 42); statCache->InjectFile("abc/bar.cpp", 42); - manager.addStatCache(statCache); + manager.addStatCache(std::move(statCache)); manager.getVirtualFile("abc/foo.cpp", 100, 0); manager.getVirtualFile("abc/bar.cpp", 200, 0); @@ -236,6 +236,15 @@ TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedVirtualFiles) { EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp")); } +TEST_F(FileManagerTest, addRemoveStatCache) { + manager.addStatCache(llvm::make_unique<FakeStatCache>()); + auto statCacheOwner = llvm::make_unique<FakeStatCache>(); + auto *statCache = statCacheOwner.get(); + manager.addStatCache(std::move(statCacheOwner)); + manager.addStatCache(llvm::make_unique<FakeStatCache>()); + manager.removeStatCache(statCache); +} + #endif // !LLVM_ON_WIN32 } // anonymous namespace diff --git a/unittests/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp index 9ea093c6b2b8..1dda54dff14d 100644 --- a/unittests/Basic/SourceManagerTest.cpp +++ b/unittests/Basic/SourceManagerTest.cpp @@ -74,8 +74,8 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnit) { const char *source = "#define M(x) [x]\n" "M(foo)"; - MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source); - FileID mainFileID = SourceMgr.createFileID(buf); + std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(source); + FileID mainFileID = SourceMgr.createFileID(std::move(Buf)); SourceMgr.setMainFileID(mainFileID); VoidModuleLoader ModLoader; @@ -127,8 +127,8 @@ TEST_F(SourceManagerTest, getColumnNumber) { "int x;\n" "int y;"; - MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(Source); - FileID MainFileID = SourceMgr.createFileID(Buf); + std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Source); + FileID MainFileID = SourceMgr.createFileID(std::move(Buf)); SourceMgr.setMainFileID(MainFileID); bool Invalid; @@ -186,14 +186,14 @@ TEST_F(SourceManagerTest, getMacroArgExpandedLocation) { "#define CONCAT(X, Y) X##Y\n" "CONCAT(1,1)\n"; - MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header); - MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main); - FileID mainFileID = SourceMgr.createFileID(mainBuf); + std::unique_ptr<MemoryBuffer> HeaderBuf = MemoryBuffer::getMemBuffer(header); + std::unique_ptr<MemoryBuffer> MainBuf = MemoryBuffer::getMemBuffer(main); + FileID mainFileID = SourceMgr.createFileID(std::move(MainBuf)); SourceMgr.setMainFileID(mainFileID); const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", - headerBuf->getBufferSize(), 0); - SourceMgr.overrideFileContents(headerFile, headerBuf); + HeaderBuf->getBufferSize(), 0); + SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf)); VoidModuleLoader ModLoader; HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, @@ -285,13 +285,13 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { "#define INC2 </test-header.h>\n" "#include M(INC2)\n"; - MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header); - MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main); - SourceMgr.setMainFileID(SourceMgr.createFileID(mainBuf)); + std::unique_ptr<MemoryBuffer> HeaderBuf = MemoryBuffer::getMemBuffer(header); + std::unique_ptr<MemoryBuffer> MainBuf = MemoryBuffer::getMemBuffer(main); + SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(MainBuf))); const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", - headerBuf->getBufferSize(), 0); - SourceMgr.overrideFileContents(headerFile, headerBuf); + HeaderBuf->getBufferSize(), 0); + SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf)); VoidModuleLoader ModLoader; HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, @@ -303,7 +303,7 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { PP.Initialize(*Target); std::vector<MacroAction> Macros; - PP.addPPCallbacks(new MacroTracker(Macros)); + PP.addPPCallbacks(llvm::make_unique<MacroTracker>(Macros)); PP.EnterMainSourceFile(); diff --git a/unittests/Basic/VirtualFileSystemTest.cpp b/unittests/Basic/VirtualFileSystemTest.cpp index e7d361e252b4..67beb923d976 100644 --- a/unittests/Basic/VirtualFileSystemTest.cpp +++ b/unittests/Basic/VirtualFileSystemTest.cpp @@ -32,21 +32,15 @@ class DummyFileSystem : public vfs::FileSystem { public: DummyFileSystem() : FSID(getNextFSID()), FileID(0) {} - ErrorOr<vfs::Status> status(const Twine &Path) { + ErrorOr<vfs::Status> status(const Twine &Path) override { std::map<std::string, vfs::Status>::iterator I = FilesAndDirs.find(Path.str()); if (I == FilesAndDirs.end()) return make_error_code(llvm::errc::no_such_file_or_directory); return I->second; } - std::error_code openFileForRead(const Twine &Path, - std::unique_ptr<vfs::File> &Result) { - llvm_unreachable("unimplemented"); - } - std::error_code getBufferForFile(const Twine &Name, - std::unique_ptr<MemoryBuffer> &Result, - int64_t FileSize = -1, - bool RequiresNullTerminator = true) { + ErrorOr<std::unique_ptr<vfs::File>> + openFileForRead(const Twine &Path) override { llvm_unreachable("unimplemented"); } @@ -539,8 +533,9 @@ public: IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLRawString(StringRef Content, IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) { - MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(Content); - return getVFSFromYAML(Buffer, CountingDiagHandler, this, ExternalFS); + std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content); + return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, this, + ExternalFS); } IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString( diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 936b8b206599..d0e2860e07f0 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -20,6 +20,7 @@ add_subdirectory(AST) add_subdirectory(Tooling) add_subdirectory(Format) add_subdirectory(Sema) +add_subdirectory(CodeGen) # FIXME: Why are the libclang unit tests disabled on Windows? if(NOT WIN32) add_subdirectory(libclang) diff --git a/unittests/CodeGen/BufferSourceTest.cpp b/unittests/CodeGen/BufferSourceTest.cpp new file mode 100644 index 000000000000..8169a6d0c9e5 --- /dev/null +++ b/unittests/CodeGen/BufferSourceTest.cpp @@ -0,0 +1,78 @@ +//===- unittests/CodeGen/BufferSourceTest.cpp - MemoryBuffer source tests -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/ParseAST.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/Triple.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/MemoryBuffer.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace { + +// Emitting constructors for global objects involves looking +// at the source file name. This makes sure that we don't crash +// if the source file is a memory buffer. +const char TestProgram[] = + "class EmitCXXGlobalInitFunc " + "{ " + "public: " + " EmitCXXGlobalInitFunc() {} " + "}; " + "EmitCXXGlobalInitFunc test; "; + +TEST(BufferSourceTest, EmitCXXGlobalInitFunc) { + CompilerInstance compiler; + + compiler.createDiagnostics(); + compiler.getLangOpts().CPlusPlus = 1; + compiler.getLangOpts().CPlusPlus11 = 1; + + compiler.getTargetOpts().Triple = llvm::Triple::normalize( + llvm::sys::getProcessTriple()); + compiler.setTarget(clang::TargetInfo::CreateTargetInfo( + compiler.getDiagnostics(), + std::make_shared<clang::TargetOptions>( + compiler.getTargetOpts()))); + + compiler.createFileManager(); + compiler.createSourceManager(compiler.getFileManager()); + compiler.createPreprocessor(clang::TU_Prefix); + + compiler.createASTContext(); + + compiler.setASTConsumer(std::unique_ptr<ASTConsumer>( + CreateLLVMCodeGen( + compiler.getDiagnostics(), + "EmitCXXGlobalInitFuncTest", + compiler.getCodeGenOpts(), + compiler.getTargetOpts(), + llvm::getGlobalContext()))); + + compiler.createSema(clang::TU_Prefix,NULL); + + clang::SourceManager &sm = compiler.getSourceManager(); + sm.setMainFileID(sm.createFileID( + llvm::MemoryBuffer::getMemBuffer(TestProgram), clang::SrcMgr::C_User)); + + clang::ParseAST(compiler.getSema(), false, false); +} + +} diff --git a/unittests/CodeGen/CMakeLists.txt b/unittests/CodeGen/CMakeLists.txt new file mode 100644 index 000000000000..27a513a2f982 --- /dev/null +++ b/unittests/CodeGen/CMakeLists.txt @@ -0,0 +1,15 @@ +set(LLVM_LINK_COMPONENTS + Core + Support + ) + +add_clang_unittest(ClangCodeGenTests + BufferSourceTest.cpp + ) + +target_link_libraries(ClangCodeGenTests + clangBasic + clangCodeGen + clangFrontend + clangParse + ) diff --git a/unittests/CodeGen/Makefile b/unittests/CodeGen/Makefile new file mode 100644 index 000000000000..de347e1afddc --- /dev/null +++ b/unittests/CodeGen/Makefile @@ -0,0 +1,20 @@ +##===- unittests/CodeGen/Makefile --------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL = ../.. +TESTNAME = CodeGen +include $(CLANG_LEVEL)/../../Makefile.config +LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader mc option \ + profiledata support +USEDLIBS = clangCodeGen.a clangFrontend.a clangSerialization.a \ + clangDriver.a \ + clangParse.a clangSema.a clangAnalysis.a \ + clangEdit.a clangAST.a clangLex.a clangBasic.a + +include $(CLANG_LEVEL)/unittests/Makefile diff --git a/unittests/Format/CMakeLists.txt b/unittests/Format/CMakeLists.txt index 14fc22d05c08..4a7ab794187b 100644 --- a/unittests/Format/CMakeLists.txt +++ b/unittests/Format/CMakeLists.txt @@ -4,11 +4,12 @@ set(LLVM_LINK_COMPONENTS add_clang_unittest(FormatTests FormatTest.cpp + FormatTestJava.cpp FormatTestJS.cpp FormatTestProto.cpp ) target_link_libraries(FormatTests clangFormat - clangTooling + clangToolingCore ) diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index 21bc86275461..8e770c2e9cd5 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -111,6 +111,7 @@ TEST_F(FormatTest, NestedNameSpecifiers) { verifyFormat("vector<::Type> v;"); verifyFormat("::ns::SomeFunction(::ns::SomeOtherFunction())"); verifyFormat("static constexpr bool Bar = decltype(bar())::value;"); + verifyFormat("bool a = 2 < ::SomeFunction();"); } TEST_F(FormatTest, OnlyGeneratesNecessaryReplacements) { @@ -158,9 +159,21 @@ TEST_F(FormatTest, FormatsCorrectRegionForLeadingWhitespace) { 25, 0, getLLVMStyleWithColumns(12))); } +TEST_F(FormatTest, FormatLineWhenInvokedOnTrailingNewline) { + EXPECT_EQ("int b;\n\nint a;", + format("int b;\n\nint a;", 8, 0, getLLVMStyle())); + EXPECT_EQ("int b;\n\nint a;", + format("int b;\n\nint a;", 7, 0, getLLVMStyle())); + + // This might not strictly be correct, but is likely good in all practical + // cases. + EXPECT_EQ("int b;\nint a;", + format("int b;int a;", 7, 0, getLLVMStyle())); +} + TEST_F(FormatTest, RemovesWhitespaceWhenTriggeredOnEmptyLine) { EXPECT_EQ("int a;\n\n int b;", - format("int a;\n \n\n int b;", 7, 0, getLLVMStyle())); + format("int a;\n \n\n int b;", 8, 0, getLLVMStyle())); EXPECT_EQ("int a;\n\n int b;", format("int a;\n \n\n int b;", 9, 0, getLLVMStyle())); } @@ -174,7 +187,7 @@ TEST_F(FormatTest, RemovesEmptyLines) { "\n" "};")); - // Don't remove empty lines at the start of namespaces. + // Don't remove empty lines at the start of namespaces or extern "C" blocks. EXPECT_EQ("namespace N {\n" "\n" "int i;\n" @@ -184,6 +197,29 @@ TEST_F(FormatTest, RemovesEmptyLines) { "int i;\n" "}", getGoogleStyle())); + EXPECT_EQ("extern /**/ \"C\" /**/ {\n" + "\n" + "int i;\n" + "}", + format("extern /**/ \"C\" /**/ {\n" + "\n" + "int i;\n" + "}", + getGoogleStyle())); + + // ...but do keep inlining and removing empty lines for non-block extern "C" + // functions. + verifyFormat("extern \"C\" int f() { return 42; }", getGoogleStyle()); + EXPECT_EQ("extern \"C\" int f() {\n" + " int i = 42;\n" + " return i;\n" + "}", + format("extern \"C\" int f() {\n" + "\n" + " int i = 42;\n" + " return i;\n" + "}", + getGoogleStyle())); // Remove empty lines at the beginning and end of blocks. EXPECT_EQ("void f() {\n" @@ -700,6 +736,58 @@ TEST_F(FormatTest, CaseRanges) { "}"); } +TEST_F(FormatTest, ShortCaseLabels) { + FormatStyle Style = getLLVMStyle(); + Style.AllowShortCaseLabelsOnASingleLine = true; + verifyFormat("switch (a) {\n" + "case 1: x = 1; break;\n" + "case 2: return;\n" + "case 3:\n" + "case 4:\n" + "case 5: return;\n" + "case 6: // comment\n" + " return;\n" + "case 7:\n" + " // comment\n" + " return;\n" + "default: y = 1; break;\n" + "}", + Style); + verifyFormat("switch (a) {\n" + "#if FOO\n" + "case 0: return 0;\n" + "#endif\n" + "}", + Style); + verifyFormat("switch (a) {\n" + "case 1: {\n" + "}\n" + "case 2: {\n" + " return;\n" + "}\n" + "case 3: {\n" + " x = 1;\n" + " return;\n" + "}\n" + "case 4:\n" + " if (x)\n" + " return;\n" + "}", + Style); + Style.ColumnLimit = 21; + verifyFormat("switch (a) {\n" + "case 1: x = 1; break;\n" + "case 2: return;\n" + "case 3:\n" + "case 4:\n" + "case 5: return;\n" + "default:\n" + " y = 1;\n" + " break;\n" + "}", + Style); +} + TEST_F(FormatTest, FormatsLabels) { verifyFormat("void f() {\n" " some_code();\n" @@ -791,6 +879,12 @@ TEST_F(FormatTest, UnderstandsSingleLineComments) { verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n" " // Comment inside a statement.\n" " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;"); + verifyFormat("SomeFunction(a,\n" + " // comment\n" + " b + x);"); + verifyFormat("SomeFunction(a, a,\n" + " // comment\n" + " b + x);"); verifyFormat( "bool aaaaaaaaaaaaa = // comment\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n" @@ -904,6 +998,14 @@ TEST_F(FormatTest, UnderstandsSingleLineComments) { " // first\n" "// at start\n" "otherLine();")); + EXPECT_EQ("void f() {\n" + " lineWith(); // comment\n" + " // at start\n" + "}", + format("void f() {\n" + " lineWith(); // comment\n" + " // at start\n" + "}")); verifyFormat( "#define A \\\n" @@ -1159,8 +1261,8 @@ TEST_F(FormatTest, CorrectlyHandlesLengthOfBlockComments) { } TEST_F(FormatTest, DontBreakNonTrailingBlockComments) { - EXPECT_EQ("void\n" - "ffffffffff(int aaaaa /* test */);", + EXPECT_EQ("void ffffffffff(\n" + " int aaaaa /* test */);", format("void ffffffffff(int aaaaa /* test */);", getLLVMStyleWithColumns(35))); } @@ -1210,11 +1312,11 @@ TEST_F(FormatTest, SplitsLongCxxComments) { format("// A comment before a macro definition\n" "#define a b", getLLVMStyleWithColumns(20))); - EXPECT_EQ("void\n" - "ffffff(int aaaaaaaaa, // wwww\n" - " int bbbbbbbbbb, // xxxxxxx\n" - " // yyyyyyyyyy\n" - " int c, int d, int e) {}", + EXPECT_EQ("void ffffff(\n" + " int aaaaaaaaa, // wwww\n" + " int bbbbbbbbbb, // xxxxxxx\n" + " // yyyyyyyyyy\n" + " int c, int d, int e) {}", format("void ffffff(\n" " int aaaaaaaaa, // wwww\n" " int bbbbbbbbbb, // xxxxxxx yyyyyyyyyy\n" @@ -1846,6 +1948,7 @@ TEST_F(FormatTest, FormatsClasses) { verifyFormat("template <class R, class C>\n" "struct Aaaaaaaaaaaaaaaaa<R (C::*)(int) const>\n" " : Aaaaaaaaaaaaaaaaa<R (C::*)(int)> {};"); + verifyFormat("class ::A::B {};"); } TEST_F(FormatTest, FormatsVariableDeclarationsAfterStructOrClass) { @@ -1903,7 +2006,8 @@ TEST_F(FormatTest, FormatsEnum) { verifyFormat("enum E { // comment\n" " ONE,\n" " TWO\n" - "};"); + "};\n" + "int i;"); } TEST_F(FormatTest, FormatsEnumsWithErrors) { @@ -1973,6 +2077,21 @@ TEST_F(FormatTest, FormatsNSEnums) { " // Information about aThirdDecentlyLongValue.\n" " aThirdDecentlyLongValue\n" "};"); + verifyGoogleFormat("typedef NS_OPTIONS(NSInteger, MyType) {\n" + " a = 1,\n" + " b = 2,\n" + " c = 3,\n" + "};"); + verifyGoogleFormat("typedef CF_ENUM(NSInteger, MyType) {\n" + " a = 1,\n" + " b = 2,\n" + " c = 3,\n" + "};"); + verifyGoogleFormat("typedef CF_OPTIONS(NSInteger, MyType) {\n" + " a = 1,\n" + " b = 2,\n" + " c = 3,\n" + "};"); } TEST_F(FormatTest, FormatsBitfields) { @@ -2063,12 +2182,32 @@ TEST_F(FormatTest, FormatsExternC) { verifyFormat("extern \"C\" {\nint a;"); } TEST_F(FormatTest, FormatsInlineASM) { verifyFormat("asm(\"xyz\" : \"=a\"(a), \"=d\"(b) : \"a\"(data));"); + verifyFormat("asm(\"nop\" ::: \"memory\");"); verifyFormat( "asm(\"movq\\t%%rbx, %%rsi\\n\\t\"\n" " \"cpuid\\n\\t\"\n" " \"xchgq\\t%%rbx, %%rsi\\n\\t\"\n" " : \"=a\"(*rEAX), \"=S\"(*rEBX), \"=c\"(*rECX), \"=d\"(*rEDX)\n" " : \"a\"(value));"); + EXPECT_EQ( + "void NS_InvokeByIndex(void *that, unsigned int methodIndex) {\n" + " __asm {\n" + " mov edx,[that] // vtable in edx\n" + " mov eax,methodIndex\n" + " call [edx][eax*4] // stdcall\n" + " }\n" + "}", + format("void NS_InvokeByIndex(void *that, unsigned int methodIndex) {\n" + " __asm {\n" + " mov edx,[that] // vtable in edx\n" + " mov eax,methodIndex\n" + " call [edx][eax*4] // stdcall\n" + " }\n" + "}")); + verifyFormat("void function() {\n" + " // comment\n" + " asm(\"\");\n" + "}"); } TEST_F(FormatTest, FormatTryCatch) { @@ -2247,6 +2386,16 @@ TEST_F(FormatTest, NestedStaticInitializers) { " {kOsWin, \"Windows\"},\n" " {kOsLinux, \"Linux\"},\n" " {kOsCrOS, \"Chrome OS\"}};"); + verifyFormat( + "struct {\n" + " unsigned bit;\n" + " const char *const name;\n" + "} kBitsToOs[] = {\n" + " {kOsMac, \"Mac\"},\n" + " {kOsWin, \"Windows\"},\n" + " {kOsLinux, \"Linux\"},\n" + " {kOsCrOS, \"Chrome OS\"},\n" + "};"); } TEST_F(FormatTest, FormatsSmallMacroDefinitionsInSingleLine) { @@ -2482,6 +2631,14 @@ TEST_F(FormatTest, MacrosWithoutTrailingSemicolon) { " Q_Object\n" " A() {\n}\n" "} ;")); + + // Only if the next line can actually start an unwrapped line. + EXPECT_EQ("SOME_WEIRD_LOG_MACRO << SomeThing;", + format("SOME_WEIRD_LOG_MACRO\n" + "<< SomeThing;")); + + verifyFormat("VISIT_GL_CALL(GenBuffers, void, (GLsizei n, GLuint* buffers), " + "(n, buffers))\n", getChromiumStyle(FormatStyle::LK_Cpp)); } TEST_F(FormatTest, MacroCallsWithoutTrailingSemicolon) { @@ -2659,6 +2816,17 @@ TEST_F(FormatTest, NoEscapedNewlineHandlingInBlockComments) { EXPECT_EQ("/* \\ \\ \\\n*/", format("\\\n/* \\ \\ \\\n*/")); } +TEST_F(FormatTest, DontCrashOnBlockComments) { + EXPECT_EQ( + "int xxxxxxxxx; /* " + "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\n" + "zzzzzz\n" + "0*/", + format("int xxxxxxxxx; /* " + "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy zzzzzz\n" + "0*/")); +} + TEST_F(FormatTest, CalculateSpaceOnConsecutiveLinesInMacro) { verifyFormat("#define A \\\n" " int v( \\\n" @@ -2779,11 +2947,19 @@ TEST_F(FormatTest, LayoutBlockInsideParens) { "});", format(" functionCall ( {int i;int j;} );")); EXPECT_EQ("functionCall({\n" - " int i;\n" - " int j;\n" - " },\n" - " aaaa, bbbb, cccc);", + " int i;\n" + " int j;\n" + "}, aaaa, bbbb, cccc);", format(" functionCall ( {int i;int j;}, aaaa, bbbb, cccc);")); + EXPECT_EQ("functionCall(\n" + " {\n" + " int i;\n" + " int j;\n" + " },\n" + " aaaa, bbbb, // comment\n" + " cccc);", + format(" functionCall ( {int i;int j;}, aaaa, bbbb, // comment\n" + "cccc);")); EXPECT_EQ("functionCall(aaaa, bbbb, { int i; });", format(" functionCall (aaaa, bbbb, {int i;});")); EXPECT_EQ("functionCall(aaaa, bbbb, {\n" @@ -2794,7 +2970,8 @@ TEST_F(FormatTest, LayoutBlockInsideParens) { EXPECT_EQ("functionCall(aaaa, bbbb, { int i; });", format(" functionCall (aaaa, bbbb, {int i;});")); verifyFormat( - "Aaa({\n" + "Aaa(\n" // FIXME: There shouldn't be a linebreak here. + " {\n" " int i; // break\n" " },\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,\n" @@ -2876,10 +3053,9 @@ TEST_F(FormatTest, LayoutNestedBlocks) { FormatStyle Style = getGoogleStyle(); Style.ColumnLimit = 45; verifyFormat("Debug(aaaaa, {\n" - " if (aaaaaaaaaaaaaaaaaaaaaaaa)\n" - " return;\n" - " },\n" - " a);", Style); + " if (aaaaaaaaaaaaaaaaaaaaaaaa) return;\n" + "}, a);", + Style); } TEST_F(FormatTest, IndividualStatementsOfNestedBlocks) { @@ -3025,6 +3201,9 @@ TEST_F(FormatTest, LineBreakingInBinaryExpressions) { verifyFormat("if ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n" " bbbbbbbbbbbbbbbbbb) && // aaaaaaaaaaaaaaaa\n" " cccccc) {\n}"); + verifyFormat("b = a &&\n" + " // Comment\n" + " b.c && d;"); // If the LHS of a comparison is not a binary expression itself, the // additional linebreak confuses many people. @@ -3114,39 +3293,47 @@ TEST_F(FormatTest, ExpressionIndentationBreakingBeforeOperators) { // everything until something with the same indent as the operator is found. // FIXME: Is this a good system? FormatStyle Style = getLLVMStyle(); - Style.BreakBeforeBinaryOperators = true; + Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; verifyFormat( "bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " * bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" - " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" + " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " * bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" + " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" " && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " > ccccccccccccccccccccccccccccccccccccccccc;", + " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " > ccccccccccccccccccccccccccccccccccccccccc;", Style); verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" " == bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}", Style); verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" " == bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}", Style); verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" " == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" - " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}", + " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}", Style); verifyFormat("if () {\n" "} else if (aaaaa\n" " && bbbbb // break\n" - " > ccccc) {\n" + " > ccccc) {\n" "}", Style); + verifyFormat("return (a)\n" + " // comment\n" + " + b;", + Style); + verifyFormat("int aaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " * bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" + " + cc;", + Style); // Forced by comments. verifyFormat( @@ -3167,6 +3354,48 @@ TEST_F(FormatTest, ExpressionIndentationBreakingBeforeOperators) { Style); } +TEST_F(FormatTest, NoOperandAlignment) { + FormatStyle Style = getLLVMStyle(); + Style.AlignOperands = false; + Style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment; + verifyFormat( + "bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " * bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" + " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" + " && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " > ccccccccccccccccccccccccccccccccccccccccc;", + Style); + + verifyFormat("int aaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " * bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" + " + cc;", + Style); + verifyFormat("int a = aa\n" + " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" + " * cccccccccccccccccccccccccccccccccccc;", + Style); + + Style.AlignAfterOpenBracket = false; + verifyFormat("return (a > b\n" + " // comment1\n" + " // comment2\n" + " || c);", + Style); +} + +TEST_F(FormatTest, BreakingBeforeNonAssigmentOperators) { + FormatStyle Style = getLLVMStyle(); + Style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment; + verifyFormat("int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;", + Style); +} + TEST_F(FormatTest, ConstructorInitializers) { verifyFormat("Constructor() : Initializer(FitsOnTheLine) {}"); verifyFormat("Constructor() : Inttializer(FitsOnTheLine) {}", @@ -3409,6 +3638,10 @@ TEST_F(FormatTest, BreaksFunctionDeclarations) { " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" " bbbb bbbb);"); + verifyFormat("void SomeLoooooooooooongFunction(\n" + " std::unique_ptr<aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaa,\n" + " int bbbbbbbbbbbbb);"); // Treat overloaded operators like other functions. verifyFormat("SomeLoooooooooooooooooooooooooogType\n" @@ -3427,6 +3660,10 @@ TEST_F(FormatTest, BreaksFunctionDeclarations) { " int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 1);"); verifyFormat("aaaaaaaaaaaaaaaaaaaaaa\n" "aaaaaaaaaaaaaaaaaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaa = 1);"); + verifyGoogleFormat( + "typename aaaaaaaaaa<aaaaaa>::aaaaaaaaaaa\n" + "aaaaaaaaaa<aaaaaa>::aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" + " bool *aaaaaaaaaaaaaaaaaa, bool *aa) {}"); } TEST_F(FormatTest, TrailingReturnType) { @@ -3437,6 +3674,9 @@ TEST_F(FormatTest, TrailingReturnType) { verifyFormat("template <size_t Order, typename T>\n" "auto load_img(const std::string &filename)\n" " -> alias::tensor<Order, T, mem::tag::cpu> {}"); + verifyFormat("auto SomeFunction(A aaaaaaaaaaaaaaaaaaaaa) const\n" + " -> decltype(f(aaaaaaaaaaaaaaaaaaaaa)) {}"); + verifyFormat("auto doSomething(Aaaaaa *aaaaaa) -> decltype(aaaaaa->f()) {}"); // Not trailing return types. verifyFormat("void f() { auto a = b->c(); }"); @@ -3447,8 +3687,8 @@ TEST_F(FormatTest, BreaksFunctionDeclarationsWithTrailingTokens) { // they are not function-like. FormatStyle Style = getGoogleStyle(); Style.ColumnLimit = 47; - verifyFormat("void\n" - "someLongFunction(int someLongParameter) const {\n}", + verifyFormat("void someLongFunction(\n" + " int someLoooooooooooooongParameter) const {\n}", getLLVMStyleWithColumns(47)); verifyFormat("LoooooongReturnType\n" "someLoooooooongFunction() const {}", @@ -3513,6 +3753,7 @@ TEST_F(FormatTest, BreaksFunctionDeclarationsWithTrailingTokens) { " LOCKS_EXCLUDED(aaaaaaaaaaaaa) {}"); verifyGoogleFormat("void aaaaaaaaaaaaaa(aaaaaaaa aaa) override\n" " AAAAAAAAAAAAAAAAAAAAAAAA(aaaaaaaaaaaaaaa);"); + verifyFormat("SomeFunction([](int i) LOCKS_EXCLUDED(a) {});"); verifyFormat( "void aaaaaaaaaaaaaaaaaa()\n" @@ -3607,9 +3848,25 @@ TEST_F(FormatTest, BreaksDesireably) { " NSTrackingActiveAlways;"); } +TEST_F(FormatTest, FormatsDeclarationsOnePerLine) { + FormatStyle NoBinPacking = getGoogleStyle(); + NoBinPacking.BinPackParameters = false; + NoBinPacking.BinPackArguments = true; + verifyFormat("void f() {\n" + " f(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);\n" + "}", + NoBinPacking); + verifyFormat("void f(int aaaaaaaaaaaaaaaaaaaa,\n" + " int aaaaaaaaaaaaaaaaaaaa,\n" + " int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}", + NoBinPacking); +} + TEST_F(FormatTest, FormatsOneParameterPerLineIfNecessary) { FormatStyle NoBinPacking = getGoogleStyle(); NoBinPacking.BinPackParameters = false; + NoBinPacking.BinPackArguments = false; verifyFormat("f(aaaaaaaaaaaaaaaaaaaa,\n" " aaaaaaaaaaaaaaaaaaaa,\n" " aaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaa);", @@ -3866,6 +4123,66 @@ TEST_F(FormatTest, AlignsAfterReturn) { " code == a || code == b;"); } +TEST_F(FormatTest, AlignsAfterOpenBracket) { + verifyFormat( + "void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaa aaaaaaaa,\n" + " aaaaaaaaa aaaaaaa) {}"); + verifyFormat( + "SomeLongVariableName->someVeryLongFunctionName(aaaaaaaaaaa aaaaaaaaa,\n" + " aaaaaaaaaaa aaaaaaaaa);"); + verifyFormat( + "SomeLongVariableName->someFunction(foooooooo(aaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaaaaaaaa));"); + FormatStyle Style = getLLVMStyle(); + Style.AlignAfterOpenBracket = false; + verifyFormat( + "void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" + " aaaaaaaaaaa aaaaaaaa, aaaaaaaaa aaaaaaa) {}", + Style); + verifyFormat( + "SomeLongVariableName->someVeryLongFunctionName(\n" + " aaaaaaaaaaa aaaaaaaaa, aaaaaaaaaaa aaaaaaaaa);", + Style); + verifyFormat( + "SomeLongVariableName->someFunction(\n" + " foooooooo(aaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaa));", + Style); + verifyFormat( + "void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaa aaaaaaaa,\n" + " aaaaaaaaa aaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}", + Style); + verifyFormat( + "SomeLongVariableName->someVeryLongFunctionName(aaaaaaaaaaa aaaaaaaaa,\n" + " aaaaaaaaaaa aaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);", + Style); + verifyFormat( + "SomeLongVariableName->someFunction(foooooooo(aaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa));", + Style); +} + +TEST_F(FormatTest, ParenthesesAndOperandAlignment) { + FormatStyle Style = getLLVMStyleWithColumns(40); + verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n" + " bbbbbbbbbbbbbbbbbbbbbb);", + Style); + Style.AlignAfterOpenBracket = true; + Style.AlignOperands = false; + verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n" + " bbbbbbbbbbbbbbbbbbbbbb);", + Style); + Style.AlignAfterOpenBracket = false; + Style.AlignOperands = true; + verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n" + " bbbbbbbbbbbbbbbbbbbbbb);", + Style); + Style.AlignAfterOpenBracket = false; + Style.AlignOperands = false; + verifyFormat("int a = f(aaaaaaaaaaaaaaaaaaaaaa &&\n" + " bbbbbbbbbbbbbbbbbbbbbb);", + Style); +} + TEST_F(FormatTest, BreaksConditionalExpressions) { verifyFormat( "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaa\n" @@ -3918,6 +4235,10 @@ TEST_F(FormatTest, BreaksConditionalExpressions) { " aaaaaaaaa\n" " ? b\n" " : c);"); + verifyFormat("return aaaa == bbbb\n" + " // comment\n" + " ? aaaa\n" + " : bbbb;"); verifyFormat( "unsigned Indent =\n" " format(TheLine.First, IndentForLevel[TheLine.Level] >= 0\n" @@ -3948,7 +4269,7 @@ TEST_F(FormatTest, BreaksConditionalExpressions) { " : aaaaaaaaaaaaaaaaaaaaaaaaaaaa;"); FormatStyle NoBinPacking = getLLVMStyle(); - NoBinPacking.BinPackParameters = false; + NoBinPacking.BinPackArguments = false; verifyFormat( "void f() {\n" " g(aaa,\n" @@ -3966,6 +4287,32 @@ TEST_F(FormatTest, BreaksConditionalExpressions) { " ?: aaaaaaaaaaaaaaa);\n" "}", NoBinPacking); + + verifyFormat("SomeFunction(aaaaaaaaaaaaaaaaa,\n" + " // comment.\n" + " ccccccccccccccccccccccccccccccccccccccc\n" + " ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " : bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb);"); + + // Assignments in conditional expressions. Apparently not uncommon :-(. + verifyFormat("return a != b\n" + " // comment\n" + " ? a = b\n" + " : a = b;"); + verifyFormat("return a != b\n" + " // comment\n" + " ? a = a != b\n" + " // comment\n" + " ? a = b\n" + " : a\n" + " : a;\n"); + verifyFormat("return a != b\n" + " // comment\n" + " ? a\n" + " : a = a != b\n" + " // comment\n" + " ? a = b\n" + " : a;"); } TEST_F(FormatTest, BreaksConditionalExpressionsAfterOperator) { @@ -4079,13 +4426,13 @@ TEST_F(FormatTest, DeclarationsOfMultipleVariables) { // line. Also fix indent for breaking after the type, this looks bad. verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaa,\n" - " *b = bbbbbbbbbbbbbbbbbbb;", + " * b = bbbbbbbbbbbbbbbbbbb;", getGoogleStyle()); // Not ideal, but pointer-with-type does not allow much here. verifyGoogleFormat( - "aaaaaaaaa* a = aaaaaaaaaaaaaaaaaaa, *b = bbbbbbbbbbbbbbbbbbb,\n" - " *b = bbbbbbbbbbbbbbbbbbb, *d = ddddddddddddddddddd;"); + "aaaaaaaaa* a = aaaaaaaaaaaaaaaaaaa, * b = bbbbbbbbbbbbbbbbbbb,\n" + " * b = bbbbbbbbbbbbbbbbbbb, * d = ddddddddddddddddddd;"); } TEST_F(FormatTest, ConditionalExpressionsInBrackets) { @@ -4145,6 +4492,40 @@ TEST_F(FormatTest, AlignsStringLiterals) { getLLVMStyleWithColumns(25)); } +TEST_F(FormatTest, AlwaysBreakAfterDefinitionReturnType) { + FormatStyle AfterType = getLLVMStyle(); + AfterType.AlwaysBreakAfterDefinitionReturnType = true; + verifyFormat("const char *\n" + "f(void) {\n" // Break here. + " return \"\";\n" + "}\n" + "const char *bar(void);\n", // No break here. + AfterType); + verifyFormat("template <class T>\n" + "T *\n" + "f(T &c) {\n" // Break here. + " return NULL;\n" + "}\n" + "template <class T> T *f(T &c);\n", // No break here. + AfterType); + AfterType.BreakBeforeBraces = FormatStyle::BS_Stroustrup; + verifyFormat("const char *\n" + "f(void)\n" // Break here. + "{\n" + " return \"\";\n" + "}\n" + "const char *bar(void);\n", // No break here. + AfterType); + verifyFormat("template <class T>\n" + "T *\n" // Problem here: no line break + "f(T &c)\n" // Break here. + "{\n" + " return NULL;\n" + "}\n" + "template <class T> T *f(T &c);\n", // No break here. + AfterType); +} + TEST_F(FormatTest, AlwaysBreakBeforeMultilineStrings) { FormatStyle NoBreak = getLLVMStyle(); NoBreak.AlwaysBreakBeforeMultilineStrings = false; @@ -4308,6 +4689,10 @@ TEST_F(FormatTest, AlignsPipes) { " CHECK_EQ(aaaa, (*bbbbbbbbb)->cccccc)\n" " << \"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\";\n" "}"); + + // Handle 'endl'. + verifyFormat("llvm::errs() << aaaa << endl\n" + " << bbbb << endl;"); } TEST_F(FormatTest, UnderstandsEquals) { @@ -4353,6 +4738,11 @@ TEST_F(FormatTest, WrapsAtFunctionCallsIfNecessary) { verifyFormat("EXPECT_CALL(SomeObject, SomeFunction(Parameter))\n" " .WillRepeatedly(Return(SomeValue));"); + verifyFormat("void f() {\n" + " EXPECT_CALL(SomeObject, SomeFunction(Parameter))\n" + " .Times(2)\n" + " .WillRepeatedly(Return(SomeValue));\n" + "}"); verifyFormat("SomeMap[std::pair(aaaaaaaaaaaa, bbbbbbbbbbbbbbb)].insert(\n" " ccccccccccccccccccccccc);"); verifyFormat("aaaaa(aaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" @@ -4480,6 +4870,8 @@ TEST_F(FormatTest, WrapsTemplateDeclarations) { " B>*>(\n" "\n" " );")); + verifyFormat("int aaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" + " const typename aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaa);"); FormatStyle AlwaysBreak = getLLVMStyle(); AlwaysBreak.AlwaysBreakTemplateDeclarations = true; @@ -4559,11 +4951,14 @@ TEST_F(FormatTest, UnderstandsTemplateParameters) { EXPECT_EQ("A<::A<int>> a;", format("A< ::A<int>> a;", getGoogleStyle())); EXPECT_EQ("A<::A<int>> a;", format("A<::A<int> > a;", getGoogleStyle())); + verifyFormat("A<A>> a;", getChromiumStyle(FormatStyle::LK_Cpp)); + verifyFormat("test >> a >> b;"); verifyFormat("test << a >> b;"); verifyFormat("f<int>();"); verifyFormat("template <typename T> void f() {}"); + verifyFormat("struct A<std::enable_if<sizeof(T2) < sizeof(int32)>::type>;"); // Not template parameters. verifyFormat("return a < b && c > d;"); @@ -4577,6 +4972,8 @@ TEST_F(FormatTest, UnderstandsTemplateParameters) { verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaa >> aaaaa);", getLLVMStyleWithColumns(60)); + verifyFormat("static_assert(is_convertible<A &&, B>::value, \"AAA\");"); + verifyFormat("Constructor(A... a) : a_(X<A>{std::forward<A>(a)}...) {}"); } TEST_F(FormatTest, UnderstandsBinaryOperators) { @@ -4687,6 +5084,7 @@ TEST_F(FormatTest, UnderstandsOverloadedOperators) { " return left.group < right.group;\n" "}"); verifyFormat("SomeType &operator=(const SomeType &S);"); + verifyFormat("f.template operator()<int>();"); verifyGoogleFormat("operator void*();"); verifyGoogleFormat("operator SomeType<SomeType<int>>();"); @@ -4712,6 +5110,12 @@ TEST_F(FormatTest, UnderstandsNewAndDelete) { " delete a;\n" " delete (A *)a;\n" "}"); + verifyFormat("new (aaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaa))\n" + " typename aaaaaaaaaaaaaaaaaaaaaaaa();"); + verifyFormat("auto aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n" + " new (aaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaa))\n" + " typename aaaaaaaaaaaaaaaaaaaaaaaa();"); + verifyFormat("delete[] h->p;"); } TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { @@ -4765,6 +5169,10 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { verifyIndependentOfContext("typedef void (*f)(int *a);"); verifyIndependentOfContext("int i{a * b};"); verifyIndependentOfContext("aaa && aaa->f();"); + verifyIndependentOfContext("int x = ~*p;"); + verifyFormat("Constructor() : a(a), area(width * height) {}"); + verifyFormat("Constructor() : a(a), area(a, width * height) {}"); + verifyFormat("void f() { f(a, c * d); }"); verifyIndependentOfContext("InvalidRegions[*R] = 0;"); @@ -4784,6 +5192,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaa, *aaaaaaaaaaaaaaaaaaaaaaaaaaaaa);"); + verifyGoogleFormat("**outparam = 1;"); verifyGoogleFormat("int main(int argc, char** argv) {}"); verifyGoogleFormat("A<int*> a;"); verifyGoogleFormat("A<int**> a;"); @@ -4798,6 +5207,14 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { verifyGoogleFormat("Type* t = x++ * y;"); verifyGoogleFormat( "const char* const p = reinterpret_cast<const char* const>(q);"); + verifyGoogleFormat("void f(int i = 0, SomeType** temps = NULL);"); + verifyGoogleFormat("void f(Bar* a = nullptr, Bar* b);"); + verifyGoogleFormat("template <typename T>\n" + "void f(int i = 0, SomeType** temps = NULL);"); + + FormatStyle Left = getLLVMStyle(); + Left.PointerAlignment = FormatStyle::PAS_Left; + verifyFormat("x = *a(x) = *a(y);", Left); verifyIndependentOfContext("a = *(x + y);"); verifyIndependentOfContext("a = &(x + y);"); @@ -4858,6 +5275,19 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { verifyFormat("vector<a * b> v;"); verifyFormat("foo<b && false>();"); verifyFormat("foo<b & 1>();"); + verifyFormat("decltype(*::std::declval<const T &>()) void F();"); + verifyFormat( + "template <class T, class = typename std::enable_if<\n" + " std::is_integral<T>::value &&\n" + " (sizeof(T) > 1 || sizeof(T) < 8)>::type>\n" + "void F();", + getLLVMStyleWithColumns(76)); + verifyFormat( + "template <class T,\n" + " class = typename ::std::enable_if<\n" + " ::std::is_array<T>{} && ::std::is_array<T>{}>::type>\n" + "void F();", + getGoogleStyleWithColumns(68)); verifyIndependentOfContext("MACRO(int *i);"); verifyIndependentOfContext("MACRO(auto *a);"); @@ -4880,7 +5310,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) { // FIXME: We cannot handle this case yet; we might be able to figure out that // foo<x> d > v; doesn't make sense. - verifyFormat("foo<a < b && c> d > v;"); + verifyFormat("foo<a<b && c> d> v;"); FormatStyle PointerMiddle = getLLVMStyle(); PointerMiddle.PointerAlignment = FormatStyle::PAS_Middle; @@ -4987,6 +5417,7 @@ TEST_F(FormatTest, FormatsCasts) { verifyFormat("my_int a = (my_int)sizeof(int);"); verifyFormat("return (my_int)aaa;"); verifyFormat("#define x ((int)-1)"); + verifyFormat("#define LENGTH(x, y) (x) - (y) + 1"); verifyFormat("#define p(q) ((int *)&q)"); verifyFormat("fn(a)(b) + 1;"); @@ -4994,11 +5425,12 @@ TEST_F(FormatTest, FormatsCasts) { verifyFormat("void f() { return P ? (my_int)*P : (my_int)0; }"); verifyFormat("my_int a = (my_int)~0;"); verifyFormat("my_int a = (my_int)++a;"); - verifyFormat("my_int a = (my_int)+2;"); + verifyFormat("my_int a = (my_int)-2;"); verifyFormat("my_int a = (my_int)1;"); verifyFormat("my_int a = (my_int *)1;"); verifyFormat("my_int a = (const my_int)-1;"); verifyFormat("my_int a = (const my_int *)-1;"); + verifyFormat("my_int a = (my_int)(my_int)-1;"); // FIXME: single value wrapped with paren will be treated as cast. verifyFormat("void f(int i = (kValue)*kMask) {}"); @@ -5095,6 +5527,8 @@ TEST_F(FormatTest, BreaksLongDeclarations) { "LoooooooooooooooooooooooooooooooongFunctionDeclaration();"); verifyFormat("LoooooooooooooooooooooooooooooooooooooooongReturnType\n" "LooooooooooooooooooooooooooooooooooongFunctionDefinition() {}"); + verifyFormat("LoooooooooooooooooooooooooooooooooooooooongReturnType MACRO\n" + "LooooooooooooooooooooooooooooooooooongFunctionDefinition() {}"); verifyFormat("LoooooooooooooooooooooooooooooooooooooooongReturnType const\n" "LooooooooooooooooooooooooooooooooooongFunctionDefinition() {}"); verifyFormat("decltype(LoooooooooooooooooooooooooooooooooooooooongName)\n" @@ -5156,6 +5590,10 @@ TEST_F(FormatTest, BreaksLongDeclarations) { "aaaaaaaaaaaaaaaaaaaaaaaa<T>::aaaaaaa() {}"); verifyGoogleFormat("A<A<A>> aaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" " int aaaaaaaaaaaaaaaaaaaaaaa);"); + + verifyFormat("typedef size_t (*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)(\n" + " const aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);"); } TEST_F(FormatTest, FormatsArrays) { @@ -5210,6 +5648,8 @@ TEST_F(FormatTest, HandlesIncludeDirectives) { "#include <strstream>\n" "#endif"); + verifyFormat("#define MY_IMPORT <a/b>"); + // Protocol buffer definition or missing "#". verifyFormat("import \"aaaaaaaaaaaaaaaaa/aaaaaaaaaaaaaaa\";", getLLVMStyleWithColumns(30)); @@ -5218,6 +5658,10 @@ TEST_F(FormatTest, HandlesIncludeDirectives) { Style.AlwaysBreakBeforeMultilineStrings = true; Style.ColumnLimit = 0; verifyFormat("#import \"abc.h\"", Style); + + // But 'import' might also be a regular C++ namespace. + verifyFormat("import::SomeFunction(aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaa);"); } //===----------------------------------------------------------------------===// @@ -5385,6 +5829,9 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) { verifyFormat("int foo(int i) { return fo1{}(i); }"); verifyFormat("int foo(int i) { return fo1{}(i); }"); verifyFormat("auto i = decltype(x){};"); + verifyFormat("std::vector<int> v = {1, 0 /* comment */};"); + verifyFormat("Node n{1, Node{1000}, //\n" + " 2};"); // In combination with BinPackParameters = false. FormatStyle NoBinPacking = getLLVMStyle(); @@ -5415,13 +5862,20 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) { " kkkkkk,\n" "};", NoBinPacking); + verifyFormat( + "const Aaaaaa aaaaa = {\n" + " aaaaa, bbbbb, ccccc, ddddd, eeeee, ffffff, ggggg, hhhhhh,\n" + " iiiiii, jjjjjj, kkkkkk, aaaaa, bbbbb, ccccc, ddddd, eeeee,\n" + " ffffff, ggggg, hhhhhh, iiiiii, jjjjjj, kkkkkk,\n" + "};", + NoBinPacking); // FIXME: The alignment of these trailing comments might be bad. Then again, // this might be utterly useless in real code. verifyFormat("Constructor::Constructor()\n" - " : some_value{ //\n" - " aaaaaaa //\n" - " } {}"); + " : some_value{ //\n" + " aaaaaaa, //\n" + " bbbbbbb} {}"); // In braced lists, the first comment is always assumed to belong to the // first element. Thus, it can be moved to the next or previous line as @@ -5445,6 +5899,13 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) { " // Second element:\n" " 2};", getLLVMStyleWithColumns(30))); + // A trailing comma should still lead to an enforced line break. + EXPECT_EQ("vector<int> SomeVector = {\n" + " // aaa\n" + " 1, 2,\n" + "};", + format("vector<int> SomeVector = { // aaa\n" + " 1, 2, };")); FormatStyle ExtraSpaces = getLLVMStyle(); ExtraSpaces.Cpp11BracedListStyle = false; @@ -5473,32 +5934,24 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) { " bbbbbbbbbbbbbbbbbbbb, bbbbb };", ExtraSpaces); verifyFormat("DoSomethingWithVector({} /* No data */);", ExtraSpaces); - verifyFormat("DoSomethingWithVector({\n" - " {} /* No data */\n" - " },\n" - " { { 1, 2 } });", + verifyFormat("DoSomethingWithVector({ {} /* No data */ }, { { 1, 2 } });", ExtraSpaces); verifyFormat( "someFunction(OtherParam,\n" " BracedList{ // comment 1 (Forcing interesting break)\n" " param1, param2,\n" " // comment 2\n" - " param3, param4\n" - " });", + " param3, param4 });", ExtraSpaces); verifyFormat( "std::this_thread::sleep_for(\n" " std::chrono::nanoseconds{ std::chrono::seconds{ 1 } } / 5);", ExtraSpaces); - verifyFormat("std::vector<MyValues> aaaaaaaaaaaaaaaaaaa{\n" - " aaaaaaa, aaaaaaaaaa,\n" - " aaaaa, aaaaaaaaaaaaaaa,\n" - " aaa, aaaaaaaaaa,\n" - " a, aaaaaaaaaaaaaaaaaaaaa,\n" - " aaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaa,\n" - " aaaaaaa, a\n" - "};", - ExtraSpaces); + verifyFormat( + "std::vector<MyValues> aaaaaaaaaaaaaaaaaaa{\n" + " aaaaaaa, aaaaaaaaaa, aaaaa, aaaaaaaaaaaaaaa, aaa, aaaaaaaaaa, a,\n" + " aaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaa, aaaaaaa, a};"); verifyFormat("vector<int> foo = { ::SomeGlobalFunction() };", ExtraSpaces); } @@ -5546,10 +5999,9 @@ TEST_F(FormatTest, FormatsBracedListsInColumnLayout) { " 1, 1, 1, 1, 1, 1, 1, 1, //\n" "};", getLLVMStyleWithColumns(39)); - verifyFormat("vector<int> x = {\n" - " 1, 1, 1, 1, 1, 1, 1, 1,\n" - " /**/ /**/\n" - "};", + verifyFormat("vector<int> x = {1, 1, 1, 1,\n" + " 1, 1, 1, 1,\n" + " /**/ /**/};", getLLVMStyleWithColumns(39)); verifyFormat("return {{aaaaaaaaaaaaaaaaaaaaa},\n" " {aaaaaaaaaaaaaaaaaaa},\n" @@ -6112,7 +6564,7 @@ TEST_F(FormatTest, FormatObjCInterface) { "+ (id)init;\n" "@end"); - verifyGoogleFormat("@interface Foo (HackStuff)<MyProtocol>\n" + verifyGoogleFormat("@interface Foo (HackStuff) <MyProtocol>\n" "+ (id)init;\n" "@end"); @@ -6154,7 +6606,7 @@ TEST_F(FormatTest, FormatObjCInterface) { FormatStyle OnePerLine = getGoogleStyle(); OnePerLine.BinPackParameters = false; - verifyFormat("@interface aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ()<\n" + verifyFormat("@interface aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa () <\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" @@ -6291,11 +6743,16 @@ TEST_F(FormatTest, FormatObjCMethodDeclarations) { " evenLongerKeyword:(float)theInterval\n" " error:(NSError **)theError {\n" "}"); + verifyFormat("- (instancetype)initXxxxxx:(id<x>)x\n" + " y:(id<yyyyyyyyyyyyyyyyyyyy>)y\n" + " NS_DESIGNATED_INITIALIZER;", + getLLVMStyleWithColumns(60)); } TEST_F(FormatTest, FormatObjCMethodExpr) { verifyFormat("[foo bar:baz];"); verifyFormat("return [foo bar:baz];"); + verifyFormat("return (a)[foo bar:baz];"); verifyFormat("f([foo bar:baz]);"); verifyFormat("f(2, [foo bar:baz]);"); verifyFormat("f(2, a ? b : c);"); @@ -6353,8 +6810,10 @@ TEST_F(FormatTest, FormatObjCMethodExpr) { // Whew! verifyFormat("return in[42];"); + verifyFormat("for (auto v : in[1]) {\n}"); verifyFormat("for (id foo in [self getStuffFor:bla]) {\n" "}"); + verifyFormat("[self aaaaa:MACRO(a, b:, c:)];"); verifyFormat("[self stuffWithInt:(4 + 2) float:4.5];"); verifyFormat("[self stuffWithInt:a ? b : c float:4.5];"); @@ -6408,17 +6867,16 @@ TEST_F(FormatTest, FormatObjCMethodExpr) { " der:NO]);\n" "}", getLLVMStyleWithColumns(70)); - verifyFormat("{\n" - " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n" - " initWithContentRect:NSMakeRect(origin_global.x,\n" - " origin_global.y,\n" - " pos.width(),\n" - " pos.height())\n" - " styleMask:NSBorderlessWindowMask\n" - " backing:NSBackingStoreBuffered\n" - " defer:NO]);\n" - "}", - getChromiumStyle(FormatStyle::LK_Cpp)); + verifyFormat( + "void f() {\n" + " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n" + " initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,\n" + " pos.width(), pos.height())\n" + " styleMask:NSBorderlessWindowMask\n" + " backing:NSBackingStoreBuffered\n" + " defer:NO]);\n" + "}", + getChromiumStyle(FormatStyle::LK_Cpp)); verifyFormat("[contentsContainer replaceSubview:[subviews objectAtIndex:0]\n" " with:contentsNativeView];"); @@ -6957,22 +7415,14 @@ TEST_F(FormatTest, BreaksWideAndNSStringLiterals) { format("@\"NSString literal\";", getGoogleStyleWithColumns(19))); } -TEST_F(FormatTest, BreaksRawStringLiterals) { - EXPECT_EQ("R\"x(raw )x\"\n" - "R\"x(literal)x\";", - format("R\"x(raw literal)x\";", getGoogleStyleWithColumns(15))); - EXPECT_EQ("uR\"x(raw )x\"\n" - "uR\"x(literal)x\";", - format("uR\"x(raw literal)x\";", getGoogleStyleWithColumns(16))); - EXPECT_EQ("u8R\"x(raw )x\"\n" - "u8R\"x(literal)x\";", - format("u8R\"x(raw literal)x\";", getGoogleStyleWithColumns(17))); - EXPECT_EQ("LR\"x(raw )x\"\n" - "LR\"x(literal)x\";", - format("LR\"x(raw literal)x\";", getGoogleStyleWithColumns(16))); - EXPECT_EQ("UR\"x(raw )x\"\n" - "UR\"x(literal)x\";", - format("UR\"x(raw literal)x\";", getGoogleStyleWithColumns(16))); +TEST_F(FormatTest, DoesNotBreakRawStringLiterals) { + FormatStyle Style = getGoogleStyleWithColumns(15); + EXPECT_EQ("R\"x(raw literal)x\";", format("R\"x(raw literal)x\";", Style)); + EXPECT_EQ("uR\"x(raw literal)x\";", format("uR\"x(raw literal)x\";", Style)); + EXPECT_EQ("LR\"x(raw literal)x\";", format("LR\"x(raw literal)x\";", Style)); + EXPECT_EQ("UR\"x(raw literal)x\";", format("UR\"x(raw literal)x\";", Style)); + EXPECT_EQ("u8R\"x(raw literal)x\";", + format("u8R\"x(raw literal)x\";", Style)); } TEST_F(FormatTest, BreaksStringLiteralsWithin_TMacro) { @@ -7161,11 +7611,6 @@ TEST_F(FormatTest, DoNotBreakStringLiteralsInEscapeSequence) { "\"00000000\"\n" "\"1\"", format("\"test\\000000000001\"", getLLVMStyleWithColumns(10))); - // FIXME: We probably don't need to care about escape sequences in raw - // literals. - EXPECT_EQ("R\"(\\x)\"\n" - "R\"(\\x00)\"\n", - format("R\"(\\x\\x00)\"\n", getGoogleStyleWithColumns(7))); } TEST_F(FormatTest, DoNotCreateUnreasonableUnwrappedLines) { @@ -7213,7 +7658,7 @@ TEST_F(FormatTest, ConfigurableIndentWidth) { } TEST_F(FormatTest, ConfigurableFunctionDeclarationIndentAfterType) { - verifyFormat("void\n" + verifyFormat("double\n" "f();", getLLVMStyleWithColumns(8)); } @@ -7353,11 +7798,10 @@ TEST_F(FormatTest, ConfigurableUseOfTab) { Tab); verifyFormat("{\n" "\tQ({\n" - "\t\t int a;\n" - "\t\t someFunction(aaaaaaaaaa,\n" - "\t\t bbbbbbbbb);\n" - "\t },\n" - "\t p);\n" + "\t\tint a;\n" + "\t\tsomeFunction(aaaaaaaa,\n" + "\t\t bbbbbbb);\n" + "\t}, p);\n" "}", Tab); EXPECT_EQ("{\n" @@ -7521,6 +7965,14 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeParens) { "default:\n" " break;\n" "}", NoSpace); + verifyFormat("auto i = std::make_unique<int>(5);", NoSpace); + verifyFormat("size_t x = sizeof(x);", NoSpace); + verifyFormat("auto f(int x) -> decltype(x);", NoSpace); + verifyFormat("int f(T x) noexcept(x.create());", NoSpace); + verifyFormat("alignas(128) char a[128];", NoSpace); + verifyFormat("size_t x = alignof(MyType);", NoSpace); + verifyFormat("static_assert(sizeof(char) == 1, \"Impossible!\");", NoSpace); + verifyFormat("int f() throw(Deprecated);", NoSpace); FormatStyle Space = getLLVMStyle(); Space.SpaceBeforeParens = FormatStyle::SBPO_Always; @@ -7557,6 +8009,14 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeParens) { verifyFormat("#if defined(x)\n" "#endif", Space); + verifyFormat("auto i = std::make_unique<int> (5);", Space); + verifyFormat("size_t x = sizeof (x);", Space); + verifyFormat("auto f (int x) -> decltype (x);", Space); + verifyFormat("int f (T x) noexcept (x.create ());", Space); + verifyFormat("alignas (128) char a[128];", Space); + verifyFormat("size_t x = alignof (MyType);", Space); + verifyFormat("static_assert (sizeof (char) == 1, \"Impossible!\");", Space); + verifyFormat("int f () throw (Deprecated);", Space); } TEST_F(FormatTest, ConfigurableSpacesInParentheses) { @@ -7618,6 +8078,60 @@ TEST_F(FormatTest, ConfigurableSpacesInParentheses) { "default:\n" " break;\n" "}", Spaces); + + Spaces.SpaceAfterCStyleCast = true; + verifyFormat("call(x, y, z);", Spaces); + verifyFormat("while (( bool ) 1)\n" + " continue;", + Spaces); + verifyFormat("for (;;)\n" + " continue;", + Spaces); + verifyFormat("if (true)\n" + " f( );\n" + "else if (true)\n" + " f( );", + Spaces); + verifyFormat("do {\n" + " do_something(( int ) i);\n" + "} while (something( ));", + Spaces); + verifyFormat("switch (x) {\n" + "default:\n" + " break;\n" + "}", + Spaces); + Spaces.SpacesInCStyleCastParentheses = false; + Spaces.SpaceAfterCStyleCast = true; + verifyFormat("while ((bool) 1)\n" + " continue;", + Spaces); + verifyFormat("do {\n" + " do_something((int) i);\n" + "} while (something( ));", + Spaces); +} + +TEST_F(FormatTest, ConfigurableSpacesInSquareBrackets) { + verifyFormat("int a[5];"); + verifyFormat("a[3] += 42;"); + + FormatStyle Spaces = getLLVMStyle(); + Spaces.SpacesInSquareBrackets = true; + // Lambdas unchanged. + verifyFormat("int c = []() -> int { return 2; }();\n", Spaces); + verifyFormat("return [i, args...] {};", Spaces); + + // Not lambdas. + verifyFormat("int a[ 5 ];", Spaces); + verifyFormat("a[ 3 ] += 42;", Spaces); + verifyFormat("constexpr char hello[]{\"hello\"};", Spaces); + verifyFormat("double &operator[](int i) { return 0; }\n" + "int i;", + Spaces); + verifyFormat("std::unique_ptr<int[]> foo() {}", Spaces); + verifyFormat("int i = a[ a ][ a ]->f();", Spaces); + verifyFormat("int i = (*b)[ a ]->f();", Spaces); } TEST_F(FormatTest, ConfigurableSpaceBeforeAssignmentOperators) { @@ -7633,8 +8147,8 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeAssignmentOperators) { } TEST_F(FormatTest, LinuxBraceBreaking) { - FormatStyle BreakBeforeBrace = getLLVMStyle(); - BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Linux; + FormatStyle LinuxBraceStyle = getLLVMStyle(); + LinuxBraceStyle.BreakBeforeBraces = FormatStyle::BS_Linux; verifyFormat("namespace a\n" "{\n" "class A\n" @@ -7647,14 +8161,33 @@ TEST_F(FormatTest, LinuxBraceBreaking) { " }\n" " }\n" " void g() { return; }\n" - "}\n" - "}", - BreakBeforeBrace); + "};\n" + "struct B {\n" + " int x;\n" + "};\n" + "}\n", + LinuxBraceStyle); + verifyFormat("enum X {\n" + " Y = 0,\n" + "}\n", + LinuxBraceStyle); + verifyFormat("struct S {\n" + " int Type;\n" + " union {\n" + " int x;\n" + " double y;\n" + " } Value;\n" + " class C\n" + " {\n" + " MyFavoriteType Value;\n" + " } Class;\n" + "}\n", + LinuxBraceStyle); } TEST_F(FormatTest, StroustrupBraceBreaking) { - FormatStyle BreakBeforeBrace = getLLVMStyle(); - BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Stroustrup; + FormatStyle StroustrupBraceStyle = getLLVMStyle(); + StroustrupBraceStyle.BreakBeforeBraces = FormatStyle::BS_Stroustrup; verifyFormat("namespace a {\n" "class A {\n" " void f()\n" @@ -7665,9 +8198,23 @@ TEST_F(FormatTest, StroustrupBraceBreaking) { " }\n" " }\n" " void g() { return; }\n" - "}\n" - "}", - BreakBeforeBrace); + "};\n" + "struct B {\n" + " int x;\n" + "};\n" + "}\n", + StroustrupBraceStyle); + + verifyFormat("void foo()\n" + "{\n" + " if (a) {\n" + " a();\n" + " }\n" + " else {\n" + " b();\n" + " }\n" + "}\n", + StroustrupBraceStyle); verifyFormat("#ifdef _DEBUG\n" "int foo(int i = 0)\n" @@ -7677,7 +8224,7 @@ TEST_F(FormatTest, StroustrupBraceBreaking) { "{\n" " return i;\n" "}", - BreakBeforeBrace); + StroustrupBraceStyle); verifyFormat("void foo() {}\n" "void bar()\n" @@ -7689,7 +8236,7 @@ TEST_F(FormatTest, StroustrupBraceBreaking) { "{\n" "}\n" "#endif", - BreakBeforeBrace); + StroustrupBraceStyle); verifyFormat("void foobar() { int i = 5; }\n" "#ifdef _DEBUG\n" @@ -7697,12 +8244,12 @@ TEST_F(FormatTest, StroustrupBraceBreaking) { "#else\n" "void bar() { foobar(); }\n" "#endif", - BreakBeforeBrace); + StroustrupBraceStyle); } TEST_F(FormatTest, AllmanBraceBreaking) { - FormatStyle BreakBeforeBrace = getLLVMStyle(); - BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Allman; + FormatStyle AllmanBraceStyle = getLLVMStyle(); + AllmanBraceStyle.BreakBeforeBraces = FormatStyle::BS_Allman; verifyFormat("namespace a\n" "{\n" "class A\n" @@ -7716,9 +8263,13 @@ TEST_F(FormatTest, AllmanBraceBreaking) { " }\n" " }\n" " void g() { return; }\n" - "}\n" + "};\n" + "struct B\n" + "{\n" + " int x;\n" + "};\n" "}", - BreakBeforeBrace); + AllmanBraceStyle); verifyFormat("void f()\n" "{\n" @@ -7735,7 +8286,7 @@ TEST_F(FormatTest, AllmanBraceBreaking) { " c();\n" " }\n" "}\n", - BreakBeforeBrace); + AllmanBraceStyle); verifyFormat("void f()\n" "{\n" @@ -7752,7 +8303,7 @@ TEST_F(FormatTest, AllmanBraceBreaking) { " c();\n" " } while (false)\n" "}\n", - BreakBeforeBrace); + AllmanBraceStyle); verifyFormat("void f(int a)\n" "{\n" @@ -7772,18 +8323,18 @@ TEST_F(FormatTest, AllmanBraceBreaking) { " break;\n" " }\n" "}\n", - BreakBeforeBrace); + AllmanBraceStyle); verifyFormat("enum X\n" "{\n" " Y = 0,\n" "}\n", - BreakBeforeBrace); + AllmanBraceStyle); verifyFormat("enum X\n" "{\n" " Y = 0\n" "}\n", - BreakBeforeBrace); + AllmanBraceStyle); verifyFormat("@interface BSApplicationController ()\n" "{\n" @@ -7791,7 +8342,7 @@ TEST_F(FormatTest, AllmanBraceBreaking) { " id _extraIvar;\n" "}\n" "@end\n", - BreakBeforeBrace); + AllmanBraceStyle); verifyFormat("#ifdef _DEBUG\n" "int foo(int i = 0)\n" @@ -7801,7 +8352,7 @@ TEST_F(FormatTest, AllmanBraceBreaking) { "{\n" " return i;\n" "}", - BreakBeforeBrace); + AllmanBraceStyle); verifyFormat("void foo() {}\n" "void bar()\n" @@ -7813,7 +8364,7 @@ TEST_F(FormatTest, AllmanBraceBreaking) { "{\n" "}\n" "#endif", - BreakBeforeBrace); + AllmanBraceStyle); verifyFormat("void foobar() { int i = 5; }\n" "#ifdef _DEBUG\n" @@ -7821,37 +8372,42 @@ TEST_F(FormatTest, AllmanBraceBreaking) { "#else\n" "void bar() { foobar(); }\n" "#endif", - BreakBeforeBrace); + AllmanBraceStyle); // This shouldn't affect ObjC blocks.. verifyFormat("[self doSomeThingWithACompletionHandler:^{\n" - " // ...\n" - " int i;\n" + " // ...\n" + " int i;\n" "}];", - BreakBeforeBrace); + AllmanBraceStyle); verifyFormat("void (^block)(void) = ^{\n" - " // ...\n" - " int i;\n" + " // ...\n" + " int i;\n" "};", - BreakBeforeBrace); + AllmanBraceStyle); // .. or dict literals. verifyFormat("void f()\n" "{\n" " [object someMethod:@{ @\"a\" : @\"b\" }];\n" "}", - BreakBeforeBrace); + AllmanBraceStyle); + verifyFormat("int f()\n" + "{ // comment\n" + " return 42;\n" + "}", + AllmanBraceStyle); - BreakBeforeBrace.ColumnLimit = 19; - verifyFormat("void f() { int i; }", BreakBeforeBrace); - BreakBeforeBrace.ColumnLimit = 18; + AllmanBraceStyle.ColumnLimit = 19; + verifyFormat("void f() { int i; }", AllmanBraceStyle); + AllmanBraceStyle.ColumnLimit = 18; verifyFormat("void f()\n" "{\n" " int i;\n" "}", - BreakBeforeBrace); - BreakBeforeBrace.ColumnLimit = 80; + AllmanBraceStyle); + AllmanBraceStyle.ColumnLimit = 80; - FormatStyle BreakBeforeBraceShortIfs = BreakBeforeBrace; + FormatStyle BreakBeforeBraceShortIfs = AllmanBraceStyle; BreakBeforeBraceShortIfs.AllowShortIfStatementsOnASingleLine = true; BreakBeforeBraceShortIfs.AllowShortLoopsOnASingleLine = true; verifyFormat("void f(bool b)\n" @@ -8108,34 +8664,41 @@ TEST_F(FormatTest, GetsCorrectBasedOnStyle) { EXPECT_ALL_STYLES_EQUAL(Styles); } +#define CHECK_PARSE_BOOL_FIELD(FIELD, CONFIG_NAME) \ + Style.FIELD = false; \ + EXPECT_EQ(0, parseConfiguration(CONFIG_NAME ": true", &Style).value()); \ + EXPECT_TRUE(Style.FIELD); \ + EXPECT_EQ(0, parseConfiguration(CONFIG_NAME ": false", &Style).value()); \ + EXPECT_FALSE(Style.FIELD); + +#define CHECK_PARSE_BOOL(FIELD) CHECK_PARSE_BOOL_FIELD(FIELD, #FIELD) + #define CHECK_PARSE(TEXT, FIELD, VALUE) \ EXPECT_NE(VALUE, Style.FIELD); \ EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value()); \ EXPECT_EQ(VALUE, Style.FIELD) -#define CHECK_PARSE_BOOL(FIELD) \ - Style.FIELD = false; \ - EXPECT_EQ(0, parseConfiguration(#FIELD ": true", &Style).value()); \ - EXPECT_TRUE(Style.FIELD); \ - EXPECT_EQ(0, parseConfiguration(#FIELD ": false", &Style).value()); \ - EXPECT_FALSE(Style.FIELD); - -TEST_F(FormatTest, ParsesConfiguration) { +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(AllowAllParametersOfDeclarationOnNextLine); CHECK_PARSE_BOOL(AllowShortBlocksOnASingleLine); + CHECK_PARSE_BOOL(AllowShortCaseLabelsOnASingleLine); CHECK_PARSE_BOOL(AllowShortIfStatementsOnASingleLine); CHECK_PARSE_BOOL(AllowShortLoopsOnASingleLine); + CHECK_PARSE_BOOL(AlwaysBreakAfterDefinitionReturnType); CHECK_PARSE_BOOL(AlwaysBreakTemplateDeclarations); CHECK_PARSE_BOOL(BinPackParameters); - CHECK_PARSE_BOOL(BreakBeforeBinaryOperators); + CHECK_PARSE_BOOL(BinPackArguments); 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(IndentCaseLabels); CHECK_PARSE_BOOL(IndentWrappedFunctionNames); CHECK_PARSE_BOOL(KeepEmptyLinesAtTheStartOfBlocks); @@ -8143,15 +8706,24 @@ TEST_F(FormatTest, ParsesConfiguration) { CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList); CHECK_PARSE_BOOL(Cpp11BracedListStyle); CHECK_PARSE_BOOL(SpacesInParentheses); + CHECK_PARSE_BOOL(SpacesInSquareBrackets); CHECK_PARSE_BOOL(SpacesInAngles); CHECK_PARSE_BOOL(SpaceInEmptyParentheses); CHECK_PARSE_BOOL(SpacesInContainerLiterals); CHECK_PARSE_BOOL(SpacesInCStyleCastParentheses); + CHECK_PARSE_BOOL(SpaceAfterCStyleCast); CHECK_PARSE_BOOL(SpaceBeforeAssignmentOperators); +} + +#undef CHECK_PARSE_BOOL +TEST_F(FormatTest, ParsesConfiguration) { + FormatStyle Style = {}; + Style.Language = FormatStyle::LK_Cpp; CHECK_PARSE("AccessModifierOffset: -1234", AccessModifierOffset, -1234); CHECK_PARSE("ConstructorInitializerIndentWidth: 1234", ConstructorInitializerIndentWidth, 1234u); + CHECK_PARSE("ObjCBlockIndentWidth: 1234", ObjCBlockIndentWidth, 1234u); CHECK_PARSE("ColumnLimit: 1234", ColumnLimit, 1234u); CHECK_PARSE("MaxEmptyLinesToKeep: 1234", MaxEmptyLinesToKeep, 1234u); CHECK_PARSE("PenaltyBreakBeforeFirstCallParameter: 1234", @@ -8165,9 +8737,19 @@ TEST_F(FormatTest, ParsesConfiguration) { CHECK_PARSE("ContinuationIndentWidth: 11", ContinuationIndentWidth, 11u); Style.PointerAlignment = FormatStyle::PAS_Middle; - CHECK_PARSE("PointerAlignment: Left", PointerAlignment, FormatStyle::PAS_Left); - CHECK_PARSE("PointerAlignment: Right", PointerAlignment, FormatStyle::PAS_Right); - CHECK_PARSE("PointerAlignment: Middle", PointerAlignment, FormatStyle::PAS_Middle); + CHECK_PARSE("PointerAlignment: Left", PointerAlignment, + FormatStyle::PAS_Left); + CHECK_PARSE("PointerAlignment: Right", PointerAlignment, + FormatStyle::PAS_Right); + CHECK_PARSE("PointerAlignment: Middle", PointerAlignment, + FormatStyle::PAS_Middle); + // For backward compatibility: + CHECK_PARSE("PointerBindsToType: Left", PointerAlignment, + FormatStyle::PAS_Left); + CHECK_PARSE("PointerBindsToType: Right", PointerAlignment, + FormatStyle::PAS_Right); + CHECK_PARSE("PointerBindsToType: Middle", PointerAlignment, + FormatStyle::PAS_Middle); Style.Standard = FormatStyle::LS_Auto; CHECK_PARSE("Standard: Cpp03", Standard, FormatStyle::LS_Cpp03); @@ -8176,24 +8758,41 @@ TEST_F(FormatTest, ParsesConfiguration) { CHECK_PARSE("Standard: C++11", Standard, FormatStyle::LS_Cpp11); CHECK_PARSE("Standard: Auto", Standard, FormatStyle::LS_Auto); + Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; + CHECK_PARSE("BreakBeforeBinaryOperators: NonAssignment", + BreakBeforeBinaryOperators, FormatStyle::BOS_NonAssignment); + CHECK_PARSE("BreakBeforeBinaryOperators: None", BreakBeforeBinaryOperators, + FormatStyle::BOS_None); + CHECK_PARSE("BreakBeforeBinaryOperators: All", BreakBeforeBinaryOperators, + FormatStyle::BOS_All); + // For backward compatibility: + CHECK_PARSE("BreakBeforeBinaryOperators: false", BreakBeforeBinaryOperators, + FormatStyle::BOS_None); + CHECK_PARSE("BreakBeforeBinaryOperators: true", BreakBeforeBinaryOperators, + FormatStyle::BOS_All); + Style.UseTab = FormatStyle::UT_ForIndentation; - CHECK_PARSE("UseTab: false", UseTab, FormatStyle::UT_Never); - CHECK_PARSE("UseTab: true", UseTab, FormatStyle::UT_Always); CHECK_PARSE("UseTab: Never", UseTab, FormatStyle::UT_Never); CHECK_PARSE("UseTab: ForIndentation", UseTab, FormatStyle::UT_ForIndentation); CHECK_PARSE("UseTab: Always", UseTab, FormatStyle::UT_Always); + // For backward compatibility: + CHECK_PARSE("UseTab: false", UseTab, FormatStyle::UT_Never); + CHECK_PARSE("UseTab: true", UseTab, FormatStyle::UT_Always); Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; - CHECK_PARSE("AllowShortFunctionsOnASingleLine: false", - AllowShortFunctionsOnASingleLine, FormatStyle::SFS_None); - CHECK_PARSE("AllowShortFunctionsOnASingleLine: true", - AllowShortFunctionsOnASingleLine, FormatStyle::SFS_All); CHECK_PARSE("AllowShortFunctionsOnASingleLine: None", AllowShortFunctionsOnASingleLine, FormatStyle::SFS_None); CHECK_PARSE("AllowShortFunctionsOnASingleLine: Inline", AllowShortFunctionsOnASingleLine, FormatStyle::SFS_Inline); + CHECK_PARSE("AllowShortFunctionsOnASingleLine: Empty", + AllowShortFunctionsOnASingleLine, FormatStyle::SFS_Empty); CHECK_PARSE("AllowShortFunctionsOnASingleLine: All", AllowShortFunctionsOnASingleLine, FormatStyle::SFS_All); + // For backward compatibility: + CHECK_PARSE("AllowShortFunctionsOnASingleLine: false", + AllowShortFunctionsOnASingleLine, FormatStyle::SFS_None); + CHECK_PARSE("AllowShortFunctionsOnASingleLine: true", + AllowShortFunctionsOnASingleLine, FormatStyle::SFS_All); Style.SpaceBeforeParens = FormatStyle::SBPO_Always; CHECK_PARSE("SpaceBeforeParens: Never", SpaceBeforeParens, @@ -8344,7 +8943,6 @@ TEST_F(FormatTest, ParsesConfigurationWithLanguages) { } #undef CHECK_PARSE -#undef CHECK_PARSE_BOOL TEST_F(FormatTest, UsesLanguageForBasedOnStyle) { FormatStyle Style = {}; @@ -8519,7 +9117,10 @@ TEST_F(FormatTest, ConstructorInitializerIndentWidth) { ": aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n" " aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}", Style); +} +TEST_F(FormatTest, BreakConstructorInitializersBeforeComma) { + FormatStyle Style = getLLVMStyle(); Style.BreakConstructorInitializersBeforeComma = true; Style.ConstructorInitializerIndentWidth = 4; verifyFormat("SomeClass::Constructor()\n" @@ -8592,6 +9193,11 @@ TEST_F(FormatTest, ConstructorInitializerIndentWidth) { Style); } +TEST_F(FormatTest, Destructors) { + verifyFormat("void F(int &i) { i.~int(); }"); + verifyFormat("void F(int &i) { i->~int(); }"); +} + TEST_F(FormatTest, FormatsWithWebKitStyle) { FormatStyle Style = getWebKitStyle(); @@ -8644,7 +9250,7 @@ TEST_F(FormatTest, FormatsWithWebKitStyle) { verifyFormat("Constructor()\n" " : aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa)\n" " , aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaa, // break\n" - " aaaaaaaaaaaaaa)\n" + " aaaaaaaaaaaaaa)\n" " , aaaaaaaaaaaaaaaaaaaaaaa()\n" "{\n" "}", @@ -8685,6 +9291,11 @@ TEST_F(FormatTest, FormatsWithWebKitStyle) { "double b; // align comments.", Style); + // Do not align operands. + EXPECT_EQ("ASSERT(aaaa\n" + " || bbbb);", + format("ASSERT ( aaaa\n||bbbb);", Style)); + // Accept input's line breaks. EXPECT_EQ("if (aaaaaaaaaaaaaaa\n" " || bbbbbbbbbbbbbbb) {\n" @@ -8764,30 +9375,50 @@ TEST_F(FormatTest, FormatsLambdas) { verifyFormat("SomeFunction([]() { // A cool function...\n" " return 43;\n" "});"); + EXPECT_EQ("SomeFunction([]() {\n" + "#define A a\n" + " return 43;\n" + "});", + format("SomeFunction([](){\n" + "#define A a\n" + "return 43;\n" + "});")); verifyFormat("void f() {\n" " SomeFunction([](decltype(x), A *a) {});\n" "}"); verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" " [](const aaaaaaaaaa &a) { return a; });"); + verifyFormat("string abc = SomeFunction(aaaaaaaaaaaaa, aaaaa, []() {\n" + " SomeOtherFunctioooooooooooooooooooooooooon();\n" + "});"); + verifyFormat("Constructor()\n" + " : Field([] { // comment\n" + " int i;\n" + " }) {}"); // Lambdas with return types. verifyFormat("int c = []() -> int { return 2; }();\n"); verifyFormat("int c = []() -> vector<int> { return {2}; }();\n"); verifyFormat("Foo([]() -> std::vector<int> { return {2}; }());"); + verifyGoogleFormat("auto a = [&b, c](D* d) -> D* {};"); + 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("auto aaaaaaaa = [](int i, // break for some reason\n" " int j) -> int {\n" " return ffffffffffffffffffffffffffffffffffffffffffff(i * j);\n" "};"); // Multiple lambdas in the same parentheses change indentation rules. - verifyFormat("SomeFunction([]() {\n" - " int i = 42;\n" - " return i;\n" - " },\n" - " []() {\n" - " int j = 43;\n" - " return j;\n" - " });"); + verifyFormat("SomeFunction(\n" + " []() {\n" + " int i = 42;\n" + " return i;\n" + " },\n" + " []() {\n" + " int j = 43;\n" + " return j;\n" + " });"); // More complex introducers. verifyFormat("return [i, args...] {};"); @@ -8810,89 +9441,113 @@ TEST_F(FormatTest, FormatsLambdas) { verifyFormat("void f() {\n" " MACRO((const AA &a) { return 1; });\n" "}"); + + verifyFormat("if (blah_blah(whatever, whatever, [] {\n" + " doo_dah();\n" + " doo_dah();\n" + " })) {\n" + "}"); } TEST_F(FormatTest, FormatsBlocks) { - verifyFormat("int (^Block)(int, int);"); - verifyFormat("int (^Block1)(int, int) = ^(int i, int j)"); - verifyFormat("void (^block)(int) = ^(id test) { int i; };"); - verifyFormat("void (^block)(int) = ^(int test) { int i; };"); - verifyFormat("void (^block)(int) = ^id(int test) { int i; };"); - verifyFormat("void (^block)(int) = ^int(int test) { int i; };"); - - verifyFormat("foo(^{ bar(); });"); - verifyFormat("foo(a, ^{ bar(); });"); - - // FIXME: Make whitespace formatting consistent. Ask a ObjC dev how - // it would ideally look. - verifyFormat("[operation setCompletionBlock:^{ [self onOperationDone]; }];"); - verifyFormat("int i = {[operation setCompletionBlock : ^{ [self " - "onOperationDone]; }]};"); - verifyFormat("[operation setCompletionBlock:^(int *i) { f(); }];"); - verifyFormat("int a = [operation block:^int(int *i) { return 1; }];"); + FormatStyle ShortBlocks = getLLVMStyle(); + ShortBlocks.AllowShortBlocksOnASingleLine = true; + verifyFormat("int (^Block)(int, int);", ShortBlocks); + verifyFormat("int (^Block1)(int, int) = ^(int i, int j)", ShortBlocks); + verifyFormat("void (^block)(int) = ^(id test) { int i; };", ShortBlocks); + verifyFormat("void (^block)(int) = ^(int test) { int i; };", ShortBlocks); + verifyFormat("void (^block)(int) = ^id(int test) { int i; };", ShortBlocks); + verifyFormat("void (^block)(int) = ^int(int test) { int i; };", ShortBlocks); + + verifyFormat("foo(^{ bar(); });", ShortBlocks); + verifyFormat("foo(a, ^{ bar(); });", ShortBlocks); + verifyFormat("{ void (^block)(Object *x); }", ShortBlocks); + + verifyFormat("[operation setCompletionBlock:^{\n" + " [self onOperationDone];\n" + "}];"); + verifyFormat("int i = {[operation setCompletionBlock:^{\n" + " [self onOperationDone];\n" + "}]};"); + verifyFormat("[operation setCompletionBlock:^(int *i) {\n" + " f();\n" + "}];"); + verifyFormat("int a = [operation block:^int(int *i) {\n" + " return 1;\n" + "}];"); verifyFormat("[myObject doSomethingWith:arg1\n" - " aaa:^int(int *a) { return 1; }\n" + " aaa:^int(int *a) {\n" + " return 1;\n" + " }\n" " bbb:f(a * bbbbbbbb)];"); verifyFormat("[operation setCompletionBlock:^{\n" - " [self.delegate newDataAvailable];\n" + " [self.delegate newDataAvailable];\n" "}];", getLLVMStyleWithColumns(60)); verifyFormat("dispatch_async(_fileIOQueue, ^{\n" - " NSString *path = [self sessionFilePath];\n" - " if (path) {\n" - " // ...\n" - " }\n" + " NSString *path = [self sessionFilePath];\n" + " if (path) {\n" + " // ...\n" + " }\n" "});"); verifyFormat("[[SessionService sharedService]\n" " loadWindowWithCompletionBlock:^(SessionWindow *window) {\n" - " if (window) {\n" - " [self windowDidLoad:window];\n" - " } else {\n" - " [self errorLoadingWindow];\n" - " }\n" + " if (window) {\n" + " [self windowDidLoad:window];\n" + " } else {\n" + " [self errorLoadingWindow];\n" + " }\n" " }];"); verifyFormat("void (^largeBlock)(void) = ^{\n" - " // ...\n" + " // ...\n" "};\n", getLLVMStyleWithColumns(40)); verifyFormat("[[SessionService sharedService]\n" " loadWindowWithCompletionBlock: //\n" " ^(SessionWindow *window) {\n" - " if (window) {\n" - " [self windowDidLoad:window];\n" - " } else {\n" - " [self errorLoadingWindow];\n" - " }\n" + " if (window) {\n" + " [self windowDidLoad:window];\n" + " } else {\n" + " [self errorLoadingWindow];\n" + " }\n" " }];", getLLVMStyleWithColumns(60)); verifyFormat("[myObject doSomethingWith:arg1\n" " firstBlock:^(Foo *a) {\n" - " // ...\n" - " int i;\n" + " // ...\n" + " int i;\n" " }\n" " secondBlock:^(Bar *b) {\n" - " // ...\n" - " int i;\n" + " // ...\n" + " int i;\n" " }\n" " thirdBlock:^Foo(Bar *b) {\n" - " // ...\n" - " int i;\n" + " // ...\n" + " int i;\n" " }];"); verifyFormat("[myObject doSomethingWith:arg1\n" " firstBlock:-1\n" " secondBlock:^(Bar *b) {\n" - " // ...\n" - " int i;\n" + " // ...\n" + " int i;\n" " }];"); verifyFormat("f(^{\n" - " @autoreleasepool {\n" - " if (a) {\n" - " g();\n" - " }\n" + " @autoreleasepool {\n" + " if (a) {\n" + " g();\n" " }\n" + " }\n" "});"); + verifyFormat("Block b = ^int *(A *a, B *b) {}"); + + FormatStyle FourIndent = getLLVMStyle(); + FourIndent.ObjCBlockIndentWidth = 4; + verifyFormat("[operation setCompletionBlock:^{\n" + " [self onOperationDone];\n" + "}];", + FourIndent); } TEST_F(FormatTest, SupportsCRLF) { @@ -9097,5 +9752,32 @@ TEST_F(FormatTest, HandleConflictMarkers) { "int i;\n")); } +TEST_F(FormatTest, DisableRegions) { + EXPECT_EQ("int i;\n" + "// clang-format off\n" + " int j;\n" + "// clang-format on\n" + "int k;", + format(" int i;\n" + " // clang-format off\n" + " int j;\n" + " // clang-format on\n" + " int k;")); + EXPECT_EQ("int i;\n" + "/* clang-format off */\n" + " int j;\n" + "/* clang-format on */\n" + "int k;", + format(" int i;\n" + " /* clang-format off */\n" + " int j;\n" + " /* clang-format on */\n" + " int k;")); +} + +TEST_F(FormatTest, DoNotCrashOnInvalidInput) { + format("? ) ="); +} + } // end namespace tooling } // end namespace clang diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp index f8802b85d606..780b02f746e9 100644 --- a/unittests/Format/FormatTestJS.cpp +++ b/unittests/Format/FormatTestJS.cpp @@ -81,11 +81,23 @@ TEST_F(FormatTestJS, UnderstandsJavaScriptOperators) { getGoogleJSStyleWithColumns(20)); verifyFormat("var b = a.map((x) => x + 1);"); + verifyFormat("return ('aaa') in bbbb;"); +} + +TEST_F(FormatTestJS, UnderstandsAmpAmp) { + verifyFormat("e && e.SomeFunction();"); +} + +TEST_F(FormatTestJS, LiteralOperatorsCanBeKeywords) { + verifyFormat("not.and.or.not_eq = 1;"); } TEST_F(FormatTestJS, ES6DestructuringAssignment) { verifyFormat("var [a, b, c] = [1, 2, 3];"); - verifyFormat("var {a, b} = {a: 1, b: 2};"); + verifyFormat("var {a, b} = {\n" + " a: 1,\n" + " b: 2\n" + "};"); } TEST_F(FormatTestJS, ContainerLiterals) { @@ -102,29 +114,45 @@ TEST_F(FormatTestJS, ContainerLiterals) { "};"); verifyFormat("return {\n" " a: a,\n" - " link:\n" - " function() {\n" - " f(); //\n" - " },\n" - " link:\n" - " function() {\n" - " f(); //\n" - " }\n" + " link: function() {\n" + " f(); //\n" + " },\n" + " link: function() {\n" + " f(); //\n" + " }\n" + "};"); + verifyFormat("var stuff = {\n" + " // comment for update\n" + " update: false,\n" + " // comment for modules\n" + " modules: false,\n" + " // comment for tasks\n" + " tasks: false\n" + "};"); + verifyFormat("return {\n" + " 'finish':\n" + " //\n" + " a\n" + "};"); + verifyFormat("var obj = {\n" + " fooooooooo: function(x) {\n" + " return x.zIsTooLongForOneLineWithTheDeclarationLine();\n" + " }\n" "};"); } TEST_F(FormatTestJS, SpacesInContainerLiterals) { verifyFormat("var arr = [1, 2, 3];"); - verifyFormat("var obj = {a: 1, b: 2, c: 3};"); + verifyFormat("f({a: 1, b: 2, c: 3});"); verifyFormat("var object_literal_with_long_name = {\n" " a: 'aaaaaaaaaaaaaaaaaa',\n" " b: 'bbbbbbbbbbbbbbbbbb'\n" "};"); - verifyFormat("var obj = {a: 1, b: 2, c: 3};", + verifyFormat("f({a: 1, b: 2, c: 3});", getChromiumStyle(FormatStyle::LK_JavaScript)); - verifyFormat("someVariable = {'a': [{}]};"); + verifyFormat("f({'a': [{}]});"); } TEST_F(FormatTestJS, SingleQuoteStrings) { @@ -138,6 +166,22 @@ TEST_F(FormatTestJS, GoogScopes) { "}); // goog.scope"); } +TEST_F(FormatTestJS, GoogModules) { + verifyFormat("goog.module('this.is.really.absurdly.long');", + getGoogleJSStyleWithColumns(40)); + verifyFormat("goog.require('this.is.really.absurdly.long');", + getGoogleJSStyleWithColumns(40)); + verifyFormat("goog.provide('this.is.really.absurdly.long');", + getGoogleJSStyleWithColumns(40)); + verifyFormat("var long = goog.require('this.is.really.absurdly.long');", + getGoogleJSStyleWithColumns(40)); + + // These should be wrapped normally. + verifyFormat( + "var MyLongClassName =\n" + " goog.module.get('my.long.module.name.followedBy.MyLongClassName');"); +} + TEST_F(FormatTestJS, FormatsFreestandingFunctions) { verifyFormat("function outer1(a, b) {\n" " function inner1(a, b) { return a; }\n" @@ -150,8 +194,11 @@ TEST_F(FormatTestJS, FormatsFreestandingFunctions) { } TEST_F(FormatTestJS, FunctionLiterals) { + verifyFormat("doFoo(function() {});"); verifyFormat("doFoo(function() { return 1; });"); - verifyFormat("var func = function() { return 1; };"); + verifyFormat("var func = function() {\n" + " return 1;\n" + "};"); verifyFormat("return {\n" " body: {\n" " setAttribute: function(key, val) { this[key] = val; },\n" @@ -159,7 +206,13 @@ TEST_F(FormatTestJS, FunctionLiterals) { " style: {direction: ''}\n" " }\n" "};"); - EXPECT_EQ("abc = xyz ? function() { return 1; } : function() { return -1; };", + 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("var closure = goog.bind(\n" @@ -181,13 +234,18 @@ TEST_F(FormatTestJS, FunctionLiterals) { " };\n" " }\n" "};"); + verifyFormat("{\n" + " var someVariable = function(x) {\n" + " return x.zIsTooLongForOneLineWithTheDeclarationLine();\n" + " };\n" + "}"); - verifyFormat("var x = {a: function() { return 1; }};", - getGoogleJSStyleWithColumns(38)); - verifyFormat("var x = {\n" + verifyFormat("f({a: function() { return 1; }});", + getGoogleJSStyleWithColumns(33)); + verifyFormat("f({\n" " a: function() { return 1; }\n" - "};", - getGoogleJSStyleWithColumns(37)); + "});", + getGoogleJSStyleWithColumns(32)); verifyFormat("return {\n" " a: function SomeFunction() {\n" @@ -195,6 +253,74 @@ TEST_F(FormatTestJS, FunctionLiterals) { " return 1;\n" " }\n" "};"); + verifyFormat("this.someObject.doSomething(aaaaaaaaaaaaaaaaaaaaaaaaaa)\n" + " .then(goog.bind(function(aaaaaaaaaaa) {\n" + " someFunction();\n" + " 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));"); +} + +TEST_F(FormatTestJS, InliningFunctionLiterals) { + FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript); + Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; + verifyFormat("var func = function() {\n" + " return 1;\n" + "};", + Style); + verifyFormat("var func = doSomething(function() { return 1; });", Style); + verifyFormat("var outer = function() {\n" + " var inner = function() { return 1; }\n" + "};", + Style); + verifyFormat("function outer1(a, b) {\n" + " function inner1(a, b) { return a; }\n" + "}", + Style); + + Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All; + verifyFormat("var func = function() { return 1; };", Style); + verifyFormat("var func = doSomething(function() { return 1; });", Style); + verifyFormat( + "var outer = function() { var inner = function() { return 1; } };", + Style); + verifyFormat("function outer1(a, b) {\n" + " function inner1(a, b) { return a; }\n" + "}", + Style); + + Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None; + verifyFormat("var func = function() {\n" + " return 1;\n" + "};", + Style); + verifyFormat("var func = doSomething(function() {\n" + " return 1;\n" + "});", + Style); + verifyFormat("var outer = function() {\n" + " var inner = function() {\n" + " return 1;\n" + " }\n" + "};", + Style); + verifyFormat("function outer1(a, b) {\n" + " function inner1(a, b) {\n" + " return a;\n" + " }\n" + "}", + Style); } TEST_F(FormatTestJS, MultipleFunctionLiterals) { @@ -228,10 +354,33 @@ TEST_F(FormatTestJS, MultipleFunctionLiterals) { " doFoo();\n" " doBaz();\n" " });\n"); + + verifyFormat("getSomeLongPromise()\n" + " .then(function(value) { body(); })\n" + " .thenCatch(function(error) {\n" + " body();\n" + " body();\n" + " });"); + verifyFormat("getSomeLongPromise()\n" + " .then(function(value) {\n" + " body();\n" + " body();\n" + " })\n" + " .thenCatch(function(error) {\n" + " body();\n" + " body();\n" + " });"); + + // FIXME: This is bad, but it used to be formatted correctly by accident. + verifyFormat("getSomeLongPromise().then(function(value) {\n" + " body();\n" + "}).thenCatch(function(error) { body(); });"); } TEST_F(FormatTestJS, ReturnStatements) { - verifyFormat("function() { return [hello, world]; }"); + verifyFormat("function() {\n" + " return [hello, world];\n" + "}"); } TEST_F(FormatTestJS, ClosureStyleComments) { @@ -246,6 +395,11 @@ TEST_F(FormatTestJS, TryCatch) { "} finally {\n" " h();\n" "}"); + + // But, of course, "catch" is a perfectly fine function name in JavaScript. + verifyFormat("someObject.catch();"); + verifyFormat("someObject.new();"); + verifyFormat("someObject.delete();"); } TEST_F(FormatTestJS, StringLiteralConcatenation) { @@ -307,6 +461,12 @@ TEST_F(FormatTestJS, RegexLiteralSpecialCharacters) { verifyFormat("var regex = /\\\\/g;"); verifyFormat("var regex = /\\a\\\\/g;"); verifyFormat("var regex = /\a\\//g;"); + verifyFormat("var regex = /a\\//;\n" + "var x = 0;"); + EXPECT_EQ("var regex = /\\/*/;\n" + "var x = 0;", + format("var regex = /\\/*/;\n" + "var x=0;")); } TEST_F(FormatTestJS, RegexLiteralModifiers) { @@ -322,6 +482,8 @@ TEST_F(FormatTestJS, RegexLiteralLength) { verifyFormat("var regex =\n" " /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;", getGoogleJSStyleWithColumns(60)); + verifyFormat("var regex = /\\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;", + getGoogleJSStyleWithColumns(50)); } TEST_F(FormatTestJS, RegexLiteralExamples) { diff --git a/unittests/Format/FormatTestJava.cpp b/unittests/Format/FormatTestJava.cpp new file mode 100644 index 000000000000..8d6daa62a599 --- /dev/null +++ b/unittests/Format/FormatTestJava.cpp @@ -0,0 +1,492 @@ +//===- unittest/Format/FormatTestJava.cpp - Formatting tests for Java -----===// +// +// 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 { + +class FormatTestJava : public ::testing::Test { +protected: + static std::string format(llvm::StringRef Code, unsigned Offset, + unsigned Length, const FormatStyle &Style) { + DEBUG(llvm::errs() << "---\n"); + DEBUG(llvm::errs() << Code << "\n\n"); + std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length)); + tooling::Replacements Replaces = reformat(Style, Code, Ranges); + std::string Result = applyAllReplacements(Code, Replaces); + EXPECT_NE("", Result); + DEBUG(llvm::errs() << "\n" << Result << "\n\n"); + return Result; + } + + static std::string format( + llvm::StringRef Code, + const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_Java)) { + return format(Code, 0, Code.size(), Style); + } + + static FormatStyle getStyleWithColumns(unsigned ColumnLimit) { + FormatStyle Style = getGoogleStyle(FormatStyle::LK_Java); + Style.ColumnLimit = ColumnLimit; + return Style; + } + + static void verifyFormat( + llvm::StringRef Code, + const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_Java)) { + EXPECT_EQ(Code.str(), format(test::messUp(Code), Style)); + } +}; + +TEST_F(FormatTestJava, NoAlternativeOperatorNames) { + verifyFormat("someObject.and();"); +} + +TEST_F(FormatTestJava, UnderstandsCasts) { + verifyFormat("a[b >> 1] = (byte) (c() << 4);"); +} + +TEST_F(FormatTestJava, FormatsInstanceOfLikeOperators) { + FormatStyle Style = getStyleWithColumns(50); + verifyFormat("return aaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " instanceof bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;", + Style); + Style.BreakBeforeBinaryOperators = FormatStyle::BOS_None; + verifyFormat("return aaaaaaaaaaaaaaaaaaaaaaaaaaaaa instanceof\n" + " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;", + Style); +} + +TEST_F(FormatTestJava, Chromium) { + verifyFormat("class SomeClass {\n" + " void f() {}\n" + " int g() {\n" + " return 0;\n" + " }\n" + " void h() {\n" + " while (true) f();\n" + " for (;;) f();\n" + " if (true) f();\n" + " }\n" + "}", + getChromiumStyle(FormatStyle::LK_Java)); +} + +TEST_F(FormatTestJava, QualifiedNames) { + verifyFormat("public some.package.Type someFunction( // comment\n" + " int parameter) {}"); +} + +TEST_F(FormatTestJava, ClassKeyword) { + verifyFormat("SomeClass.class.getName();"); + verifyFormat("Class c = SomeClass.class;"); +} + +TEST_F(FormatTestJava, ClassDeclarations) { + verifyFormat("public class SomeClass {\n" + " private int a;\n" + " private int b;\n" + "}"); + verifyFormat("public class A {\n" + " class B {\n" + " int i;\n" + " }\n" + " class C {\n" + " int j;\n" + " }\n" + "}"); + verifyFormat("public class A extends B.C {}"); + + verifyFormat("abstract class SomeClass\n" + " extends SomeOtherClass implements SomeInterface {}", + getStyleWithColumns(60)); + verifyFormat("abstract class SomeClass extends SomeOtherClass\n" + " implements SomeInterfaceeeeeeeeeeeee {}", + getStyleWithColumns(60)); + verifyFormat("abstract class SomeClass\n" + " extends SomeOtherClass\n" + " implements SomeInterface {}", + getStyleWithColumns(40)); + verifyFormat("abstract class SomeClass\n" + " extends SomeOtherClass\n" + " implements SomeInterface,\n" + " AnotherInterface {}", + getStyleWithColumns(40)); + verifyFormat("abstract class SomeClass\n" + " implements SomeInterface, AnotherInterface {}", + getStyleWithColumns(60)); + verifyFormat("@SomeAnnotation()\n" + "abstract class aaaaaaaaaaaa\n" + " extends bbbbbbbbbbbbbbb implements cccccccccccc {}", + getStyleWithColumns(76)); + verifyFormat("@SomeAnnotation()\n" + "abstract class aaaaaaaaa<a>\n" + " extends bbbbbbbbbbbb<b> implements cccccccccccc {}", + getStyleWithColumns(76)); + verifyFormat("interface SomeInterface<A> extends Foo, Bar {\n" + " void doStuff(int theStuff);\n" + " void doMoreStuff(int moreStuff);\n" + "}"); + verifyFormat("public interface SomeInterface {\n" + " void doStuff(int theStuff);\n" + " void doMoreStuff(int moreStuff);\n" + "}"); + verifyFormat("@interface SomeInterface {\n" + " void doStuff(int theStuff);\n" + " void doMoreStuff(int moreStuff);\n" + "}"); + verifyFormat("public @interface SomeInterface {\n" + " void doStuff(int theStuff);\n" + " void doMoreStuff(int moreStuff);\n" + "}"); +} + +TEST_F(FormatTestJava, EnumDeclarations) { + verifyFormat("enum SomeThing { ABC, CDE }"); + verifyFormat("enum SomeThing {\n" + " ABC,\n" + " CDE,\n" + "}"); + verifyFormat("public class SomeClass {\n" + " enum SomeThing { ABC, CDE }\n" + " void f() {}\n" + "}"); + verifyFormat("public class SomeClass implements SomeInterface {\n" + " enum SomeThing { ABC, CDE }\n" + " void f() {}\n" + "}"); + verifyFormat("enum SomeThing {\n" + " ABC,\n" + " CDE;\n" + " void f() {}\n" + "}"); + verifyFormat("enum SomeThing {\n" + " ABC(1, \"ABC\"),\n" + " CDE(2, \"CDE\");\n" + " Something(int i, String s) {}\n" + "}"); + verifyFormat("enum SomeThing {\n" + " ABC(new int[] {1, 2}),\n" + " CDE(new int[] {2, 3});\n" + " Something(int[] i) {}\n" + "}"); + verifyFormat("public enum SomeThing {\n" + " ABC {\n" + " public String toString() {\n" + " return \"ABC\";\n" + " }\n" + " },\n" + " CDE {\n" + " @Override\n" + " public String toString() {\n" + " return \"CDE\";\n" + " }\n" + " };\n" + " public void f() {}\n" + "}"); + verifyFormat("private enum SomeEnum implements Foo<?, B> {\n" + " ABC {\n" + " @Override\n" + " public String toString() {\n" + " return \"ABC\";\n" + " }\n" + " },\n" + " CDE {\n" + " @Override\n" + " public String toString() {\n" + " return \"CDE\";\n" + " }\n" + " };\n" + "}"); +} + +TEST_F(FormatTestJava, ArrayInitializers) { + verifyFormat("new int[] {1, 2, 3, 4};"); + verifyFormat("new int[] {\n" + " 1, 2, 3, 4,\n" + "};"); + + FormatStyle Style = getStyleWithColumns(65); + Style.Cpp11BracedListStyle = false; + verifyFormat( + "expected = new int[] { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,\n" + " 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 };", + Style); +} + +TEST_F(FormatTestJava, ThrowsDeclarations) { + verifyFormat("public void doSooooooooooooooooooooooooooomething()\n" + " throws LooooooooooooooooooooooooooooongException {}"); + verifyFormat("public void doSooooooooooooooooooooooooooomething()\n" + " throws LoooooooooongException, LooooooooooongException {}"); +} + +TEST_F(FormatTestJava, Annotations) { + verifyFormat("@Override\n" + "public String toString() {}"); + verifyFormat("@Override\n" + "@Nullable\n" + "public String getNameIfPresent() {}"); + verifyFormat("@Override // comment\n" + "@Nullable\n" + "public String getNameIfPresent() {}"); + verifyFormat("@java.lang.Override // comment\n" + "@Nullable\n" + "public String getNameIfPresent() {}"); + + verifyFormat("@SuppressWarnings(value = \"unchecked\")\n" + "public void doSomething() {}"); + verifyFormat("@SuppressWarnings(value = \"unchecked\")\n" + "@Author(name = \"abc\")\n" + "public void doSomething() {}"); + + verifyFormat("DoSomething(new A() {\n" + " @Override\n" + " public String toString() {}\n" + "});"); + + verifyFormat("void SomeFunction(@Nullable String something) {}"); + verifyFormat("void SomeFunction(@org.llvm.Nullable String something) {}"); + + verifyFormat("@Partial @Mock DataLoader loader;"); + verifyFormat("@SuppressWarnings(value = \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\")\n" + "public static int iiiiiiiiiiiiiiiiiiiiiiii;"); + + verifyFormat("@SomeAnnotation(\"With some really looooooooooooooong text\")\n" + "private static final long something = 0L;"); + verifyFormat("@org.llvm.Qualified(\"With some really looooooooooong text\")\n" + "private static final long something = 0L;"); + verifyFormat("@Mock\n" + "DataLoader loooooooooooooooooooooooader =\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;", + getStyleWithColumns(60)); + verifyFormat("@org.llvm.QualifiedMock\n" + "DataLoader loooooooooooooooooooooooader =\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;", + getStyleWithColumns(60)); + verifyFormat("@Test(a)\n" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaa);"); + verifyFormat("@SomeAnnotation(\n" + " aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaa)\n" + "int i;", + getStyleWithColumns(50)); + verifyFormat("@Test\n" + "ReturnType doSomething(\n" + " String aaaaaaaaaaaaa, String bbbbbbbbbbbbbbb) {}", + getStyleWithColumns(60)); + verifyFormat("{\n" + " boolean someFunction(\n" + " @Param(aaaaaaaaaaaaaaaa) String aaaaa,\n" + " String bbbbbbbbbbbbbbb) {}\n" + "}", + getStyleWithColumns(60)); +} + +TEST_F(FormatTestJava, Generics) { + verifyFormat("Iterable<?> a;"); + verifyFormat("Iterable<?> a;"); + verifyFormat("Iterable<? extends SomeObject> a;"); + + verifyFormat("A.<B>doSomething();"); + + verifyFormat("@Override\n" + "public Map<String, ?> getAll() {}"); + + verifyFormat("public <R> ArrayList<R> get() {}"); + verifyFormat("protected <R> ArrayList<R> get() {}"); + verifyFormat("private <R> ArrayList<R> get() {}"); + verifyFormat("public static <R> ArrayList<R> get() {}"); + verifyFormat("public static native <R> ArrayList<R> get();"); + verifyFormat("public final <X> Foo foo() {}"); + verifyFormat("public abstract <X> Foo foo();"); + verifyFormat("<T extends B> T getInstance(Class<T> type);"); + verifyFormat("Function<F, ? extends T> function;"); + + verifyFormat("private Foo<X, Y>[] foos;"); + verifyFormat("Foo<X, Y>[] foos = this.foos;"); + verifyFormat("return (a instanceof List<?>)\n" + " ? aaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaa)\n" + " : aaaaaaaaaaaaaaaaaaaaaaa;", + getStyleWithColumns(60)); + + verifyFormat( + "SomeLoooooooooooooooooooooongType name =\n" + " SomeType.foo(someArgument)\n" + " .<X>method()\n" + " .aaaaaaaaaaaaaaaaaaa()\n" + " .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa();"); +} + +TEST_F(FormatTestJava, StringConcatenation) { + verifyFormat("String someString = \"abc\"\n" + " + \"cde\";"); +} + +TEST_F(FormatTestJava, TryCatchFinally) { + verifyFormat("try {\n" + " Something();\n" + "} catch (SomeException e) {\n" + " HandleException(e);\n" + "}"); + verifyFormat("try {\n" + " Something();\n" + "} finally {\n" + " AlwaysDoThis();\n" + "}"); + verifyFormat("try {\n" + " Something();\n" + "} catch (SomeException e) {\n" + " HandleException(e);\n" + "} finally {\n" + " AlwaysDoThis();\n" + "}"); + + verifyFormat("try {\n" + " Something();\n" + "} catch (SomeException | OtherException e) {\n" + " HandleException(e);\n" + "}"); +} + +TEST_F(FormatTestJava, TryWithResources) { + verifyFormat("try (SomeResource rs = someFunction()) {\n" + " Something();\n" + "}"); + verifyFormat("try (SomeResource rs = someFunction()) {\n" + " Something();\n" + "} catch (SomeException e) {\n" + " HandleException(e);\n" + "}"); +} + +TEST_F(FormatTestJava, SynchronizedKeyword) { + verifyFormat("synchronized (mData) {\n" + " // ...\n" + "}"); +} + +TEST_F(FormatTestJava, PackageDeclarations) { + verifyFormat("package some.really.loooooooooooooooooooooong.package;", + getStyleWithColumns(50)); +} + +TEST_F(FormatTestJava, ImportDeclarations) { + verifyFormat("import some.really.loooooooooooooooooooooong.imported.Class;", + getStyleWithColumns(50)); + verifyFormat("import static some.really.looooooooooooooooong.imported.Class;", + getStyleWithColumns(50)); +} + +TEST_F(FormatTestJava, MethodDeclarations) { + verifyFormat("void methodName(Object arg1,\n" + " Object arg2, Object arg3) {}", + getStyleWithColumns(40)); + verifyFormat("void methodName(\n" + " Object arg1, Object arg2) {}", + getStyleWithColumns(40)); +} + +TEST_F(FormatTestJava, CppKeywords) { + verifyFormat("public void union(Type a, Type b);"); + verifyFormat("public void struct(Object o);"); + verifyFormat("public void delete(Object o);"); +} + +TEST_F(FormatTestJava, NeverAlignAfterReturn) { + verifyFormat("return aaaaaaaaaaaaaaaaaaa\n" + " && bbbbbbbbbbbbbbbbbbb\n" + " && ccccccccccccccccccc;", + getStyleWithColumns(40)); + verifyFormat("return (result == null)\n" + " ? aaaaaaaaaaaaaaaaa\n" + " : bbbbbbbbbbbbbbbbb;", + getStyleWithColumns(40)); + verifyFormat("return aaaaaaaaaaaaaaaaaaa()\n" + " .bbbbbbbbbbbbbbbbbbb()\n" + " .ccccccccccccccccccc();", + getStyleWithColumns(40)); + verifyFormat("return aaaaaaaaaaaaaaaaaaa()\n" + " .bbbbbbbbbbbbbbbbbbb(\n" + " ccccccccccccccc)\n" + " .ccccccccccccccccccc();", + getStyleWithColumns(40)); +} + +TEST_F(FormatTestJava, FormatsInnerBlocks) { + verifyFormat("someObject.someFunction(new Runnable() {\n" + " @Override\n" + " public void run() {\n" + " System.out.println(42);\n" + " }\n" + "}, someOtherParameter);"); + verifyFormat("someFunction(new Runnable() {\n" + " public void run() {\n" + " System.out.println(42);\n" + " }\n" + "});"); + verifyFormat("someObject.someFunction(\n" + " new Runnable() {\n" + " @Override\n" + " public void run() {\n" + " System.out.println(42);\n" + " }\n" + " },\n" + " new Runnable() {\n" + " @Override\n" + " public void run() {\n" + " System.out.println(43);\n" + " }\n" + " },\n" + " someOtherParameter);"); +} + +TEST_F(FormatTestJava, FormatsLambdas) { + verifyFormat("(aaaaaaaaaa, bbbbbbbbbb) -> aaaaaaaaaa + bbbbbbbbbb;"); + verifyFormat("(aaaaaaaaaa, bbbbbbbbbb)\n" + " -> aaaaaaaaaa + bbbbbbbbbb;", + getStyleWithColumns(40)); + verifyFormat("Runnable someLambda = () -> DoSomething();"); + verifyFormat("Runnable someLambda = () -> {\n" + " DoSomething();\n" + "}"); + + verifyFormat("Runnable someLambda =\n" + " (int aaaaa) -> DoSomething(aaaaa);", + getStyleWithColumns(40)); +} + +TEST_F(FormatTestJava, BreaksStringLiterals) { + // FIXME: String literal breaking is currently disabled for Java and JS, as it + // requires strings to be merged using "+" which we don't support. + EXPECT_EQ("\"some text other\";", + format("\"some text other\";", getStyleWithColumns(14))); +} + +TEST_F(FormatTestJava, AlignsBlockComments) { + EXPECT_EQ("/*\n" + " * Really multi-line\n" + " * comment.\n" + " */\n" + "void f() {}", + format(" /*\n" + " * Really multi-line\n" + " * comment.\n" + " */\n" + " void f() {}")); +} + +} // end namespace tooling +} // end namespace clang diff --git a/unittests/Format/FormatTestProto.cpp b/unittests/Format/FormatTestProto.cpp index bfd502566757..3a2f97e875d1 100644 --- a/unittests/Format/FormatTestProto.cpp +++ b/unittests/Format/FormatTestProto.cpp @@ -85,21 +85,50 @@ TEST_F(FormatTestProto, MessageFieldAttributes) { " [default = REALLY_REALLY_LONG_CONSTANT_VALUE];"); verifyFormat("repeated double value = 1\n" " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaaa: AAAAAAAA}];"); - verifyFormat("repeated double value = 1\n" - " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaa: AAAAAAAAAA,\n" - " bbbbbbbbbbbbbbbb: BBBBBBBBBB}];"); - verifyFormat("repeated double value = 1\n" - " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaa: AAAAAAAAAA\n" - " bbbbbbbbbbbbbbbb: BBBBBBBBBB}];"); - verifyFormat("repeated double value = 1\n" - " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaa: AAAAAAAAAA,\n" - " bbbbbbb: BBBB,\n" - " bbbb: BBB}];"); + verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n" + " aaaaaaaaaaaaaaaa: AAAAAAAAAA,\n" + " bbbbbbbbbbbbbbbb: BBBBBBBBBB\n" + "}];"); + verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n" + " aaaaaaaaaaaaaaaa: AAAAAAAAAA\n" + " bbbbbbbbbbbbbbbb: BBBBBBBBBB\n" + "}];"); + verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n" + " aaaaaaaaaaaaaaaa: AAAAAAAAAA,\n" + " bbbbbbb: BBBB,\n" + " bbbb: BBB\n" + "}];"); } TEST_F(FormatTestProto, FormatsOptions) { - verifyFormat("option java_package = \"my.test.package\";"); - verifyFormat("option (my_custom_option) = \"abc\";"); + verifyFormat("option (MyProto.options) = {\n" + " field_a: OK\n" + " field_b: \"OK\"\n" + " field_c: \"OK\"\n" + " msg_field: {field_d: 123}\n" + "};"); + + verifyFormat("option (MyProto.options) = {\n" + " field_a: OK\n" + " field_b: \"OK\"\n" + " field_c: \"OK\"\n" + " msg_field: {\n" + " field_d: 123\n" + " field_e: OK\n" + " }\n" + "};"); + + verifyFormat("option (MyProto.options) = {\n" + " field_a: OK // Comment\n" + " field_b: \"OK\"\n" + " field_c: \"OK\"\n" + " msg_field: {field_d: 123}\n" + "};"); + + verifyFormat("option (MyProto.options) = {\n" + " field_c: \"OK\"\n" + " msg_field{field_d: 123}\n" + "};"); } TEST_F(FormatTestProto, FormatsService) { diff --git a/unittests/Format/FormatTestUtils.h b/unittests/Format/FormatTestUtils.h index 649f5b3822c5..bd340e5b0e60 100644 --- a/unittests/Format/FormatTestUtils.h +++ b/unittests/Format/FormatTestUtils.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_FORMAT_TEST_UTILS_H -#define LLVM_CLANG_FORMAT_TEST_UTILS_H +#ifndef LLVM_CLANG_UNITTESTS_FORMAT_FORMATTESTUTILS_H +#define LLVM_CLANG_UNITTESTS_FORMAT_FORMATTESTUTILS_H #include "llvm/ADT/StringRef.h" @@ -64,4 +64,4 @@ inline std::string messUp(llvm::StringRef Code) { } // end namespace format } // end namespace clang -#endif // LLVM_CLANG_FORMAT_TEST_UTILS_H +#endif diff --git a/unittests/Format/Makefile b/unittests/Format/Makefile index e6dce4d8e814..f95d6d34127b 100644 --- a/unittests/Format/Makefile +++ b/unittests/Format/Makefile @@ -11,8 +11,8 @@ CLANG_LEVEL = ../.. TESTNAME = Format include $(CLANG_LEVEL)/../../Makefile.config LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option -USEDLIBS = clangFormat.a clangTooling.a clangFrontend.a clangSerialization.a \ - clangDriver.a clangParse.a clangRewrite.a \ +USEDLIBS = clangFormat.a clangTooling.a clangToolingCore.a clangFrontend.a \ + clangSerialization.a clangDriver.a clangParse.a clangRewrite.a \ clangRewriteFrontend.a clangSema.a clangAnalysis.a clangEdit.a \ clangAST.a clangASTMatchers.a clangLex.a clangBasic.a diff --git a/unittests/Frontend/CMakeLists.txt b/unittests/Frontend/CMakeLists.txt index cdc955944bcf..a1310e885a55 100644 --- a/unittests/Frontend/CMakeLists.txt +++ b/unittests/Frontend/CMakeLists.txt @@ -8,4 +8,6 @@ add_clang_unittest(FrontendTests target_link_libraries(FrontendTests clangAST clangFrontend + clangLex + clangSema ) diff --git a/unittests/Frontend/FrontendActionTest.cpp b/unittests/Frontend/FrontendActionTest.cpp index e39d00f6af3d..5581c4487ecc 100644 --- a/unittests/Frontend/FrontendActionTest.cpp +++ b/unittests/Frontend/FrontendActionTest.cpp @@ -14,6 +14,7 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Sema/Sema.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/MemoryBuffer.h" #include "gtest/gtest.h" @@ -25,10 +26,13 @@ namespace { class TestASTFrontendAction : public ASTFrontendAction { public: - TestASTFrontendAction(bool enableIncrementalProcessing = false) - : EnableIncrementalProcessing(enableIncrementalProcessing) { } + TestASTFrontendAction(bool enableIncrementalProcessing = false, + bool actOnEndOfTranslationUnit = false) + : EnableIncrementalProcessing(enableIncrementalProcessing), + ActOnEndOfTranslationUnit(actOnEndOfTranslationUnit) { } bool EnableIncrementalProcessing; + bool ActOnEndOfTranslationUnit; std::vector<std::string> decl_names; virtual bool BeginSourceFileAction(CompilerInstance &ci, StringRef filename) { @@ -38,17 +42,24 @@ public: return ASTFrontendAction::BeginSourceFileAction(ci, filename); } - virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { - return new Visitor(decl_names); + virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + return llvm::make_unique<Visitor>(CI, ActOnEndOfTranslationUnit, + decl_names); } private: class Visitor : public ASTConsumer, public RecursiveASTVisitor<Visitor> { public: - Visitor(std::vector<std::string> &decl_names) : decl_names_(decl_names) {} + Visitor(CompilerInstance &CI, bool ActOnEndOfTranslationUnit, + std::vector<std::string> &decl_names) : + CI(CI), ActOnEndOfTranslationUnit(ActOnEndOfTranslationUnit), + decl_names_(decl_names) {} virtual void HandleTranslationUnit(ASTContext &context) { + if (ActOnEndOfTranslationUnit) { + CI.getSema().ActOnEndOfTranslationUnit(); + } TraverseDecl(context.getTranslationUnitDecl()); } @@ -58,6 +69,8 @@ private: } private: + CompilerInstance &CI; + bool ActOnEndOfTranslationUnit; std::vector<std::string> &decl_names_; }; }; @@ -65,7 +78,8 @@ private: TEST(ASTFrontendAction, Sanity) { CompilerInvocation *invocation = new CompilerInvocation; invocation->getPreprocessorOpts().addRemappedFile( - "test.cc", MemoryBuffer::getMemBuffer("int main() { float x; }")); + "test.cc", + MemoryBuffer::getMemBuffer("int main() { float x; }").release()); invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc", IK_CXX)); invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; @@ -84,7 +98,8 @@ TEST(ASTFrontendAction, Sanity) { TEST(ASTFrontendAction, IncrementalParsing) { CompilerInvocation *invocation = new CompilerInvocation; invocation->getPreprocessorOpts().addRemappedFile( - "test.cc", MemoryBuffer::getMemBuffer("int main() { float x; }")); + "test.cc", + MemoryBuffer::getMemBuffer("int main() { float x; }").release()); invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc", IK_CXX)); invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; @@ -100,4 +115,79 @@ TEST(ASTFrontendAction, IncrementalParsing) { EXPECT_EQ("x", test_action.decl_names[1]); } +TEST(ASTFrontendAction, LateTemplateIncrementalParsing) { + CompilerInvocation *invocation = new CompilerInvocation; + invocation->getLangOpts()->CPlusPlus = true; + invocation->getLangOpts()->DelayedTemplateParsing = true; + invocation->getPreprocessorOpts().addRemappedFile( + "test.cc", MemoryBuffer::getMemBuffer( + "template<typename T> struct A { A(T); T data; };\n" + "template<typename T> struct B: public A<T> {\n" + " B();\n" + " B(B const& b): A<T>(b.data) {}\n" + "};\n" + "B<char> c() { return B<char>(); }\n").release()); + invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc", + IK_CXX)); + invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; + invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; + CompilerInstance compiler; + compiler.setInvocation(invocation); + compiler.createDiagnostics(); + + TestASTFrontendAction test_action(/*enableIncrementalProcessing=*/true, + /*actOnEndOfTranslationUnit=*/true); + ASSERT_TRUE(compiler.ExecuteAction(test_action)); + ASSERT_EQ(13U, test_action.decl_names.size()); + EXPECT_EQ("A", test_action.decl_names[0]); + EXPECT_EQ("c", test_action.decl_names[12]); +} + +struct TestPPCallbacks : public PPCallbacks { + TestPPCallbacks() : SeenEnd(false) {} + + void EndOfMainFile() override { SeenEnd = true; } + + bool SeenEnd; +}; + +class TestPPCallbacksFrontendAction : public PreprocessorFrontendAction { + TestPPCallbacks *Callbacks; + +public: + TestPPCallbacksFrontendAction(TestPPCallbacks *C) + : Callbacks(C), SeenEnd(false) {} + + void ExecuteAction() override { + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + PP.addPPCallbacks(std::unique_ptr<TestPPCallbacks>(Callbacks)); + PP.EnterMainSourceFile(); + } + void EndSourceFileAction() override { SeenEnd = Callbacks->SeenEnd; } + + bool SeenEnd; +}; + +TEST(PreprocessorFrontendAction, EndSourceFile) { + CompilerInvocation *Invocation = new CompilerInvocation; + Invocation->getPreprocessorOpts().addRemappedFile( + "test.cc", + MemoryBuffer::getMemBuffer("int main() { float x; }").release()); + Invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile("test.cc", IK_CXX)); + Invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; + Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; + CompilerInstance Compiler; + Compiler.setInvocation(Invocation); + Compiler.createDiagnostics(); + + TestPPCallbacks *Callbacks = new TestPPCallbacks; + TestPPCallbacksFrontendAction TestAction(Callbacks); + ASSERT_FALSE(Callbacks->SeenEnd); + ASSERT_FALSE(TestAction.SeenEnd); + ASSERT_TRUE(Compiler.ExecuteAction(TestAction)); + // Check that EndOfMainFile was called before EndSourceFileAction. + ASSERT_TRUE(TestAction.SeenEnd); +} + } // anonymous namespace diff --git a/unittests/Lex/CMakeLists.txt b/unittests/Lex/CMakeLists.txt index 1fb57cfdfba0..461e0d95fc87 100644 --- a/unittests/Lex/CMakeLists.txt +++ b/unittests/Lex/CMakeLists.txt @@ -14,5 +14,4 @@ target_link_libraries(LexTests clangLex clangParse clangSema - clangSerialization ) diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp index 2d75b52276cc..85987bf00161 100644 --- a/unittests/Lex/LexerTest.cpp +++ b/unittests/Lex/LexerTest.cpp @@ -62,8 +62,8 @@ protected: std::vector<Token> CheckLex(StringRef Source, ArrayRef<tok::TokenKind> ExpectedTokens) { - MemoryBuffer *buf = MemoryBuffer::getMemBuffer(Source); - SourceMgr.setMainFileID(SourceMgr.createFileID(buf)); + std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Source); + SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf))); VoidModuleLoader ModLoader; HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, diff --git a/unittests/Lex/PPCallbacksTest.cpp b/unittests/Lex/PPCallbacksTest.cpp index a1af75403638..bb27bac6ed66 100644 --- a/unittests/Lex/PPCallbacksTest.cpp +++ b/unittests/Lex/PPCallbacksTest.cpp @@ -27,8 +27,6 @@ #include "llvm/Support/Path.h" #include "gtest/gtest.h" -using namespace llvm; -using namespace llvm::sys; using namespace clang; namespace { @@ -142,7 +140,7 @@ protected: FileMgr.getVirtualFile(HeaderPath, 0, 0); // Add header's parent path to search path. - StringRef SearchPath = path::parent_path(HeaderPath); + StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath); const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath); DirectoryLookup DL(DE, SrcMgr::C_User, false); HeaderInfo.AddSearchPath(DL, IsSystemHeader); @@ -160,8 +158,9 @@ protected: // the InclusionDirective callback. CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText, const char* HeaderPath, bool SystemHeader) { - MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(SourceText); - SourceMgr.setMainFileID(SourceMgr.createFileID(Buf)); + std::unique_ptr<llvm::MemoryBuffer> Buf = + llvm::MemoryBuffer::getMemBuffer(SourceText); + SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf))); VoidModuleLoader ModLoader; @@ -176,7 +175,7 @@ protected: /*OwnsHeaderSearch =*/false); PP.Initialize(*Target); InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks; - PP.addPPCallbacks(Callbacks); // Takes ownership. + PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks)); // Lex source text. PP.EnterMainSourceFile(); @@ -197,8 +196,9 @@ protected: LangOptions OpenCLLangOpts; OpenCLLangOpts.OpenCL = 1; - MemoryBuffer* sourceBuf = MemoryBuffer::getMemBuffer(SourceText, "test.cl"); - SourceMgr.setMainFileID(SourceMgr.createFileID(sourceBuf)); + std::unique_ptr<llvm::MemoryBuffer> SourceBuf = + llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl"); + SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf))); VoidModuleLoader ModLoader; HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, @@ -221,7 +221,7 @@ protected: Sema S(PP, Context, Consumer); Parser P(PP, S, false); PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks; - PP.addPPCallbacks(Callbacks); // Takes ownership. + PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks)); // Lex source text. PP.EnterMainSourceFile(); diff --git a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp index e63106c295a3..946cb88b9810 100644 --- a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp +++ b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp @@ -90,8 +90,8 @@ TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) { "#endif\n" "9\n"; - MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source); - SourceMgr.setMainFileID(SourceMgr.createFileID(buf)); + std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(source); + SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf))); VoidModuleLoader ModLoader; HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, @@ -103,7 +103,7 @@ TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) { PP.Initialize(*Target); PPConditionalDirectiveRecord * PPRec = new PPConditionalDirectiveRecord(SourceMgr); - PP.addPPCallbacks(PPRec); + PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec)); PP.EnterMainSourceFile(); std::vector<Token> toks; diff --git a/unittests/Makefile b/unittests/Makefile index 95b1639415b2..1e6a50835b05 100644 --- a/unittests/Makefile +++ b/unittests/Makefile @@ -14,12 +14,13 @@ ifndef CLANG_LEVEL IS_UNITTEST_LEVEL := 1 CLANG_LEVEL := .. -PARALLEL_DIRS = Basic Lex Driver libclang Format ASTMatchers AST Tooling Sema +PARALLEL_DIRS = CodeGen Basic Lex Driver Format ASTMatchers AST Tooling \ + Sema include $(CLANG_LEVEL)/../..//Makefile.config ifeq ($(ENABLE_CLANG_ARCMT),1) -PARALLEL_DIRS += Frontend +PARALLEL_DIRS += Frontend libclang endif endif # CLANG_LEVEL diff --git a/unittests/Sema/ExternalSemaSourceTest.cpp b/unittests/Sema/ExternalSemaSourceTest.cpp index bc0d632cfdb5..3a93fc77fb19 100644 --- a/unittests/Sema/ExternalSemaSourceTest.cpp +++ b/unittests/Sema/ExternalSemaSourceTest.cpp @@ -140,10 +140,10 @@ class ExternalSemaSourceInstaller : public clang::ASTFrontendAction { std::unique_ptr<DiagnosticConsumer> OwnedClient; protected: - virtual clang::ASTConsumer * + virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance &Compiler, llvm::StringRef /* dummy */) { - return new clang::ASTConsumer(); + return llvm::make_unique<clang::ASTConsumer>(); } virtual void ExecuteAction() { @@ -154,7 +154,7 @@ protected: DiagnosticsEngine &Diagnostics = CI.getDiagnostics(); DiagnosticConsumer *Client = Diagnostics.getClient(); if (Diagnostics.ownsClient()) - OwnedClient.reset(Diagnostics.takeClient()); + OwnedClient = Diagnostics.takeClient(); for (size_t I = 0, E = Watchers.size(); I < E; ++I) Client = Watchers[I]->Chain(Client); Diagnostics.setClient(Client, false); diff --git a/unittests/Tooling/CMakeLists.txt b/unittests/Tooling/CMakeLists.txt index a41d87c6ea82..469e6a956b2d 100644 --- a/unittests/Tooling/CMakeLists.txt +++ b/unittests/Tooling/CMakeLists.txt @@ -7,6 +7,10 @@ add_clang_unittest(ToolingTests CompilationDatabaseTest.cpp ToolingTest.cpp RecursiveASTVisitorTest.cpp + RecursiveASTVisitorTestCallVisitor.cpp + RecursiveASTVisitorTestDeclVisitor.cpp + RecursiveASTVisitorTestExprVisitor.cpp + RecursiveASTVisitorTestTypeLocVisitor.cpp RefactoringTest.cpp RewriterTest.cpp RefactoringCallbacksTest.cpp @@ -21,4 +25,5 @@ target_link_libraries(ToolingTests clangLex clangRewrite clangTooling + clangToolingCore ) diff --git a/unittests/Tooling/Makefile b/unittests/Tooling/Makefile index 46af8a11bba1..514e80bd0309 100644 --- a/unittests/Tooling/Makefile +++ b/unittests/Tooling/Makefile @@ -11,7 +11,8 @@ CLANG_LEVEL = ../.. TESTNAME = Tooling include $(CLANG_LEVEL)/../../Makefile.config LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option -USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \ +USEDLIBS = clangTooling.a clangToolingCore.a clangFrontend.a \ + clangSerialization.a clangDriver.a \ clangParse.a clangRewrite.a clangRewriteFrontend.a \ clangSema.a clangAnalysis.a clangEdit.a \ clangAST.a clangASTMatchers.a clangLex.a clangBasic.a diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp index a1a93a59c79b..c28704532a6e 100644 --- a/unittests/Tooling/RecursiveASTVisitorTest.cpp +++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp @@ -14,85 +14,6 @@ using namespace clang; namespace { -class TypeLocVisitor : public ExpectedLocationVisitor<TypeLocVisitor> { -public: - bool VisitTypeLoc(TypeLoc TypeLocation) { - Match(TypeLocation.getType().getAsString(), TypeLocation.getBeginLoc()); - return true; - } -}; - -class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> { -public: - bool VisitDeclRefExpr(DeclRefExpr *Reference) { - Match(Reference->getNameInfo().getAsString(), Reference->getLocation()); - return true; - } -}; - -class VarDeclVisitor : public ExpectedLocationVisitor<VarDeclVisitor> { -public: - bool VisitVarDecl(VarDecl *Variable) { - Match(Variable->getNameAsString(), Variable->getLocStart()); - return true; - } -}; - -class ParmVarDeclVisitorForImplicitCode : - public ExpectedLocationVisitor<ParmVarDeclVisitorForImplicitCode> { -public: - bool shouldVisitImplicitCode() const { return true; } - - bool VisitParmVarDecl(ParmVarDecl *ParamVar) { - Match(ParamVar->getNameAsString(), ParamVar->getLocStart()); - return true; - } -}; - -class CXXMemberCallVisitor - : public ExpectedLocationVisitor<CXXMemberCallVisitor> { -public: - bool VisitCXXMemberCallExpr(CXXMemberCallExpr *Call) { - Match(Call->getMethodDecl()->getQualifiedNameAsString(), - Call->getLocStart()); - return true; - } -}; - -class NamedDeclVisitor - : public ExpectedLocationVisitor<NamedDeclVisitor> { -public: - bool VisitNamedDecl(NamedDecl *Decl) { - std::string NameWithTemplateArgs; - llvm::raw_string_ostream OS(NameWithTemplateArgs); - Decl->getNameForDiagnostic(OS, - Decl->getASTContext().getPrintingPolicy(), - true); - Match(OS.str(), Decl->getLocation()); - return true; - } -}; - -class CXXOperatorCallExprTraverser - : public ExpectedLocationVisitor<CXXOperatorCallExprTraverser> { -public: - // Use Traverse, not Visit, to check that data recursion optimization isn't - // bypassing the call of this function. - bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *CE) { - Match(getOperatorSpelling(CE->getOperator()), CE->getExprLoc()); - return ExpectedLocationVisitor<CXXOperatorCallExprTraverser>:: - TraverseCXXOperatorCallExpr(CE); - } -}; - -class ParenExprVisitor : public ExpectedLocationVisitor<ParenExprVisitor> { -public: - bool VisitParenExpr(ParenExpr *Parens) { - Match("", Parens->getExprLoc()); - return true; - } -}; - class LambdaExprVisitor : public ExpectedLocationVisitor<LambdaExprVisitor> { public: bool VisitLambdaExpr(LambdaExpr *Lambda) { @@ -117,429 +38,6 @@ private: std::stack<LambdaExpr *> PendingBodies; }; -// Matches the (optional) capture-default of a lambda-introducer. -class LambdaDefaultCaptureVisitor - : public ExpectedLocationVisitor<LambdaDefaultCaptureVisitor> { -public: - bool VisitLambdaExpr(LambdaExpr *Lambda) { - if (Lambda->getCaptureDefault() != LCD_None) { - Match("", Lambda->getCaptureDefaultLoc()); - } - return true; - } -}; - -class TemplateArgumentLocTraverser - : public ExpectedLocationVisitor<TemplateArgumentLocTraverser> { -public: - bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) { - std::string ArgStr; - llvm::raw_string_ostream Stream(ArgStr); - const TemplateArgument &Arg = ArgLoc.getArgument(); - - Arg.print(Context->getPrintingPolicy(), Stream); - Match(Stream.str(), ArgLoc.getLocation()); - return ExpectedLocationVisitor<TemplateArgumentLocTraverser>:: - TraverseTemplateArgumentLoc(ArgLoc); - } -}; - -class CXXBoolLiteralExprVisitor - : public ExpectedLocationVisitor<CXXBoolLiteralExprVisitor> { -public: - bool VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *BE) { - if (BE->getValue()) - Match("true", BE->getLocation()); - else - Match("false", BE->getLocation()); - return true; - } -}; - -// Test RAV visits parameter variable declaration of the implicit -// copy assignment operator and implicit copy constructor. -TEST(RecursiveASTVisitor, VisitsParmVarDeclForImplicitCode) { - ParmVarDeclVisitorForImplicitCode Visitor; - // Match parameter variable name of implicit copy assignment operator and - // implicit copy constructor. - // This parameter name does not have a valid IdentifierInfo, and shares - // same SourceLocation with its class declaration, so we match an empty name - // with the class' source location. - Visitor.ExpectMatch("", 1, 7); - Visitor.ExpectMatch("", 3, 7); - EXPECT_TRUE(Visitor.runOver( - "class X {};\n" - "void foo(X a, X b) {a = b;}\n" - "class Y {};\n" - "void bar(Y a) {Y b = a;}")); -} - -TEST(RecursiveASTVisitor, VisitsBaseClassDeclarations) { - TypeLocVisitor Visitor; - Visitor.ExpectMatch("class X", 1, 30); - EXPECT_TRUE(Visitor.runOver("class X {}; class Y : public X {};")); -} - -TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersOfForwardDeclaredClass) { - TypeLocVisitor Visitor; - Visitor.ExpectMatch("class X", 3, 18); - EXPECT_TRUE(Visitor.runOver( - "class Y;\n" - "class X {};\n" - "class Y : public X {};")); -} - -TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersWithIncompleteInnerClass) { - TypeLocVisitor Visitor; - Visitor.ExpectMatch("class X", 2, 18); - EXPECT_TRUE(Visitor.runOver( - "class X {};\n" - "class Y : public X { class Z; };")); -} - -TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersOfSelfReferentialType) { - TypeLocVisitor Visitor; - Visitor.ExpectMatch("X<class Y>", 2, 18); - EXPECT_TRUE(Visitor.runOver( - "template<typename T> class X {};\n" - "class Y : public X<Y> {};")); -} - -TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) { - DeclRefExprVisitor Visitor; - Visitor.ExpectMatch("x", 2, 3); - EXPECT_TRUE(Visitor.runOver( - "void x(); template <void (*T)()> class X {};\nX<x> y;")); -} - -TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtRange) { - DeclRefExprVisitor Visitor; - Visitor.ExpectMatch("x", 2, 25); - Visitor.ExpectMatch("x", 2, 30); - EXPECT_TRUE(Visitor.runOver( - "int x[5];\n" - "void f() { for (int i : x) { x[0] = 1; } }", - DeclRefExprVisitor::Lang_CXX11)); -} - -TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtLoopVariable) { - VarDeclVisitor Visitor; - Visitor.ExpectMatch("i", 2, 17); - EXPECT_TRUE(Visitor.runOver( - "int x[5];\n" - "void f() { for (int i : x) {} }", - VarDeclVisitor::Lang_CXX11)); -} - -TEST(RecursiveASTVisitor, VisitsCallExpr) { - DeclRefExprVisitor Visitor; - Visitor.ExpectMatch("x", 1, 22); - EXPECT_TRUE(Visitor.runOver( - "void x(); void y() { x(); }")); -} - -TEST(RecursiveASTVisitor, VisitsCallInTemplateInstantiation) { - CXXMemberCallVisitor Visitor; - Visitor.ExpectMatch("Y::x", 3, 3); - EXPECT_TRUE(Visitor.runOver( - "struct Y { void x(); };\n" - "template<typename T> void y(T t) {\n" - " t.x();\n" - "}\n" - "void foo() { y<Y>(Y()); }")); -} - -TEST(RecursiveASTVisitor, VisitsCallInNestedFunctionTemplateInstantiation) { - CXXMemberCallVisitor Visitor; - Visitor.ExpectMatch("Y::x", 4, 5); - EXPECT_TRUE(Visitor.runOver( - "struct Y { void x(); };\n" - "template<typename T> struct Z {\n" - " template<typename U> static void f() {\n" - " T().x();\n" - " }\n" - "};\n" - "void foo() { Z<Y>::f<int>(); }")); -} - -TEST(RecursiveASTVisitor, VisitsCallInNestedClassTemplateInstantiation) { - CXXMemberCallVisitor Visitor; - Visitor.ExpectMatch("A::x", 5, 7); - EXPECT_TRUE(Visitor.runOver( - "template <typename T1> struct X {\n" - " template <typename T2> struct Y {\n" - " void f() {\n" - " T2 y;\n" - " y.x();\n" - " }\n" - " };\n" - "};\n" - "struct A { void x(); };\n" - "int main() {\n" - " (new X<A>::Y<A>())->f();\n" - "}")); -} - -/* FIXME: According to Richard Smith this is a bug in the AST. -TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) { - DeclRefExprVisitor Visitor; - Visitor.ExpectMatch("x", 3, 43); - EXPECT_TRUE(Visitor.runOver( - "template <typename T> void x();\n" - "template <void (*T)()> class X {};\n" - "template <typename T> class Y : public X< x<T> > {};\n" - "Y<int> y;")); -} -*/ - -TEST(RecursiveASTVisitor, VisitsCallInPartialTemplateSpecialization) { - CXXMemberCallVisitor Visitor; - Visitor.ExpectMatch("A::x", 6, 20); - EXPECT_TRUE(Visitor.runOver( - "template <typename T1> struct X {\n" - " template <typename T2, bool B> struct Y { void g(); };\n" - "};\n" - "template <typename T1> template <typename T2>\n" - "struct X<T1>::Y<T2, true> {\n" - " void f() { T2 y; y.x(); }\n" - "};\n" - "struct A { void x(); };\n" - "int main() {\n" - " (new X<A>::Y<A, true>())->f();\n" - "}\n")); -} - -TEST(RecursiveASTVisitor, VisitsExplicitTemplateSpecialization) { - CXXMemberCallVisitor Visitor; - Visitor.ExpectMatch("A::f", 4, 5); - EXPECT_TRUE(Visitor.runOver( - "struct A {\n" - " void f() const {}\n" - " template<class T> void g(const T& t) const {\n" - " t.f();\n" - " }\n" - "};\n" - "template void A::g(const A& a) const;\n")); -} - -TEST(RecursiveASTVisitor, VisitsPartialTemplateSpecialization) { - // From cfe-commits/Week-of-Mon-20100830/033998.html - // Contrary to the approach suggested in that email, we visit all - // specializations when we visit the primary template. Visiting them when we - // visit the associated specialization is problematic for specializations of - // template members of class templates. - NamedDeclVisitor Visitor; - Visitor.ExpectMatch("A<bool>", 1, 26); - Visitor.ExpectMatch("A<char *>", 2, 26); - EXPECT_TRUE(Visitor.runOver( - "template <class T> class A {};\n" - "template <class T> class A<T*> {};\n" - "A<bool> ab;\n" - "A<char*> acp;\n")); -} - -TEST(RecursiveASTVisitor, VisitsUndefinedClassTemplateSpecialization) { - NamedDeclVisitor Visitor; - Visitor.ExpectMatch("A<int>", 1, 29); - EXPECT_TRUE(Visitor.runOver( - "template<typename T> struct A;\n" - "A<int> *p;\n")); -} - -TEST(RecursiveASTVisitor, VisitsNestedUndefinedClassTemplateSpecialization) { - NamedDeclVisitor Visitor; - Visitor.ExpectMatch("A<int>::B<char>", 2, 31); - EXPECT_TRUE(Visitor.runOver( - "template<typename T> struct A {\n" - " template<typename U> struct B;\n" - "};\n" - "A<int>::B<char> *p;\n")); -} - -TEST(RecursiveASTVisitor, VisitsUndefinedFunctionTemplateSpecialization) { - NamedDeclVisitor Visitor; - Visitor.ExpectMatch("A<int>", 1, 26); - EXPECT_TRUE(Visitor.runOver( - "template<typename T> int A();\n" - "int k = A<int>();\n")); -} - -TEST(RecursiveASTVisitor, VisitsNestedUndefinedFunctionTemplateSpecialization) { - NamedDeclVisitor Visitor; - Visitor.ExpectMatch("A<int>::B<char>", 2, 35); - EXPECT_TRUE(Visitor.runOver( - "template<typename T> struct A {\n" - " template<typename U> static int B();\n" - "};\n" - "int k = A<int>::B<char>();\n")); -} - -TEST(RecursiveASTVisitor, NoRecursionInSelfFriend) { - // From cfe-commits/Week-of-Mon-20100830/033977.html - NamedDeclVisitor Visitor; - Visitor.ExpectMatch("vector_iterator<int>", 2, 7); - EXPECT_TRUE(Visitor.runOver( - "template<typename Container>\n" - "class vector_iterator {\n" - " template <typename C> friend class vector_iterator;\n" - "};\n" - "vector_iterator<int> it_int;\n")); -} - -TEST(RecursiveASTVisitor, TraversesOverloadedOperator) { - CXXOperatorCallExprTraverser Visitor; - Visitor.ExpectMatch("()", 4, 9); - EXPECT_TRUE(Visitor.runOver( - "struct A {\n" - " int operator()();\n" - "} a;\n" - "int k = a();\n")); -} - -TEST(RecursiveASTVisitor, VisitsParensDuringDataRecursion) { - ParenExprVisitor Visitor; - Visitor.ExpectMatch("", 1, 9); - EXPECT_TRUE(Visitor.runOver("int k = (4) + 9;\n")); -} - -TEST(RecursiveASTVisitor, VisitsClassTemplateNonTypeParmDefaultArgument) { - CXXBoolLiteralExprVisitor Visitor; - Visitor.ExpectMatch("true", 2, 19); - EXPECT_TRUE(Visitor.runOver( - "template<bool B> class X;\n" - "template<bool B = true> class Y;\n" - "template<bool B> class Y {};\n")); -} - -TEST(RecursiveASTVisitor, VisitsClassTemplateTypeParmDefaultArgument) { - TypeLocVisitor Visitor; - Visitor.ExpectMatch("class X", 2, 23); - EXPECT_TRUE(Visitor.runOver( - "class X;\n" - "template<typename T = X> class Y;\n" - "template<typename T> class Y {};\n")); -} - -TEST(RecursiveASTVisitor, VisitsClassTemplateTemplateParmDefaultArgument) { - TemplateArgumentLocTraverser Visitor; - Visitor.ExpectMatch("X", 2, 40); - EXPECT_TRUE(Visitor.runOver( - "template<typename T> class X;\n" - "template<template <typename> class T = X> class Y;\n" - "template<template <typename> class T> class Y {};\n")); -} - -// A visitor that visits implicit declarations and matches constructors. -class ImplicitCtorVisitor - : public ExpectedLocationVisitor<ImplicitCtorVisitor> { -public: - bool shouldVisitImplicitCode() const { return true; } - - bool VisitCXXConstructorDecl(CXXConstructorDecl* Ctor) { - if (Ctor->isImplicit()) { // Was not written in source code - if (const CXXRecordDecl* Class = Ctor->getParent()) { - Match(Class->getName(), Ctor->getLocation()); - } - } - return true; - } -}; - -TEST(RecursiveASTVisitor, VisitsImplicitCopyConstructors) { - ImplicitCtorVisitor Visitor; - Visitor.ExpectMatch("Simple", 2, 8); - // Note: Clang lazily instantiates implicit declarations, so we need - // to use them in order to force them to appear in the AST. - EXPECT_TRUE(Visitor.runOver( - "struct WithCtor { WithCtor(); }; \n" - "struct Simple { Simple(); WithCtor w; }; \n" - "int main() { Simple s; Simple t(s); }\n")); -} - -/// \brief A visitor that optionally includes implicit code and matches -/// CXXConstructExpr. -/// -/// The name recorded for the match is the name of the class whose constructor -/// is invoked by the CXXConstructExpr, not the name of the class whose -/// constructor the CXXConstructExpr is contained in. -class ConstructExprVisitor - : public ExpectedLocationVisitor<ConstructExprVisitor> { -public: - ConstructExprVisitor() : ShouldVisitImplicitCode(false) {} - - bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; } - - void setShouldVisitImplicitCode(bool NewValue) { - ShouldVisitImplicitCode = NewValue; - } - - bool VisitCXXConstructExpr(CXXConstructExpr* Expr) { - if (const CXXConstructorDecl* Ctor = Expr->getConstructor()) { - if (const CXXRecordDecl* Class = Ctor->getParent()) { - Match(Class->getName(), Expr->getLocation()); - } - } - return true; - } - - private: - bool ShouldVisitImplicitCode; -}; - -TEST(RecursiveASTVisitor, CanVisitImplicitMemberInitializations) { - ConstructExprVisitor Visitor; - Visitor.setShouldVisitImplicitCode(true); - Visitor.ExpectMatch("WithCtor", 2, 8); - // Simple has a constructor that implicitly initializes 'w'. Test - // that a visitor that visits implicit code visits that initialization. - // Note: Clang lazily instantiates implicit declarations, so we need - // to use them in order to force them to appear in the AST. - EXPECT_TRUE(Visitor.runOver( - "struct WithCtor { WithCtor(); }; \n" - "struct Simple { WithCtor w; }; \n" - "int main() { Simple s; }\n")); -} - -// The same as CanVisitImplicitMemberInitializations, but checking that the -// visits are omitted when the visitor does not include implicit code. -TEST(RecursiveASTVisitor, CanSkipImplicitMemberInitializations) { - ConstructExprVisitor Visitor; - Visitor.setShouldVisitImplicitCode(false); - Visitor.DisallowMatch("WithCtor", 2, 8); - // Simple has a constructor that implicitly initializes 'w'. Test - // that a visitor that skips implicit code skips that initialization. - // Note: Clang lazily instantiates implicit declarations, so we need - // to use them in order to force them to appear in the AST. - EXPECT_TRUE(Visitor.runOver( - "struct WithCtor { WithCtor(); }; \n" - "struct Simple { WithCtor w; }; \n" - "int main() { Simple s; }\n")); -} - -TEST(RecursiveASTVisitor, VisitsExtension) { - DeclRefExprVisitor Visitor; - Visitor.ExpectMatch("s", 1, 24); - EXPECT_TRUE(Visitor.runOver( - "int s = __extension__ (s);\n")); -} - -TEST(RecursiveASTVisitor, VisitsCompoundLiteralType) { - TypeLocVisitor Visitor; - Visitor.ExpectMatch("struct S", 1, 26); - EXPECT_TRUE(Visitor.runOver( - "int f() { return (struct S { int a; }){.a = 0}.a; }", - TypeLocVisitor::Lang_C)); -} - -TEST(RecursiveASTVisitor, VisitsObjCPropertyType) { - TypeLocVisitor Visitor; - Visitor.ExpectMatch("NSNumber", 2, 33); - EXPECT_TRUE(Visitor.runOver( - "@class NSNumber; \n" - "@interface A @property (retain) NSNumber *x; @end\n", - TypeLocVisitor::Lang_OBJC)); -} - TEST(RecursiveASTVisitor, VisitsLambdaExpr) { LambdaExprVisitor Visitor; Visitor.ExpectMatch("", 1, 12); @@ -554,6 +52,18 @@ TEST(RecursiveASTVisitor, TraverseLambdaBodyCanBeOverridden) { EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed()); } +// Matches the (optional) capture-default of a lambda-introducer. +class LambdaDefaultCaptureVisitor + : public ExpectedLocationVisitor<LambdaDefaultCaptureVisitor> { +public: + bool VisitLambdaExpr(LambdaExpr *Lambda) { + if (Lambda->getCaptureDefault() != LCD_None) { + Match("", Lambda->getCaptureDefaultLoc()); + } + return true; + } +}; + TEST(RecursiveASTVisitor, HasCaptureDefaultLoc) { LambdaDefaultCaptureVisitor Visitor; Visitor.ExpectMatch("", 1, 20); @@ -561,16 +71,6 @@ TEST(RecursiveASTVisitor, HasCaptureDefaultLoc) { LambdaDefaultCaptureVisitor::Lang_CXX11)); } -TEST(RecursiveASTVisitor, VisitsCopyExprOfBlockDeclCapture) { - DeclRefExprVisitor Visitor; - Visitor.ExpectMatch("x", 3, 24); - EXPECT_TRUE(Visitor.runOver("void f(int(^)(int)); \n" - "void g() { \n" - " f([&](int x){ return x; }); \n" - "}", - DeclRefExprVisitor::Lang_OBJCXX11)); -} - // Checks for lambda classes that are not marked as implicitly-generated. // (There should be none.) class ClassVisitor : public ExpectedLocationVisitor<ClassVisitor> { @@ -598,7 +98,6 @@ TEST(RecursiveASTVisitor, LambdaClosureTypesAreImplicit) { } - // Check to ensure that attributes and expressions within them are being // visited. class AttrVisitor : public ExpectedLocationVisitor<AttrVisitor> { diff --git a/unittests/Tooling/RecursiveASTVisitorTestCallVisitor.cpp b/unittests/Tooling/RecursiveASTVisitorTestCallVisitor.cpp new file mode 100644 index 000000000000..f8ff5bdc7879 --- /dev/null +++ b/unittests/Tooling/RecursiveASTVisitorTestCallVisitor.cpp @@ -0,0 +1,121 @@ +//===- unittest/Tooling/RecursiveASTVisitorTestCallVisitor.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 <stack> + +using namespace clang; + +namespace { + +class CXXMemberCallVisitor + : public ExpectedLocationVisitor<CXXMemberCallVisitor> { +public: + bool VisitCXXMemberCallExpr(CXXMemberCallExpr *Call) { + Match(Call->getMethodDecl()->getQualifiedNameAsString(), + Call->getLocStart()); + return true; + } +}; + +TEST(RecursiveASTVisitor, VisitsCallInTemplateInstantiation) { + CXXMemberCallVisitor Visitor; + Visitor.ExpectMatch("Y::x", 3, 3); + EXPECT_TRUE(Visitor.runOver( + "struct Y { void x(); };\n" + "template<typename T> void y(T t) {\n" + " t.x();\n" + "}\n" + "void foo() { y<Y>(Y()); }")); +} + +TEST(RecursiveASTVisitor, VisitsCallInNestedFunctionTemplateInstantiation) { + CXXMemberCallVisitor Visitor; + Visitor.ExpectMatch("Y::x", 4, 5); + EXPECT_TRUE(Visitor.runOver( + "struct Y { void x(); };\n" + "template<typename T> struct Z {\n" + " template<typename U> static void f() {\n" + " T().x();\n" + " }\n" + "};\n" + "void foo() { Z<Y>::f<int>(); }")); +} + +TEST(RecursiveASTVisitor, VisitsCallInNestedClassTemplateInstantiation) { + CXXMemberCallVisitor Visitor; + Visitor.ExpectMatch("A::x", 5, 7); + EXPECT_TRUE(Visitor.runOver( + "template <typename T1> struct X {\n" + " template <typename T2> struct Y {\n" + " void f() {\n" + " T2 y;\n" + " y.x();\n" + " }\n" + " };\n" + "};\n" + "struct A { void x(); };\n" + "int main() {\n" + " (new X<A>::Y<A>())->f();\n" + "}")); +} + +TEST(RecursiveASTVisitor, VisitsCallInPartialTemplateSpecialization) { + CXXMemberCallVisitor Visitor; + Visitor.ExpectMatch("A::x", 6, 20); + EXPECT_TRUE(Visitor.runOver( + "template <typename T1> struct X {\n" + " template <typename T2, bool B> struct Y { void g(); };\n" + "};\n" + "template <typename T1> template <typename T2>\n" + "struct X<T1>::Y<T2, true> {\n" + " void f() { T2 y; y.x(); }\n" + "};\n" + "struct A { void x(); };\n" + "int main() {\n" + " (new X<A>::Y<A, true>())->f();\n" + "}\n")); +} + +TEST(RecursiveASTVisitor, VisitsExplicitTemplateSpecialization) { + CXXMemberCallVisitor Visitor; + Visitor.ExpectMatch("A::f", 4, 5); + EXPECT_TRUE(Visitor.runOver( + "struct A {\n" + " void f() const {}\n" + " template<class T> void g(const T& t) const {\n" + " t.f();\n" + " }\n" + "};\n" + "template void A::g(const A& a) const;\n")); +} + +class CXXOperatorCallExprTraverser + : public ExpectedLocationVisitor<CXXOperatorCallExprTraverser> { +public: + // Use Traverse, not Visit, to check that data recursion optimization isn't + // bypassing the call of this function. + bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *CE) { + Match(getOperatorSpelling(CE->getOperator()), CE->getExprLoc()); + return ExpectedLocationVisitor<CXXOperatorCallExprTraverser>:: + TraverseCXXOperatorCallExpr(CE); + } +}; + +TEST(RecursiveASTVisitor, TraversesOverloadedOperator) { + CXXOperatorCallExprTraverser Visitor; + Visitor.ExpectMatch("()", 4, 9); + EXPECT_TRUE(Visitor.runOver( + "struct A {\n" + " int operator()();\n" + "} a;\n" + "int k = a();\n")); +} + +} // end anonymous namespace diff --git a/unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp b/unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp new file mode 100644 index 000000000000..02676a737ab1 --- /dev/null +++ b/unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp @@ -0,0 +1,141 @@ +//===- unittest/Tooling/RecursiveASTVisitorTestDeclVisitor.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 <stack> + +using namespace clang; + +namespace { + +class VarDeclVisitor : public ExpectedLocationVisitor<VarDeclVisitor> { +public: + bool VisitVarDecl(VarDecl *Variable) { + Match(Variable->getNameAsString(), Variable->getLocStart()); + return true; + } +}; + +TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtLoopVariable) { + VarDeclVisitor Visitor; + Visitor.ExpectMatch("i", 2, 17); + EXPECT_TRUE(Visitor.runOver( + "int x[5];\n" + "void f() { for (int i : x) {} }", + VarDeclVisitor::Lang_CXX11)); +} + +class ParmVarDeclVisitorForImplicitCode : + public ExpectedLocationVisitor<ParmVarDeclVisitorForImplicitCode> { +public: + bool shouldVisitImplicitCode() const { return true; } + + bool VisitParmVarDecl(ParmVarDecl *ParamVar) { + Match(ParamVar->getNameAsString(), ParamVar->getLocStart()); + return true; + } +}; + +// Test RAV visits parameter variable declaration of the implicit +// copy assignment operator and implicit copy constructor. +TEST(RecursiveASTVisitor, VisitsParmVarDeclForImplicitCode) { + ParmVarDeclVisitorForImplicitCode Visitor; + // Match parameter variable name of implicit copy assignment operator and + // implicit copy constructor. + // This parameter name does not have a valid IdentifierInfo, and shares + // same SourceLocation with its class declaration, so we match an empty name + // with the class' source location. + Visitor.ExpectMatch("", 1, 7); + Visitor.ExpectMatch("", 3, 7); + EXPECT_TRUE(Visitor.runOver( + "class X {};\n" + "void foo(X a, X b) {a = b;}\n" + "class Y {};\n" + "void bar(Y a) {Y b = a;}")); +} + +class NamedDeclVisitor + : public ExpectedLocationVisitor<NamedDeclVisitor> { +public: + bool VisitNamedDecl(NamedDecl *Decl) { + std::string NameWithTemplateArgs; + llvm::raw_string_ostream OS(NameWithTemplateArgs); + Decl->getNameForDiagnostic(OS, + Decl->getASTContext().getPrintingPolicy(), + true); + Match(OS.str(), Decl->getLocation()); + return true; + } +}; + +TEST(RecursiveASTVisitor, VisitsPartialTemplateSpecialization) { + // From cfe-commits/Week-of-Mon-20100830/033998.html + // Contrary to the approach suggested in that email, we visit all + // specializations when we visit the primary template. Visiting them when we + // visit the associated specialization is problematic for specializations of + // template members of class templates. + NamedDeclVisitor Visitor; + Visitor.ExpectMatch("A<bool>", 1, 26); + Visitor.ExpectMatch("A<char *>", 2, 26); + EXPECT_TRUE(Visitor.runOver( + "template <class T> class A {};\n" + "template <class T> class A<T*> {};\n" + "A<bool> ab;\n" + "A<char*> acp;\n")); +} + +TEST(RecursiveASTVisitor, VisitsUndefinedClassTemplateSpecialization) { + NamedDeclVisitor Visitor; + Visitor.ExpectMatch("A<int>", 1, 29); + EXPECT_TRUE(Visitor.runOver( + "template<typename T> struct A;\n" + "A<int> *p;\n")); +} + +TEST(RecursiveASTVisitor, VisitsNestedUndefinedClassTemplateSpecialization) { + NamedDeclVisitor Visitor; + Visitor.ExpectMatch("A<int>::B<char>", 2, 31); + EXPECT_TRUE(Visitor.runOver( + "template<typename T> struct A {\n" + " template<typename U> struct B;\n" + "};\n" + "A<int>::B<char> *p;\n")); +} + +TEST(RecursiveASTVisitor, VisitsUndefinedFunctionTemplateSpecialization) { + NamedDeclVisitor Visitor; + Visitor.ExpectMatch("A<int>", 1, 26); + EXPECT_TRUE(Visitor.runOver( + "template<typename T> int A();\n" + "int k = A<int>();\n")); +} + +TEST(RecursiveASTVisitor, VisitsNestedUndefinedFunctionTemplateSpecialization) { + NamedDeclVisitor Visitor; + Visitor.ExpectMatch("A<int>::B<char>", 2, 35); + EXPECT_TRUE(Visitor.runOver( + "template<typename T> struct A {\n" + " template<typename U> static int B();\n" + "};\n" + "int k = A<int>::B<char>();\n")); +} + +TEST(RecursiveASTVisitor, NoRecursionInSelfFriend) { + // From cfe-commits/Week-of-Mon-20100830/033977.html + NamedDeclVisitor Visitor; + Visitor.ExpectMatch("vector_iterator<int>", 2, 7); + EXPECT_TRUE(Visitor.runOver( + "template<typename Container>\n" + "class vector_iterator {\n" + " template <typename C> friend class vector_iterator;\n" + "};\n" + "vector_iterator<int> it_int;\n")); +} + +} // end anonymous namespace diff --git a/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp b/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp new file mode 100644 index 000000000000..6af5906c3fd4 --- /dev/null +++ b/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp @@ -0,0 +1,224 @@ +//===- unittest/Tooling/RecursiveASTVisitorTestExprVisitor.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 <stack> + +using namespace clang; + +namespace { + +class ParenExprVisitor : public ExpectedLocationVisitor<ParenExprVisitor> { +public: + bool VisitParenExpr(ParenExpr *Parens) { + Match("", Parens->getExprLoc()); + return true; + } +}; + +TEST(RecursiveASTVisitor, VisitsParensDuringDataRecursion) { + ParenExprVisitor Visitor; + Visitor.ExpectMatch("", 1, 9); + EXPECT_TRUE(Visitor.runOver("int k = (4) + 9;\n")); +} + +class TemplateArgumentLocTraverser + : public ExpectedLocationVisitor<TemplateArgumentLocTraverser> { +public: + bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) { + std::string ArgStr; + llvm::raw_string_ostream Stream(ArgStr); + const TemplateArgument &Arg = ArgLoc.getArgument(); + + Arg.print(Context->getPrintingPolicy(), Stream); + Match(Stream.str(), ArgLoc.getLocation()); + return ExpectedLocationVisitor<TemplateArgumentLocTraverser>:: + TraverseTemplateArgumentLoc(ArgLoc); + } +}; + +TEST(RecursiveASTVisitor, VisitsClassTemplateTemplateParmDefaultArgument) { + TemplateArgumentLocTraverser Visitor; + Visitor.ExpectMatch("X", 2, 40); + EXPECT_TRUE(Visitor.runOver( + "template<typename T> class X;\n" + "template<template <typename> class T = X> class Y;\n" + "template<template <typename> class T> class Y {};\n")); +} + +class CXXBoolLiteralExprVisitor + : public ExpectedLocationVisitor<CXXBoolLiteralExprVisitor> { +public: + bool VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *BE) { + if (BE->getValue()) + Match("true", BE->getLocation()); + else + Match("false", BE->getLocation()); + return true; + } +}; + +TEST(RecursiveASTVisitor, VisitsClassTemplateNonTypeParmDefaultArgument) { + CXXBoolLiteralExprVisitor Visitor; + Visitor.ExpectMatch("true", 2, 19); + EXPECT_TRUE(Visitor.runOver( + "template<bool B> class X;\n" + "template<bool B = true> class Y;\n" + "template<bool B> class Y {};\n")); +} + +// A visitor that visits implicit declarations and matches constructors. +class ImplicitCtorVisitor + : public ExpectedLocationVisitor<ImplicitCtorVisitor> { +public: + bool shouldVisitImplicitCode() const { return true; } + + bool VisitCXXConstructorDecl(CXXConstructorDecl* Ctor) { + if (Ctor->isImplicit()) { // Was not written in source code + if (const CXXRecordDecl* Class = Ctor->getParent()) { + Match(Class->getName(), Ctor->getLocation()); + } + } + return true; + } +}; + +TEST(RecursiveASTVisitor, VisitsImplicitCopyConstructors) { + ImplicitCtorVisitor Visitor; + Visitor.ExpectMatch("Simple", 2, 8); + // Note: Clang lazily instantiates implicit declarations, so we need + // to use them in order to force them to appear in the AST. + EXPECT_TRUE(Visitor.runOver( + "struct WithCtor { WithCtor(); }; \n" + "struct Simple { Simple(); WithCtor w; }; \n" + "int main() { Simple s; Simple t(s); }\n")); +} + +/// \brief A visitor that optionally includes implicit code and matches +/// CXXConstructExpr. +/// +/// The name recorded for the match is the name of the class whose constructor +/// is invoked by the CXXConstructExpr, not the name of the class whose +/// constructor the CXXConstructExpr is contained in. +class ConstructExprVisitor + : public ExpectedLocationVisitor<ConstructExprVisitor> { +public: + ConstructExprVisitor() : ShouldVisitImplicitCode(false) {} + + bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; } + + void setShouldVisitImplicitCode(bool NewValue) { + ShouldVisitImplicitCode = NewValue; + } + + bool VisitCXXConstructExpr(CXXConstructExpr* Expr) { + if (const CXXConstructorDecl* Ctor = Expr->getConstructor()) { + if (const CXXRecordDecl* Class = Ctor->getParent()) { + Match(Class->getName(), Expr->getLocation()); + } + } + return true; + } + + private: + bool ShouldVisitImplicitCode; +}; + +TEST(RecursiveASTVisitor, CanVisitImplicitMemberInitializations) { + ConstructExprVisitor Visitor; + Visitor.setShouldVisitImplicitCode(true); + Visitor.ExpectMatch("WithCtor", 2, 8); + // Simple has a constructor that implicitly initializes 'w'. Test + // that a visitor that visits implicit code visits that initialization. + // Note: Clang lazily instantiates implicit declarations, so we need + // to use them in order to force them to appear in the AST. + EXPECT_TRUE(Visitor.runOver( + "struct WithCtor { WithCtor(); }; \n" + "struct Simple { WithCtor w; }; \n" + "int main() { Simple s; }\n")); +} + +// The same as CanVisitImplicitMemberInitializations, but checking that the +// visits are omitted when the visitor does not include implicit code. +TEST(RecursiveASTVisitor, CanSkipImplicitMemberInitializations) { + ConstructExprVisitor Visitor; + Visitor.setShouldVisitImplicitCode(false); + Visitor.DisallowMatch("WithCtor", 2, 8); + // Simple has a constructor that implicitly initializes 'w'. Test + // that a visitor that skips implicit code skips that initialization. + // Note: Clang lazily instantiates implicit declarations, so we need + // to use them in order to force them to appear in the AST. + EXPECT_TRUE(Visitor.runOver( + "struct WithCtor { WithCtor(); }; \n" + "struct Simple { WithCtor w; }; \n" + "int main() { Simple s; }\n")); +} + +class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> { +public: + bool VisitDeclRefExpr(DeclRefExpr *Reference) { + Match(Reference->getNameInfo().getAsString(), Reference->getLocation()); + return true; + } +}; + +TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) { + DeclRefExprVisitor Visitor; + Visitor.ExpectMatch("x", 2, 3); + EXPECT_TRUE(Visitor.runOver( + "void x(); template <void (*T)()> class X {};\nX<x> y;")); +} + +TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtRange) { + DeclRefExprVisitor Visitor; + Visitor.ExpectMatch("x", 2, 25); + Visitor.ExpectMatch("x", 2, 30); + EXPECT_TRUE(Visitor.runOver( + "int x[5];\n" + "void f() { for (int i : x) { x[0] = 1; } }", + DeclRefExprVisitor::Lang_CXX11)); +} + +TEST(RecursiveASTVisitor, VisitsCallExpr) { + DeclRefExprVisitor Visitor; + Visitor.ExpectMatch("x", 1, 22); + EXPECT_TRUE(Visitor.runOver( + "void x(); void y() { x(); }")); +} + +/* FIXME: According to Richard Smith this is a bug in the AST. +TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) { + DeclRefExprVisitor Visitor; + Visitor.ExpectMatch("x", 3, 43); + EXPECT_TRUE(Visitor.runOver( + "template <typename T> void x();\n" + "template <void (*T)()> class X {};\n" + "template <typename T> class Y : public X< x<T> > {};\n" + "Y<int> y;")); +} +*/ + +TEST(RecursiveASTVisitor, VisitsExtension) { + DeclRefExprVisitor Visitor; + Visitor.ExpectMatch("s", 1, 24); + EXPECT_TRUE(Visitor.runOver( + "int s = __extension__ (s);\n")); +} + +TEST(RecursiveASTVisitor, VisitsCopyExprOfBlockDeclCapture) { + DeclRefExprVisitor Visitor; + Visitor.ExpectMatch("x", 3, 24); + EXPECT_TRUE(Visitor.runOver("void f(int(^)(int)); \n" + "void g() { \n" + " f([&](int x){ return x; }); \n" + "}", + DeclRefExprVisitor::Lang_OBJCXX11)); +} + +} // end anonymous namespace diff --git a/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp b/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp new file mode 100644 index 000000000000..63e2e8b6024c --- /dev/null +++ b/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp @@ -0,0 +1,93 @@ +//===- unittest/Tooling/RecursiveASTVisitorTestTypeLocVisitor.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 <stack> + +using namespace clang; + +namespace { + +class TypeLocVisitor : public ExpectedLocationVisitor<TypeLocVisitor> { +public: + bool VisitTypeLoc(TypeLoc TypeLocation) { + Match(TypeLocation.getType().getAsString(), TypeLocation.getBeginLoc()); + return true; + } +}; + +TEST(RecursiveASTVisitor, VisitsBaseClassDeclarations) { + TypeLocVisitor Visitor; + Visitor.ExpectMatch("class X", 1, 30); + EXPECT_TRUE(Visitor.runOver("class X {}; class Y : public X {};")); +} + +TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersOfForwardDeclaredClass) { + TypeLocVisitor Visitor; + Visitor.ExpectMatch("class X", 3, 18); + EXPECT_TRUE(Visitor.runOver( + "class Y;\n" + "class X {};\n" + "class Y : public X {};")); +} + +TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersWithIncompleteInnerClass) { + TypeLocVisitor Visitor; + Visitor.ExpectMatch("class X", 2, 18); + EXPECT_TRUE(Visitor.runOver( + "class X {};\n" + "class Y : public X { class Z; };")); +} + +TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersOfSelfReferentialType) { + TypeLocVisitor Visitor; + Visitor.ExpectMatch("X<class Y>", 2, 18); + EXPECT_TRUE(Visitor.runOver( + "template<typename T> class X {};\n" + "class Y : public X<Y> {};")); +} + +TEST(RecursiveASTVisitor, VisitsClassTemplateTypeParmDefaultArgument) { + TypeLocVisitor Visitor; + Visitor.ExpectMatch("class X", 2, 23); + EXPECT_TRUE(Visitor.runOver( + "class X;\n" + "template<typename T = X> class Y;\n" + "template<typename T> class Y {};\n")); +} + +TEST(RecursiveASTVisitor, VisitsCompoundLiteralType) { + TypeLocVisitor Visitor; + Visitor.ExpectMatch("struct S", 1, 26); + EXPECT_TRUE(Visitor.runOver( + "int f() { return (struct S { int a; }){.a = 0}.a; }", + TypeLocVisitor::Lang_C)); +} + +TEST(RecursiveASTVisitor, VisitsObjCPropertyType) { + TypeLocVisitor Visitor; + Visitor.ExpectMatch("NSNumber", 2, 33); + EXPECT_TRUE(Visitor.runOver( + "@class NSNumber; \n" + "@interface A @property (retain) NSNumber *x; @end\n", + TypeLocVisitor::Lang_OBJC)); +} + +TEST(RecursiveASTVisitor, VisitInvalidType) { + TypeLocVisitor Visitor; + // FIXME: It would be nice to have information about subtypes of invalid type + //Visitor.ExpectMatch("typeof(struct F *) []", 1, 1); + // Even if the full type is invalid, it should still find sub types + //Visitor.ExpectMatch("struct F", 1, 19); + EXPECT_FALSE(Visitor.runOver( + "__typeof__(struct F*) var[invalid];\n", + TypeLocVisitor::Lang_C)); +} + +} // end anonymous namespace diff --git a/unittests/Tooling/RefactoringTest.cpp b/unittests/Tooling/RefactoringTest.cpp index ddb974ac9f4a..a026a942610b 100644 --- a/unittests/Tooling/RefactoringTest.cpp +++ b/unittests/Tooling/RefactoringTest.cpp @@ -237,7 +237,8 @@ public: const FileEntry *File = Context.Files.getFile(Path); assert(File != nullptr); - StringRef Found = TemporaryFiles.GetOrCreateValue(Name, Path.str()).second; + StringRef Found = + TemporaryFiles.insert(std::make_pair(Name, Path.str())).first->second; assert(Found == Path); (void)Found; return Context.Sources.createFileID(File, SourceLocation(), SrcMgr::C_User); @@ -251,9 +252,8 @@ public: // descriptor, which might not see the changes made. // FIXME: Figure out whether there is a way to get the SourceManger to // reopen the file. - std::unique_ptr<const llvm::MemoryBuffer> FileBuffer( - Context.Files.getBufferForFile(Path, nullptr)); - return FileBuffer->getBuffer(); + auto FileBuffer = Context.Files.getBufferForFile(Path); + return (*FileBuffer)->getBuffer(); } llvm::StringMap<std::string> TemporaryFiles; @@ -299,11 +299,12 @@ private: public: TestAction(TestVisitor *Visitor) : Visitor(Visitor) {} - virtual clang::ASTConsumer* CreateASTConsumer( - clang::CompilerInstance& compiler, llvm::StringRef dummy) { + virtual std::unique_ptr<clang::ASTConsumer> + CreateASTConsumer(clang::CompilerInstance &compiler, + llvm::StringRef dummy) { Visitor->SM = &compiler.getSourceManager(); /// TestConsumer will be deleted by the framework calling us. - return new FindConsumer(Visitor); + return llvm::make_unique<FindConsumer>(Visitor); } private: @@ -392,6 +393,8 @@ TEST(DeduplicateTest, removesDuplicates) { Input.push_back(Replacement("fileA", 50, 0, " foo ")); // Duplicate Input.push_back(Replacement("fileA", 51, 3, " bar ")); Input.push_back(Replacement("fileB", 51, 3, " bar ")); // Filename differs! + Input.push_back(Replacement("fileB", 60, 1, " bar ")); + Input.push_back(Replacement("fileA", 60, 2, " bar ")); Input.push_back(Replacement("fileA", 51, 3, " moo ")); // Replacement text // differs! @@ -402,12 +405,14 @@ TEST(DeduplicateTest, removesDuplicates) { Expected.push_back(Replacement("fileA", 50, 0, " foo ")); Expected.push_back(Replacement("fileA", 51, 3, " bar ")); Expected.push_back(Replacement("fileA", 51, 3, " moo ")); - Expected.push_back(Replacement("fileB", 51, 3, " bar ")); + Expected.push_back(Replacement("fileB", 60, 1, " bar ")); + Expected.push_back(Replacement("fileA", 60, 2, " bar ")); std::vector<Range> Conflicts; // Ignored for this test deduplicate(Input, Conflicts); - ASSERT_TRUE(Expected == Input); + EXPECT_EQ(3U, Conflicts.size()); + EXPECT_EQ(Expected, Input); } TEST(DeduplicateTest, detectsConflicts) { diff --git a/unittests/Tooling/RewriterTestContext.h b/unittests/Tooling/RewriterTestContext.h index fe108ad308e5..112efac52ebc 100644 --- a/unittests/Tooling/RewriterTestContext.h +++ b/unittests/Tooling/RewriterTestContext.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_REWRITER_TEST_CONTEXT_H -#define LLVM_CLANG_REWRITER_TEST_CONTEXT_H +#ifndef LLVM_CLANG_UNITTESTS_TOOLING_REWRITERTESTCONTEXT_H +#define LLVM_CLANG_UNITTESTS_TOOLING_REWRITERTESTCONTEXT_H #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" @@ -48,10 +48,11 @@ class RewriterTestContext { ~RewriterTestContext() {} FileID createInMemoryFile(StringRef Name, StringRef Content) { - llvm::MemoryBuffer *Source = llvm::MemoryBuffer::getMemBuffer(Content); + std::unique_ptr<llvm::MemoryBuffer> Source = + llvm::MemoryBuffer::getMemBuffer(Content); const FileEntry *Entry = Files.getVirtualFile(Name, Source->getBufferSize(), 0); - Sources.overrideFileContents(Entry, Source); + Sources.overrideFileContents(Entry, std::move(Source)); assert(Entry != nullptr); return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User); } @@ -71,7 +72,8 @@ class RewriterTestContext { const FileEntry *File = Files.getFile(Path); assert(File != nullptr); - StringRef Found = TemporaryFiles.GetOrCreateValue(Name, Path.str()).second; + StringRef Found = + TemporaryFiles.insert(std::make_pair(Name, Path.str())).first->second; assert(Found == Path); (void)Found; return Sources.createFileID(File, SourceLocation(), SrcMgr::C_User); @@ -100,9 +102,8 @@ class RewriterTestContext { // descriptor, which might not see the changes made. // FIXME: Figure out whether there is a way to get the SourceManger to // reopen the file. - std::unique_ptr<const llvm::MemoryBuffer> FileBuffer( - Files.getBufferForFile(Path, nullptr)); - return FileBuffer->getBuffer(); + auto FileBuffer = Files.getBufferForFile(Path); + return (*FileBuffer)->getBuffer(); } IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; diff --git a/unittests/Tooling/TestVisitor.h b/unittests/Tooling/TestVisitor.h index 205a0aa16eb6..d4416950f226 100644 --- a/unittests/Tooling/TestVisitor.h +++ b/unittests/Tooling/TestVisitor.h @@ -12,8 +12,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_TEST_VISITOR_H -#define LLVM_CLANG_TEST_VISITOR_H +#ifndef LLVM_CLANG_UNITTESTS_TOOLING_TESTVISITOR_H +#define LLVM_CLANG_UNITTESTS_TOOLING_TESTVISITOR_H #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -95,10 +95,10 @@ protected: public: TestAction(TestVisitor *Visitor) : Visitor(Visitor) {} - virtual clang::ASTConsumer* CreateASTConsumer( - CompilerInstance&, llvm::StringRef dummy) { + virtual std::unique_ptr<clang::ASTConsumer> + CreateASTConsumer(CompilerInstance &, llvm::StringRef dummy) { /// TestConsumer will be deleted by the framework calling us. - return new FindConsumer(Visitor); + return llvm::make_unique<FindConsumer>(Visitor); } protected: @@ -231,4 +231,4 @@ protected: }; } -#endif /* LLVM_CLANG_TEST_VISITOR_H */ +#endif diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp index 9aede044f695..5a93e38c80c2 100644 --- a/unittests/Tooling/ToolingTest.cpp +++ b/unittests/Tooling/ToolingTest.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Config/llvm-config.h" #include "gtest/gtest.h" +#include <algorithm> #include <string> namespace clang { @@ -28,20 +29,20 @@ namespace { /// Takes an ast consumer and returns it from CreateASTConsumer. This only /// works with single translation unit compilations. class TestAction : public clang::ASTFrontendAction { - public: +public: /// Takes ownership of TestConsumer. - explicit TestAction(clang::ASTConsumer *TestConsumer) - : TestConsumer(TestConsumer) {} + explicit TestAction(std::unique_ptr<clang::ASTConsumer> TestConsumer) + : TestConsumer(std::move(TestConsumer)) {} - protected: - virtual clang::ASTConsumer* CreateASTConsumer( - clang::CompilerInstance& compiler, StringRef dummy) { +protected: + virtual std::unique_ptr<clang::ASTConsumer> + CreateASTConsumer(clang::CompilerInstance &compiler, StringRef dummy) { /// TestConsumer will be deleted by the framework calling us. - return TestConsumer; + return std::move(TestConsumer); } - private: - clang::ASTConsumer * const TestConsumer; +private: + std::unique_ptr<clang::ASTConsumer> TestConsumer; }; class FindTopLevelDeclConsumer : public clang::ASTConsumer { @@ -59,8 +60,10 @@ class FindTopLevelDeclConsumer : public clang::ASTConsumer { TEST(runToolOnCode, FindsNoTopLevelDeclOnEmptyCode) { bool FoundTopLevelDecl = false; - EXPECT_TRUE(runToolOnCode( - new TestAction(new FindTopLevelDeclConsumer(&FoundTopLevelDecl)), "")); + EXPECT_TRUE( + runToolOnCode(new TestAction(llvm::make_unique<FindTopLevelDeclConsumer>( + &FoundTopLevelDecl)), + "")); EXPECT_FALSE(FoundTopLevelDecl); } @@ -97,13 +100,17 @@ bool FindClassDeclX(ASTUnit *AST) { TEST(runToolOnCode, FindsClassDecl) { bool FoundClassDeclX = false; - EXPECT_TRUE(runToolOnCode(new TestAction( - new FindClassDeclXConsumer(&FoundClassDeclX)), "class X;")); + EXPECT_TRUE( + runToolOnCode(new TestAction(llvm::make_unique<FindClassDeclXConsumer>( + &FoundClassDeclX)), + "class X;")); EXPECT_TRUE(FoundClassDeclX); FoundClassDeclX = false; - EXPECT_TRUE(runToolOnCode(new TestAction( - new FindClassDeclXConsumer(&FoundClassDeclX)), "class Y;")); + EXPECT_TRUE( + runToolOnCode(new TestAction(llvm::make_unique<FindClassDeclXConsumer>( + &FoundClassDeclX)), + "class Y;")); EXPECT_FALSE(FoundClassDeclX); } @@ -125,8 +132,8 @@ TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) { } struct IndependentFrontendActionCreator { - ASTConsumer *newASTConsumer() { - return new FindTopLevelDeclConsumer(nullptr); + std::unique_ptr<ASTConsumer> newASTConsumer() { + return llvm::make_unique<FindTopLevelDeclConsumer>(nullptr); } }; @@ -182,11 +189,11 @@ struct VerifyEndCallback : public SourceFileCallbacks { ++BeginCalled; return true; } - virtual void handleEndSource() { + virtual void handleEndSource() override { ++EndCalled; } - ASTConsumer *newASTConsumer() { - return new FindTopLevelDeclConsumer(&Matched); + std::unique_ptr<ASTConsumer> newASTConsumer() { + return llvm::make_unique<FindTopLevelDeclConsumer>(&Matched); } unsigned BeginCalled; unsigned EndCalled; @@ -225,10 +232,10 @@ struct SkipBodyConsumer : public clang::ASTConsumer { }; struct SkipBodyAction : public clang::ASTFrontendAction { - virtual ASTConsumer *CreateASTConsumer(CompilerInstance &Compiler, - StringRef) { + virtual std::unique_ptr<ASTConsumer> + CreateASTConsumer(CompilerInstance &Compiler, StringRef) { Compiler.getFrontendOpts().SkipFunctionBodies = true; - return new SkipBodyConsumer; + return llvm::make_unique<SkipBodyConsumer>(); } }; @@ -254,25 +261,6 @@ TEST(runToolOnCodeWithArgs, TestNoDepFile) { EXPECT_FALSE(llvm::sys::fs::remove(DepFilePath.str())); } -struct CheckSyntaxOnlyAdjuster: public ArgumentsAdjuster { - bool &Found; - bool &Ran; - - CheckSyntaxOnlyAdjuster(bool &Found, bool &Ran) : Found(Found), Ran(Ran) { } - - virtual CommandLineArguments - Adjust(const CommandLineArguments &Args) override { - Ran = true; - for (unsigned I = 0, E = Args.size(); I != E; ++I) { - if (Args[I] == "-fsyntax-only") { - Found = true; - break; - } - } - return Args; - } -}; - TEST(ClangToolTest, ArgumentAdjusters) { FixedCompilationDatabase Compilations("/", std::vector<std::string>()); @@ -284,15 +272,22 @@ TEST(ClangToolTest, ArgumentAdjusters) { bool Found = false; bool Ran = false; - Tool.appendArgumentsAdjuster(new CheckSyntaxOnlyAdjuster(Found, Ran)); + ArgumentsAdjuster CheckSyntaxOnlyAdjuster = + [&Found, &Ran](const CommandLineArguments &Args) { + Ran = true; + if (std::find(Args.begin(), Args.end(), "-fsyntax-only") != Args.end()) + Found = true; + return Args; + }; + Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster); Tool.run(Action.get()); EXPECT_TRUE(Ran); EXPECT_TRUE(Found); Ran = Found = false; Tool.clearArgumentsAdjusters(); - Tool.appendArgumentsAdjuster(new CheckSyntaxOnlyAdjuster(Found, Ran)); - Tool.appendArgumentsAdjuster(new ClangSyntaxOnlyAdjuster()); + Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster); + Tool.appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster()); Tool.run(Action.get()); EXPECT_TRUE(Ran); EXPECT_FALSE(Found); diff --git a/unittests/libclang/LibclangTest.cpp b/unittests/libclang/LibclangTest.cpp index ee56e229367b..a21881429e62 100644 --- a/unittests/libclang/LibclangTest.cpp +++ b/unittests/libclang/LibclangTest.cpp @@ -8,11 +8,11 @@ //===----------------------------------------------------------------------===// #include "clang-c/Index.h" -#include "gtest/gtest.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" #include <fstream> #include <set> #define DEBUG_TYPE "libclang-test" diff --git a/unittests/libclang/Makefile b/unittests/libclang/Makefile index a6590eb97aeb..f8e83aa83a1b 100644 --- a/unittests/libclang/Makefile +++ b/unittests/libclang/Makefile @@ -20,6 +20,7 @@ USEDLIBS = clang.a \ clangIndex.a clangFormat.a clangRewrite.a \ clangFrontend.a clangDriver.a \ clangTooling.a \ + clangToolingCore.a \ clangSerialization.a clangParse.a clangSema.a \ clangAnalysis.a clangEdit.a clangAST.a clangLex.a \ clangBasic.a |