//===- unittest/AST/ASTTypeTraits.cpp - AST type traits unit tests ------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===--------------------------------------------------------------------===// #include "clang/AST/ASTTypeTraits.h" #include "MatchVerifier.h" #include "gtest/gtest.h" using namespace clang::ast_matchers; namespace clang { namespace { TEST(ASTNodeKind, NoKind) { EXPECT_FALSE(ASTNodeKind().isBaseOf(ASTNodeKind())); EXPECT_FALSE(ASTNodeKind().isSame(ASTNodeKind())); } template static ASTNodeKind DNT() { return ASTNodeKind::getFromNodeKind(); } TEST(ASTNodeKind, IsNone) { EXPECT_TRUE(ASTNodeKind().isNone()); EXPECT_FALSE(DNT().isNone()); EXPECT_FALSE(DNT().isNone()); } TEST(ASTNodeKind, Bases) { EXPECT_TRUE(DNT().isBaseOf(DNT())); EXPECT_FALSE(DNT().isSame(DNT())); EXPECT_FALSE(DNT().isBaseOf(DNT())); EXPECT_TRUE(DNT().isSame(DNT())); } TEST(DynTypedNode, Clades) { EXPECT_TRUE(DNT().getCladeKind().isSame(DNT())); EXPECT_TRUE(DNT().getCladeKind().isSame(DNT())); EXPECT_TRUE(DNT().getCladeKind().isSame(DNT())); EXPECT_TRUE(DNT().getCladeKind().isSame(DNT())); EXPECT_FALSE(DNT().getCladeKind().isSame(DNT())); EXPECT_TRUE(ASTNodeKind().getCladeKind().isNone()); } TEST(ASTNodeKind, BaseDistances) { unsigned Distance = 1; EXPECT_TRUE(DNT().isBaseOf(DNT(), &Distance)); EXPECT_EQ(0u, Distance); EXPECT_TRUE(DNT().isBaseOf(DNT(), &Distance)); EXPECT_EQ(1u, Distance); Distance = 3; EXPECT_TRUE(DNT().isBaseOf(DNT(), &Distance)); EXPECT_EQ(2u, Distance); } TEST(ASTNodeKind, SameBase) { EXPECT_TRUE(DNT().isBaseOf(DNT())); EXPECT_TRUE(DNT().isBaseOf(DNT())); EXPECT_FALSE(DNT().isBaseOf(DNT())); EXPECT_FALSE(DNT().isBaseOf(DNT())); } TEST(ASTNodeKind, DiffBase) { EXPECT_FALSE(DNT().isBaseOf(DNT())); EXPECT_FALSE(DNT().isBaseOf(DNT())); EXPECT_FALSE(DNT().isSame(DNT())); } TEST(ASTNodeKind, MostDerivedType) { EXPECT_TRUE(DNT().isSame( ASTNodeKind::getMostDerivedType(DNT(), DNT()))); EXPECT_TRUE(DNT().isSame( ASTNodeKind::getMostDerivedType(DNT(), DNT()))); EXPECT_TRUE(DNT().isSame( ASTNodeKind::getMostDerivedType(DNT(), DNT()))); // Not related. Returns nothing. EXPECT_TRUE( ASTNodeKind::getMostDerivedType(DNT(), DNT()).isNone()); EXPECT_TRUE(ASTNodeKind::getMostDerivedType(DNT(), DNT()).isNone()); } TEST(ASTNodeKind, MostDerivedCommonAncestor) { EXPECT_TRUE(DNT().isSame(ASTNodeKind::getMostDerivedCommonAncestor( DNT(), DNT()))); EXPECT_TRUE(DNT().isSame(ASTNodeKind::getMostDerivedCommonAncestor( DNT(), DNT()))); EXPECT_TRUE(DNT().isSame(ASTNodeKind::getMostDerivedCommonAncestor( DNT(), DNT()))); // A little related. Returns the ancestor. EXPECT_TRUE( DNT().isSame(ASTNodeKind::getMostDerivedCommonAncestor( DNT(), DNT()))); // Not related. Returns nothing. EXPECT_TRUE(ASTNodeKind::getMostDerivedCommonAncestor( DNT(), DNT()).isNone()); } struct Foo {}; TEST(ASTNodeKind, UnknownKind) { // We can construct one, but it is nowhere in the hierarchy. EXPECT_FALSE(DNT().isSame(DNT())); } template constexpr bool HasPointerIdentity = ASTNodeKind::getFromNodeKind().hasPointerIdentity(); TEST(ASTNodeKind, ConstexprHasPointerIdentity) { EXPECT_TRUE(HasPointerIdentity); EXPECT_TRUE(HasPointerIdentity); EXPECT_FALSE(HasPointerIdentity); EXPECT_FALSE(HasPointerIdentity); EXPECT_FALSE(HasPointerIdentity); constexpr bool DefaultConstructedHasPointerIdentity = ASTNodeKind().hasPointerIdentity(); EXPECT_FALSE(DefaultConstructedHasPointerIdentity); } template constexpr bool NodeKindIsSame = ASTNodeKind::getFromNodeKind().isSame(ASTNodeKind::getFromNodeKind()); TEST(ASTNodeKind, ConstexprIsSame) { EXPECT_TRUE((NodeKindIsSame)); EXPECT_FALSE((NodeKindIsSame)); EXPECT_FALSE((NodeKindIsSame)); constexpr bool DefaultConstructedIsSameToDefaultConstructed = ASTNodeKind().isSame(ASTNodeKind()); EXPECT_FALSE(DefaultConstructedIsSameToDefaultConstructed); } template constexpr bool NodeKindIsNone = ASTNodeKind::getFromNodeKind().isNone(); TEST(ASTNodeKind, ConstexprIsNone) { EXPECT_FALSE(NodeKindIsNone); EXPECT_TRUE(NodeKindIsNone); constexpr bool DefaultConstructedIsNone = ASTNodeKind().isNone(); EXPECT_TRUE(DefaultConstructedIsNone); } TEST(ASTNodeKind, Name) { EXPECT_EQ("", ASTNodeKind().asStringRef()); #define VERIFY_NAME(Node) EXPECT_EQ(#Node, DNT().asStringRef()); VERIFY_NAME(TemplateArgument); VERIFY_NAME(NestedNameSpecifierLoc); VERIFY_NAME(QualType); VERIFY_NAME(TypeLoc); VERIFY_NAME(CXXCtorInitializer); VERIFY_NAME(ConceptReference); VERIFY_NAME(NestedNameSpecifier); VERIFY_NAME(Decl); VERIFY_NAME(CXXRecordDecl); VERIFY_NAME(Stmt); VERIFY_NAME(CallExpr); VERIFY_NAME(Type); VERIFY_NAME(ConstantArrayType); VERIFY_NAME(NonNullAttr); #undef VERIFY_NAME } TEST(DynTypedNode, DeclSourceRange) { RangeVerifier Verifier; Verifier.expectRange(1, 1, 1, 11); EXPECT_TRUE(Verifier.match("void f() {}", decl())); } TEST(DynTypedNode, StmtSourceRange) { RangeVerifier Verifier; Verifier.expectRange(1, 10, 1, 11); EXPECT_TRUE(Verifier.match("void f() {}", stmt())); } TEST(DynTypedNode, TypeLocSourceRange) { RangeVerifier Verifier; Verifier.expectRange(1, 1, 1, 8); EXPECT_TRUE(Verifier.match("void f() {}", typeLoc(loc(functionType())))); } TEST(DynTypedNode, NNSLocSourceRange) { RangeVerifier Verifier; Verifier.expectRange(1, 33, 1, 34); EXPECT_TRUE(Verifier.match("namespace N { typedef void T; } N::T f() {}", nestedNameSpecifierLoc())); } TEST(DynTypedNode, AttrSourceRange) { RangeVerifier Verifier; Verifier.expectRange(1, 31, 1, 31); EXPECT_TRUE(Verifier.match("void x(char *y __attribute__((nonnull)) );", ast_matchers::attr())); } // FIXME: add tests for ConceptReference once we add an ASTMatcher. TEST(DynTypedNode, DeclDump) { DumpVerifier Verifier; Verifier.expectSubstring("FunctionDecl"); EXPECT_TRUE(Verifier.match("void f() {}", functionDecl())); } TEST(DynTypedNode, StmtDump) { DumpVerifier Verifier; Verifier.expectSubstring("CompoundStmt"); EXPECT_TRUE(Verifier.match("void f() {}", stmt())); } TEST(DynTypedNode, DeclPrint) { PrintVerifier Verifier; Verifier.expectString("void f() {\n}\n"); EXPECT_TRUE(Verifier.match("void f() {}", functionDecl())); } TEST(DynTypedNode, StmtPrint) { PrintVerifier Verifier; Verifier.expectString("{\n}\n"); EXPECT_TRUE(Verifier.match("void f() {}", stmt())); } TEST(DynTypedNode, QualType) { QualType Q; DynTypedNode Node = DynTypedNode::create(Q); EXPECT_TRUE(Node == Node); EXPECT_FALSE(Node < Node); } TEST(DynTypedNode, TypeLoc) { std::string code = R"cc(void example() { int abc; })cc"; auto AST = clang::tooling::buildASTFromCode(code); auto matches = match(traverse(TK_AsIs, varDecl(hasName("abc"), hasTypeLoc(typeLoc().bind("tl")))), AST->getASTContext()); EXPECT_EQ(matches.size(), 1u); const auto &tl = *matches[0].getNodeAs("tl"); DynTypedNode Node = DynTypedNode::create(tl); EXPECT_TRUE(Node == Node); EXPECT_FALSE(Node < Node); } TEST(DynTypedNode, PointerTypeLoc) { std::string code = R"cc(void example() { int *abc; })cc"; auto AST = clang::tooling::buildASTFromCode(code); auto matches = match(traverse(TK_AsIs, varDecl(hasName("abc"), hasTypeLoc(typeLoc().bind("ptl")))), AST->getASTContext()); EXPECT_EQ(matches.size(), 1u); const auto &tl = *matches[0].getNodeAs("ptl"); DynTypedNode TypeLocNode = DynTypedNode::create(tl); EXPECT_TRUE(TypeLocNode == TypeLocNode); EXPECT_FALSE(TypeLocNode < TypeLocNode); const auto &ptl = *matches[0].getNodeAs("ptl"); EXPECT_EQ(&tl, &ptl); DynTypedNode PointerTypeLocNode = DynTypedNode::create(ptl); EXPECT_TRUE(PointerTypeLocNode == PointerTypeLocNode); EXPECT_FALSE(PointerTypeLocNode < PointerTypeLocNode); } } // namespace } // namespace clang