1 /** 2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved. 3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 This file tests the class visitor for C++. 7 */ 8 module test.component.analyzer.cpp_class_visitor; 9 10 import std.conv : to; 11 import std.format : format; 12 import std.typecons : scoped, Yes; 13 import std.variant : visit; 14 import logger = std.experimental.logger; 15 16 import unit_threaded; 17 import test.clang_util; 18 import test.helpers; 19 20 // TODO this is a mega import. Reduce it 21 import cpptooling.data; 22 23 import cpptooling.analyzer.clang.ast; 24 import cpptooling.analyzer.clang.analyze_helper; 25 import cpptooling.analyzer.clang.context : ClangContext; 26 import cpptooling.analyzer.clang.cursor_logger : logNode, mixinNodeLog; 27 import cpptooling.analyzer.clang.type; 28 import cpptooling.data.symbol : Container; 29 import cpptooling.data.representation; 30 import cpptooling.data : TypeKindVariable, VariadicType, Location, CppNsStack, 31 USRType, toStringDecl; 32 import cpptooling.utility.virtualfilesystem : FileName, Content; 33 34 /* These lines are useful when debugging. 35 import unit_threaded; 36 writelnUt(visitor.container.toString); 37 */ 38 39 final class TestVisitor : Visitor { 40 import cpptooling.analyzer.clang.ast; 41 42 alias visit = Visitor.visit; 43 mixin generateIndentIncrDecr; 44 45 Container container; 46 47 /// The USR to find. 48 USRType find; 49 50 CppClass[] classes; 51 bool found; 52 53 override void visit(const(TranslationUnit) v) { 54 mixin(mixinNodeLog!()); 55 v.accept(this); 56 } 57 58 override void visit(const(ClassDecl) v) @trusted { 59 mixin(mixinNodeLog!()); 60 61 import std.typecons : scoped; 62 import cpptooling.analyzer.clang.analyze_helper : ClassVisitor; 63 import cpptooling.analyzer.clang.type : retrieveType; 64 import cpptooling.analyzer.clang.store : put; 65 66 ///TODO add information if it is a public/protected/private class. 67 ///TODO add metadata to the class if it is a definition or declaration 68 69 auto result = analyzeRecord(v, container, indent + 1); 70 debug logger.trace("class: ", result.name); 71 72 if (v.cursor.isDefinition) { 73 auto visitor = scoped!ClassVisitor(v, CppNsStack.init, result, container, indent + 1); 74 v.accept(visitor); 75 classes ~= visitor.root; 76 } else { 77 auto type = retrieveType(v.cursor, container, indent); 78 put(type, container, indent); 79 } 80 } 81 } 82 83 @("shall be a class with a method using the typedef as return value") 84 unittest { 85 // This test result in the return type for some_func being 86 // `const unsigned int( &x)[1]` in clang 3.7/3.8. 87 // But seems to work in 3.9 88 89 immutable code = " 90 namespace ns1 { 91 typedef unsigned int some_unsigned; 92 typedef some_unsigned the_type; 93 typedef the_type some_array[1]; 94 } 95 96 class Class { 97 public: 98 const ns1::some_array& some_func(); 99 }; 100 "; 101 102 // arrange 103 auto ctx = ClangContext(Yes.useInternalHeaders, Yes.prependParamSyntaxOnly); 104 ctx.virtualFileSystem.openAndWrite(cast(FileName) "/issue.hpp", cast(Content) code); 105 auto tu = ctx.makeTranslationUnit("/issue.hpp"); 106 auto visitor = new TestVisitor; 107 //visitor.find = "c:@F@some_func#"; 108 109 // act 110 auto ast = ClangAST!(typeof(visitor))(tu.cursor); 111 ast.accept(visitor); 112 113 // assert 114 checkForCompilerErrors(tu).shouldBeFalse; 115 visitor.classes.length.shouldEqual(1); 116 visitor.classes[0].methodPublicRange.length.shouldEqual(1); 117 118 import std.variant : visit; 119 120 CppMethod method; 121 122 // dfmt off 123 visitor.classes[0].methodPublicRange[0].visit!( 124 (const CppMethod a) { method = cast(CppMethod) a; return; }, 125 (const CppMethodOp a) => 0.shouldEqual(1), 126 (const CppCtor a) => 0.shouldEqual(1), 127 (const CppDtor a) => 0.shouldEqual(1)); 128 // dfmt on 129 130 method.returnType.toStringDecl("x").shouldEqual("const ns1::some_array &x"); 131 }