} I'd be at least interested in seeing it. We developed this functionality as a test for RecursiveASTVisitor.h. As I understand it, the reason we haven't tried to submit it upstream yet is that it's still quite incomplete. (It will probably need to be refactored into one test per kind of AST node, rather than a single monolithic test like we have now.)
This is all Zhanyong's work, so I'll let him speak to how practical it would be to get something upstream. I also don't want so share the test code itself without his ok, but I've attached the actual test file below. It's at least enough to show what the output looks like, and how one might do FileCheck tests with it. craig --cut here-- // Copyright 2010 Google Inc. All Rights Reserved. // Author: [email protected] (Zhanyong Wan) // ast_visitor_test.py uses FileCheck to verify the Clang AST // generated by this file. See http://llvm.org/cmds/FileCheck.html // for how FileCheck works. // // Please read the comments at the beginning of dump_ast.cc to learn // the meaning of the CHECK-NEXT lines in this file, and read README // for how to update this file in case ast_visitor_test fails. #include <stddef.h> // for offsetof() #include <typeinfo> // for typeid() //////////////////////////////////////////////////////////// // Tests traversing VarDecl. // A variable declaration without an initializer expression. // CHECK: . |=VarDecl: start // CHECK-NEXT: . | `=BuiltinType: int int start; // A variable declaration with a simple initializer expression. // CHECK-NEXT: . |=VarDecl: n // CHECK-NEXT: . | |=BuiltinType: int // CHECK-NEXT: . | `=IntegerLiteral int n = 0; // A const variable definition. // CHECK-NEXT: . |=VarDecl: kInteger // CHECK-NEXT: . | |=BuiltinType: int // CHECK-NEXT: . | `=IntegerLiteral const int kInteger = 42; //////////////////////////////////////////////////////////// // Tests traversing an enum definition. // CHECK-NEXT: . |=EnumDecl: MyEnum // CHECK-NEXT: . | |=EnumType: MyEnum enum MyEnum { // CHECK-NEXT: . | |=EnumConstantDecl: MyEnum::kVal1 // CHECK-NEXT: . | | `=ImplicitCastExpr // CHECK-NEXT: . | | `=IntegerLiteral kVal1 = 0, // CHECK-NEXT: . | `=EnumConstantDecl: MyEnum::kVal2 kVal2 }; //////////////////////////////////////////////////////////// // Tests traversing FunctionDecl. // CHECK-NEXT: . |=CXXRecordDecl: FooClass class FooClass; // A declaration of a function that has no argument. // CHECK-NEXT: . |=FunctionDecl: VoidFunc // CHECK-NEXT: . | `=FunctionProtoType: void () // CHECK-NEXT: . | `=BuiltinType: void void VoidFunc(); // A declaration of a function with default parameters. // CHECK-NEXT: . |=FunctionDecl: OneArgFunc // CHECK-NEXT: . | `=FunctionProtoType: float (int) // CHECK-NEXT: . | |=BuiltinType: float // CHECK-NEXT: . | `=ParmVarDecl: a // CHECK-NEXT: . | |=BuiltinType: int // CHECK-NEXT: . | |=BinaryOperator // CHECK-NEXT: . | | |=IntegerLiteral // CHECK-NEXT: . | | `=IntegerLiteral // CHECK-NEXT: . | `=BinaryOperator // CHECK-NEXT: . | |=IntegerLiteral // CHECK-NEXT: . | `=IntegerLiteral float OneArgFunc(int a = 5*4); // A definition of a one-argument function. // CHECK-NEXT: . |=FunctionDecl: IntFunc // CHECK-NEXT: . | |=FunctionProtoType // CHECK-NEXT: . | | |=BuiltinType: int int IntFunc( // CHECK-NEXT: . | | `=ParmVarDecl: foo // CHECK-NEXT: . | | `=PointerType: FooClass * // CHECK-NEXT: . | | `=RecordType: FooClass FooClass* foo) // CHECK-NEXT: . | `=CompoundStmt { // CHECK-NEXT: . | `=ReturnStmt // CHECK-NEXT: . | `=IntegerLiteral return 0; } // A function declaration done via a function typedef. // CHECK-NEXT: . |=TypedefDecl: MyIntFuncType // CHECK-NEXT: . | `=FunctionProtoType: int (bool) // CHECK-NEXT: . | |=BuiltinType: int // CHECK-NEXT: . | `=ParmVarDecl: flag // CHECK-NEXT: . | `=BuiltinType: bool typedef int MyIntFuncType(bool flag); // CHECK-NEXT: . |=FunctionDecl: MyIntFunc // CHECK-NEXT: . | `=TypedefType: MyIntFuncType MyIntFuncType MyIntFunc; //////////////////////////////////////////////////////////// // Tests template forward declarations. // A class template with a template type parameter and a non-type // template parameter. // CHECK-NEXT: . |=ClassTemplateDecl: ClassTemplate // TODO(wan): traverse the template parameters before the CXXRecordDecl. // CHECK-NEXT: . | |=CXXRecordDecl: ClassTemplate // CHECK-NEXT: . | |=TemplateTypeParmDecl: T // CHECK-NEXT: . | | `=TemplateTypeParmType: T // CHECK-NEXT: . | `=NonTypeTemplateParmDecl: N // CHECK-NEXT: . | `=BuiltinType: int template <typename T, int N> class ClassTemplate; // A function template with a template type parameter and a template // template parameter. // CHECK-NEXT: . |=FunctionTemplateDecl: FunctionTemplate // TODO(wan): traverse the template parameters before the FunctionDecl // and FunctionProtoType. // CHECK-NEXT: . | |=FunctionDecl: FunctionTemplate // CHECK-NEXT: . | | `=FunctionProtoType: int (T const &) // CHECK-NEXT: . | | |=BuiltinType: int // CHECK-NEXT: . | | `=ParmVarDecl: x // CHECK-NEXT: . | | `=LValueReferenceType: T const & // CHECK-NEXT: . | | `=TemplateTypeParmType: T // CHECK-NEXT: . | |=TemplateTypeParmDecl: T // CHECK-NEXT: . | | `=TemplateTypeParmType: T // CHECK-NEXT: . | `=TemplateTemplateParmDecl: V // CHECK-NEXT: . | `=TemplateTypeParmDecl: U // CHECK-NEXT: . | `=TemplateTypeParmType: U template <class T, template <typename U> class V> int FunctionTemplate(const T& x); // A class template with default template arguments. // CHECK-NEXT: . |=ClassTemplateDecl: ClassTemplate2 // CHECK-NEXT: . | |=CXXRecordDecl: ClassTemplate2 template < // CHECK-NEXT: . | |=TemplateTypeParmDecl: T // CHECK-NEXT: . | | |=TemplateTypeParmType: T // CHECK-NEXT: . | | `=BuiltinType: int class T=int, // CHECK-NEXT: . | |=NonTypeTemplateParmDecl: N // CHECK-NEXT: . | | |=BuiltinType: int // CHECK-NEXT: . | | `=ImplicitCastExpr // CHECK-NEXT: . | | `=SizeOfAlignOfExpr // CHECK-NEXT: . | | `=TemplateTypeParmType: T int N=sizeof(T), // CHECK-NEXT: . | `=TemplateTemplateParmDecl: V // CHECK-NEXT: . | |=TemplateTypeParmDecl: U // CHECK-NEXT: . | | `=TemplateTypeParmType: U // CHECK-NEXT: . | `=NonTypeTemplateParmDecl: M // CHECK-NEXT: . | `=BuiltinType: int // TODO(wan): traverse the default value ClassTemplate. template <typename U, int M> class V=ClassTemplate> class ClassTemplate2; // Another template with default template arguments. // CHECK-NEXT: . |=ClassTemplateDecl: StructTemplate1 // CHECK-NEXT: . | |=CXXRecordDecl: StructTemplate1 template < // CHECK-NEXT: . | |=NonTypeTemplateParmDecl: E // CHECK-NEXT: . | | |=EnumType: MyEnum // CHECK-NEXT: . | | `=DeclRefExpr MyEnum E = kVal1, // CHECK-NEXT: . | |=NonTypeTemplateParmDecl: B // CHECK-NEXT: . | | |=BuiltinType: bool // CHECK-NEXT: . | | `=ParenExpr // CHECK-NEXT: . | | `=BinaryOperator // CHECK-NEXT: . | | |=ImplicitCastExpr // CHECK-NEXT: . | | | `=DeclRefExpr // CHECK-NEXT: . | | `=IntegerLiteral bool B = (kInteger < 5), // CHECK-NEXT: . | `=NonTypeTemplateParmDecl: I // CHECK-NEXT: . | |=BuiltinType: int // CHECK-NEXT: . | `=ImplicitCastExpr // CHECK-NEXT: . | `=SizeOfAlignOfExpr // CHECK-NEXT: . | `=PointerType: void * // CHECK-NEXT: . | `=BuiltinType: void int I = sizeof(void*)> struct StructTemplate1; // CHECK-NEXT: . |=ClassTemplateDecl: X // CHECK-NEXT: . | |=CXXRecordDecl: X // TODO(wan): traverse A before X. // CHECK-NEXT: . | `=TemplateTypeParmDecl: A // CHECK-NEXT: . | `=TemplateTypeParmType: A template <class A> struct X {}; // CHECK-NEXT: . |=CXXRecordDecl: Foo class Foo { // CHECK-NEXT: . | `=FieldDecl: Foo::x // CHECK-NEXT: . | `=ElaboratedType: struct X<int> // CHECK-NEXT: . | `=TemplateSpecializationType: X<int> // CHECK-NEXT: . | `=BuiltinType: int struct X<int> x; }; // CHECK-NEXT: . |=ClassTemplateDecl: Bar // CHECK-NEXT: . | |=CXXRecordDecl: Bar template <class A> class Bar { // CHECK-NEXT: . | | `=FieldDecl: Bar::x // CHECK-NEXT: . | | `=ElaboratedType: struct X<A> // CHECK-NEXT: . | | `=TemplateSpecializationType: X<A> // CHECK-NEXT: . | | `=TemplateTypeParmType: A // TODO(wan): traverse A before x. // CHECK-NEXT: . | `=TemplateTypeParmDecl: A // CHECK-NEXT: . | `=TemplateTypeParmType: A struct X<A> x; }; //////////////////////////////////////////////////////////// // Tests traversing CXXRecordDecl. // A forward declaration. // CHECK-NEXT: . |=CXXRecordDecl: FooClass class FooClass; // An empty class definition. // CHECK-NEXT: . |=CXXRecordDecl: EmptyClass class EmptyClass { }; // A class definition. // CHECK-NEXT: . |=CXXRecordDecl: FooClass class FooClass { //////////////////////////////////////////////////////////// // Tests traversing AccessSpecDecl. // CHECK-NEXT: . | |=AccessSpecDecl public: //////////////////////////////////////////////////////////// // Tests traversing CXXConstructorDecl. // A default constructor. // CHECK-NEXT: . | |=CXXConstructorDecl: FooClass::FooClass // CHECK-NEXT: . | | `=FunctionProtoType: void () // CHECK-NEXT: . | | `=BuiltinType: void FooClass(); // A single-argument constructor. // CHECK-NEXT: . | |=CXXConstructorDecl: FooClass::FooClass // CHECK-NEXT: . | | |=FunctionProtoType: void (int) // CHECK-NEXT: . | | | |=BuiltinType: void // CHECK-NEXT: . | | | `=ParmVarDecl: value // CHECK-NEXT: . | | | `=BuiltinType: int FooClass(int value) // CHECK-NEXT: . | | |=DeclRefExpr : value_(value) // CHECK-NEXT: . | | `=CompoundStmt {} // A ctor with more than one element in its initializer list. // CHECK-NEXT: . | |=CXXConstructorDecl: FooClass::FooClass // CHECK-NEXT: . | | |=FunctionProtoType: void (bool) // CHECK-NEXT: . | | | |=BuiltinType: void // CHECK-NEXT: . | | | `=ParmVarDecl: flag // CHECK-NEXT: . | | | `=BuiltinType: bool FooClass(bool flag) // CHECK-NEXT: . | | |=IntegerLiteral : value_(42), // CHECK-NEXT: . | | |=DeclRefExpr flag_(flag) // CHECK-NEXT: . | | `=CompoundStmt {} //////////////////////////////////////////////////////////// // Tests traversing CXXDestructorDecl. // CHECK-NEXT: . | |=CXXDestructorDecl: FooClass::~FooClass // CHECK-NEXT: . | | |=FunctionProtoType: void () // CHECK-NEXT: . | | | `=BuiltinType: void ~FooClass() // CHECK-NEXT: . | | `=CompoundStmt {} //////////////////////////////////////////////////////////// // Tests traversing CXXMethodDecl. // A non-static method. // CHECK-NEXT: . | |=CXXMethodDecl: FooClass::Method1 // CHECK-NEXT: . | | |=FunctionProtoType: void (bool) // CHECK-NEXT: . | | | |=BuiltinType: void void Method1( // CHECK-NEXT: . | | | `=ParmVarDecl: flag // CHECK-NEXT: . | | | `=BuiltinType: bool bool flag) // CHECK-NEXT: . | | `=CompoundStmt {} //////////////////////////////////////////////////////////// // Tests traversing CXXConversionDecl. // CHECK-NEXT: . | |=CXXConversionDecl: FooClass::operator _Bool // CHECK-NEXT: . | | |=FunctionProtoType: bool () const // CHECK-NEXT: . | | | `=BuiltinType: bool operator bool() const // CHECK-NEXT: . | | `=CompoundStmt { // CHECK-NEXT: . | | `=ReturnStmt // CHECK-NEXT: . | | `=CXXBoolLiteralExpr return true; } // CHECK-NEXT: . | |=AccessSpecDecl private: //////////////////////////////////////////////////////////// // Tests traversing FieldDecl. // CHECK-NEXT: . | |=FieldDecl: FooClass::value_ // CHECK-NEXT: . | | `=BuiltinType: int int value_; // CHECK-NEXT: . | `=FieldDecl: FooClass::flag_ // CHECK-NEXT: . | `=BuiltinType: bool bool flag_; }; //////////////////////////////////////////////////////////// // Tests traversing temporary objects. // A temporary object of a built-in (i.e. non-class) type. // CHECK-NEXT: . |=VarDecl: int_var // CHECK-NEXT: . | |=BuiltinType: int int int_var = // CHECK-NEXT: . | `=CXXScalarValueInitExpr // CHECK-NEXT: . | `=BuiltinType: int int(); // A temporary object of a class type. // CHECK-NEXT: . |=VarDecl: empty_class_var // CHECK-NEXT: . | |=RecordType: EmptyClass EmptyClass empty_class_var = // CHECK-NEXT: . | `=CXXConstructExpr // CHECK-NEXT: . | `=ImplicitCastExpr // CHECK-NEXT: . | `=CXXTemporaryObjectExpr // CHECK-NEXT: . | `=RecordType: EmptyClass EmptyClass(); //////////////////////////////////////////////////////////// // Tests various types of arrays // CHECK-NEXT: . |=FunctionTemplateDecl: ArrayTestingFunction // CHECK-NEXT: . | |=FunctionDecl: ArrayTestingFunction // CHECK-NEXT: . | | |=FunctionProtoType: void (int *) // CHECK-NEXT: . | | | |=BuiltinType: void template<typename T, int Size> void ArrayTestingFunction( // allows vla // CHECK-NEXT: . | | | `=ParmVarDecl: a // CHECK-NEXT: . | | | `=IncompleteArrayType: int [] // CHECK-NEXT: . | | | `=BuiltinType: int // CHECK-NEXT: . | | `=CompoundStmt int a[]) { // CHECK-NEXT: . | | |=DeclStmt // CHECK-NEXT: . | | | `=VarDecl: kConstInt // CHECK-NEXT: . | | | |=BuiltinType: int // CHECK-NEXT: . | | | `=IntegerLiteral const int kConstInt = 5; // CHECK-NEXT: . | | |=DeclStmt // CHECK-NEXT: . | | | `=VarDecl: nonconst_int // CHECK-NEXT: . | | | |=BuiltinType: int // CHECK-NEXT: . | | | `=IntegerLiteral int nonconst_int = 6; // CHECK-NEXT: . | | |=DeclStmt // CHECK-NEXT: . | | | `=VarDecl: array // CHECK-NEXT: . | | | `=ConstantArrayType: int [5] // CHECK-NEXT: . | | | |=BuiltinType: int // CHECK-NEXT: . | | | `=DeclRefExpr int array[kConstInt]; // CHECK-NEXT: . | | |=DeclStmt // CHECK-NEXT: . | | | `=VarDecl: variable_length_array // CHECK-NEXT: . | | | `=VariableArrayType: int [nonconst_int] // CHECK-NEXT: . | | | |=BuiltinType: int // CHECK-NEXT: . | | | `=DeclRefExpr int variable_length_array[nonconst_int]; // CHECK-NEXT: . | | `=DeclStmt // CHECK-NEXT: . | | `=VarDecl: dependent_type_array // CHECK-NEXT: . | | `=DependentSizedArrayType: T [Size] // CHECK-NEXT: . | | |=TemplateTypeParmType: T // CHECK-NEXT: . | | `=DeclRefExpr T dependent_type_array[Size]; } // TODO(csilvers): these should come before the body, not after. // CHECK-NEXT: . | |=TemplateTypeParmDecl: T // CHECK-NEXT: . | | `=TemplateTypeParmType: T // CHECK-NEXT: . | `=NonTypeTemplateParmDecl: Size // CHECK-NEXT: . | `=BuiltinType: int //////////////////////////////////////////////////////////// // Tests sizeof, offsetof, typeid, and unary_type_trait // CHECK-NEXT: . |=CXXRecordDecl: OffsetOfA struct OffsetOfA { // CHECK-NEXT: . | `=FieldDecl: OffsetOfA::a // CHECK-NEXT: . | `=BuiltinType: int int a; }; // CHECK-NEXT: . |=CXXRecordDecl: OffsetOfB struct OffsetOfB { // CHECK-NEXT: . | `=FieldDecl: OffsetOfB::b // CHECK-NEXT: . | `=ConstantArrayType: OffsetOfA [10] // CHECK-NEXT: . | |=RecordType: OffsetOfA // CHECK-NEXT: . | `=IntegerLiteral OffsetOfA b[10]; }; // CHECK-NEXT: . |=CXXRecordDecl: OffsetOfC struct OffsetOfC { // CHECK-NEXT: . | `=FieldDecl: OffsetOfC::c // CHECK-NEXT: . | `=ConstantArrayType: OffsetOfB [10] // CHECK-NEXT: . | |=RecordType: OffsetOfB // CHECK-NEXT: . | `=IntegerLiteral OffsetOfB c[10]; }; // CHECK-NEXT: . |=FunctionDecl: StarOfTestingFunction // CHECK-NEXT: . | |=FunctionProtoType: void () // CHECK-NEXT: . | | `=BuiltinType: void // CHECK-NEXT: . | `=CompoundStmt void StarOfTestingFunction() { // allows vla // CHECK-NEXT: . | |=DeclStmt // CHECK-NEXT: . | | `=VarDecl: nonconst_int // CHECK-NEXT: . | | |=BuiltinType: int // CHECK-NEXT: . | | `=IntegerLiteral int nonconst_int = 6; // CHECK-NEXT: . | |=DeclStmt // CHECK-NEXT: . | | `=VarDecl: variable_length_array // CHECK-NEXT: . | | `=VariableArrayType: int [nonconst_int] // CHECK-NEXT: . | | |=BuiltinType: int // CHECK-NEXT: . | | `=DeclRefExpr int variable_length_array[nonconst_int]; // CHECK-NEXT: . | |=DeclStmt // CHECK-NEXT: . | | `=VarDecl: sizeof_var1 // CHECK-NEXT: . | | |=BuiltinType: int // CHECK-NEXT: . | | `=ImplicitCastExpr // CHECK-NEXT: . | | `=SizeOfAlignOfExpr // CHECK-NEXT: . | | `=RecordType: OffsetOfA const int sizeof_var1 = sizeof(OffsetOfA); // CHECK-NEXT: . | |=DeclStmt // CHECK-NEXT: . | | `=VarDecl: sizeof_var2 // CHECK-NEXT: . | | |=BuiltinType: int // CHECK-NEXT: . | | `=ImplicitCastExpr // CHECK-NEXT: . | | `=SizeOfAlignOfExpr // CHECK-NEXT: . | | `=DeclRefExpr const int sizeof_var2 = sizeof nonconst_int; // CHECK-NEXT: . | |=DeclStmt // CHECK-NEXT: . | | `=VarDecl: sizeof_var3 // CHECK-NEXT: . | | |=BuiltinType: int // CHECK-NEXT: . | | `=ImplicitCastExpr // CHECK-NEXT: . | | `=SizeOfAlignOfExpr // CHECK-NEXT: . | | `=ParenExpr // CHECK-NEXT: . | | `=DeclRefExpr const int sizeof_var3 = sizeof(variable_length_array); // CHECK-NEXT: . | |=CStyleCastExpr // CHECK-NEXT: . | | |=BuiltinType: void // CHECK-NEXT: . | | `=CXXTypeidExpr // CHECK-NEXT: . | | `=DeclRefExpr (void)typeid(nonconst_int); // CHECK-NEXT: . | |=CStyleCastExpr // CHECK-NEXT: . | | |=BuiltinType: void // CHECK-NEXT: . | | `=CXXTypeidExpr // CHECK-NEXT: . | | `=RecordType: OffsetOfB (void)typeid(OffsetOfB); // CHECK-NEXT: . | |=DeclStmt // CHECK-NEXT: . | | `=VarDecl: offset // CHECK-NEXT: . | | |=BuiltinType: int // CHECK-NEXT: . | | `=ImplicitCastExpr // CHECK-NEXT: . | | `=OffsetOfExpr // CHECK-NEXT: . | | |=RecordType: OffsetOfC // CHECK-NEXT: . | | |=BinaryOperator // CHECK-NEXT: . | | | |=IntegerLiteral // CHECK-NEXT: . | | | `=ImplicitCastExpr // CHECK-NEXT: . | | | `=DeclRefExpr // CHECK-NEXT: . | | `=DeclRefExpr const int offset = offsetof(OffsetOfC, c[9 + kInteger].b[kInteger].a); // CHECK-NEXT: . | `=DeclStmt // CHECK-NEXT: . | `=VarDecl: unary_trait // CHECK-NEXT: . | |=BuiltinType: int // CHECK-NEXT: . | `=ImplicitCastExpr // CHECK-NEXT: . | `=UnaryTypeTraitExpr // CHECK-NEXT: . | `=RecordType: OffsetOfA const int unary_trait = __is_enum(OffsetOfA); } //////////////////////////////////////////////////////////// // Tests exceptions. // CHECK-NEXT: . |=FunctionDecl: simple_function // CHECK-NEXT: . | `=FunctionProtoType: void (char) throw(int, float) // CHECK-NEXT: . | |=BuiltinType: void // CHECK-NEXT: . | |=ParmVarDecl: a // CHECK-NEXT: . | | `=BuiltinType: char // CHECK-NEXT: . | |=BuiltinType: int // CHECK-NEXT: . | `=BuiltinType: float void simple_function(char a) throw(int, float); // CHECK-NEXT: . |=FunctionDecl: simple_function // CHECK-NEXT: . | |=FunctionProtoType: void (char) throw(int, float) // CHECK-NEXT: . | | |=BuiltinType: void // CHECK-NEXT: . | | |=ParmVarDecl: a // CHECK-NEXT: . | | | `=BuiltinType: char // CHECK-NEXT: . | | |=BuiltinType: int // CHECK-NEXT: . | | `=BuiltinType: float // CHECK-NEXT: . | `=CompoundStmt void simple_function(char a) throw(int, float) { // CHECK-NEXT: . | `=CXXTryStmt // CHECK-NEXT: . | |=CompoundStmt try { // CHECK-NEXT: . | |=CXXCatchStmt // CHECK-NEXT: . | | |=VarDecl: i // CHECK-NEXT: . | | | `=BuiltinType: int // CHECK-NEXT: . | | `=CompoundStmt } catch (int i) { // CHECK-NEXT: . | | `=CXXThrowExpr throw; // CHECK-NEXT: . | |=CXXCatchStmt // CHECK-NEXT: . | | |=VarDecl: // CHECK-NEXT: . | | | `=PointerType: int * // CHECK-NEXT: . | | | `=BuiltinType: int // CHECK-NEXT: . | | `=CompoundStmt } catch (int*) { // CHECK-NEXT: . | |=CXXCatchStmt // CHECK-NEXT: . | | |=VarDecl: // CHECK-NEXT: . | | | `=BuiltinType: float // CHECK-NEXT: . | | `=CompoundStmt } catch (float) { // CHECK-NEXT: . | | `=CXXThrowExpr throw; // CHECK-NEXT: . | `=CXXCatchStmt // CHECK-NEXT: . | `=CompoundStmt } catch (...) { } } //////////////////////////////////////////////////////////// // Tests templatized functions // CHECK-NEXT: . |=FunctionTemplateDecl: TplFn // CHECK-NEXT: . | |=FunctionDecl: TplFn // CHECK-NEXT: . | | |=FunctionProtoType: int (T) // CHECK-NEXT: . | | | |=BuiltinType: int // CHECK-NEXT: . | | | `=ParmVarDecl: t // CHECK-NEXT: . | | | `=TemplateTypeParmType: T // CHECK-NEXT: . | | `=CompoundStmt // CHECK-NEXT: . | | `=ReturnStmt // CHECK-NEXT: . | | `=IntegerLiteral // CHECK-NEXT: . | `=TemplateTypeParmDecl: T // CHECK-NEXT: . | `=TemplateTypeParmType: T template<typename T> int TplFn(T t) { return 1; } // CHECK-NEXT: . |=FunctionDecl: TplFn // CHECK-NEXT: . | |=BuiltinType: char // CHECK-NEXT: . | |=FunctionProtoType: int (char) // CHECK-NEXT: . | | |=BuiltinType: int // CHECK-NEXT: . | | `=ParmVarDecl: t // CHECK-NEXT: . | | `=BuiltinType: char // CHECK-NEXT: . | `=CompoundStmt // CHECK-NEXT: . | `=ReturnStmt // CHECK-NEXT: . | `=IntegerLiteral template<> int TplFn<char>(char t) { return 2; } // CHECK-NEXT: . |=FunctionTemplateDecl: TplFnTI // CHECK-NEXT: . | |=FunctionDecl: TplFnTI // CHECK-NEXT: . | | |=FunctionProtoType: int (T (&)[I]) // CHECK-NEXT: . | | | |=BuiltinType: int // CHECK-NEXT: . | | | `=ParmVarDecl: t // CHECK-NEXT: . | | | `=LValueReferenceType: T (&)[I] // CHECK-NEXT: . | | | `=DependentSizedArrayType: T [I] // CHECK-NEXT: . | | | |=TemplateTypeParmType: T // CHECK-NEXT: . | | | `=DeclRefExpr // CHECK-NEXT: . | | `=CompoundStmt // CHECK-NEXT: . | | `=ReturnStmt // CHECK-NEXT: . | | `=IntegerLiteral // CHECK-NEXT: . | |=TemplateTypeParmDecl: T // CHECK-NEXT: . | | `=TemplateTypeParmType: T // CHECK-NEXT: . | `=NonTypeTemplateParmDecl: I // CHECK-NEXT: . | `=BuiltinType: int template<typename T, int I> int TplFnTI(T (&t)[I]) { return 3; } // CHECK-NEXT: . |=FunctionDecl: TplFnTI // CHECK-NEXT: . | |=BuiltinType: float // CHECK-NEXT: . | |=IntegerLiteral // CHECK-NEXT: . | |=FunctionProtoType: int (float (&)[5]) // CHECK-NEXT: . | | |=BuiltinType: int // CHECK-NEXT: . | | `=ParmVarDecl: t // CHECK-NEXT: . | | `=LValueReferenceType: float (&)[5] // CHECK-NEXT: . | | `=ConstantArrayType: float [5] // CHECK-NEXT: . | | |=BuiltinType: float // CHECK-NEXT: . | | `=IntegerLiteral // CHECK-NEXT: . | `=CompoundStmt // CHECK-NEXT: . | `=ReturnStmt // CHECK-NEXT: . | `=IntegerLiteral template<> int TplFnTI<float, 5>(float (&t)[5]) { return 4; } // CHECK-NEXT: . |=VarDecl: tpl_fn_var1 // CHECK-NEXT: . | |=BuiltinType: int // CHECK-NEXT: . | `=CallExpr // CHECK-NEXT: . | |=ImplicitCastExpr // CHECK-NEXT: . | | `=DeclRefExpr // CHECK-NEXT: . | | `=BuiltinType: int // CHECK-NEXT: . | `=IntegerLiteral int tpl_fn_var1 = TplFn<int>(10); // CHECK-NEXT: . |=VarDecl: tpl_fn_var2 // CHECK-NEXT: . | |=BuiltinType: int // CHECK-NEXT: . | `=CallExpr // CHECK-NEXT: . | |=ImplicitCastExpr // CHECK-NEXT: . | | `=DeclRefExpr // CHECK-NEXT: . | | `=BuiltinType: char // CHECK-NEXT: . | `=CharacterLiteral int tpl_fn_var2 = TplFn<char>('a'); // CHECK-NEXT: . |=VarDecl: tpl_fn_var3 // CHECK-NEXT: . | |=BuiltinType: int // CHECK-NEXT: . | `=CallExpr // CHECK-NEXT: . | |=ImplicitCastExpr // CHECK-NEXT: . | | `=DeclRefExpr // CHECK-NEXT: . | `=CharacterLiteral int tpl_fn_var3 = TplFn('b'); // CHECK-NEXT: . |=VarDecl: tpl_fn_var4_arg // CHECK-NEXT: . | `=ConstantArrayType: char [6] // CHECK-NEXT: . | |=BuiltinType: char // CHECK-NEXT: . | `=IntegerLiteral char tpl_fn_var4_arg[6]; // CHECK-NEXT: . |=VarDecl: tpl_fn_var4 // CHECK-NEXT: . | |=BuiltinType: int // CHECK-NEXT: . | `=CallExpr // CHECK-NEXT: . | |=ImplicitCastExpr // CHECK-NEXT: . | | `=DeclRefExpr // CHECK-NEXT: . | | |=BuiltinType: char // CHECK-NEXT: . | | `=IntegerLiteral // CHECK-NEXT: . | `=DeclRefExpr int tpl_fn_var4 = TplFnTI<char, 6>(tpl_fn_var4_arg); // CHECK-NEXT: . |=VarDecl: tpl_fn_var5_arg // CHECK-NEXT: . | `=ConstantArrayType: float [5] // CHECK-NEXT: . | |=BuiltinType: float // CHECK-NEXT: . | `=IntegerLiteral float tpl_fn_var5_arg[5]; // CHECK-NEXT: . |=VarDecl: tpl_fn_var5 // CHECK-NEXT: . | |=BuiltinType: int // CHECK-NEXT: . | `=CallExpr // CHECK-NEXT: . | |=ImplicitCastExpr // CHECK-NEXT: . | | `=DeclRefExpr // CHECK-NEXT: . | `=DeclRefExpr int tpl_fn_var5 = TplFnTI(tpl_fn_var5_arg); // CHECK-NEXT: . |=NamespaceDecl: ns1 namespace ns1 { // CHECK-NEXT: . | `=CXXRecordDecl: ns1::Class1 class Class1; } // namespace ns1 // CHECK-NEXT: . |=FunctionDecl: ElaborationTest // CHECK-NEXT: . | `=FunctionProtoType // CHECK-NEXT: . | |=BuiltinType: void void ElaborationTest( // CHECK-NEXT: . | |=ParmVarDecl: // CHECK-NEXT: . | | `=ElaboratedType: class ns1::Class1 // CHECK-NEXT: . | | `=RecordType: ns1::Class1 class ns1::Class1, // CHECK-NEXT: . | |=ParmVarDecl: // CHECK-NEXT: . | | `=ElaboratedType: ns1::Class1 // CHECK-NEXT: . | | `=RecordType: ns1::Class1 ns1::Class1, // CHECK-NEXT: . | |=ParmVarDecl: // CHECK-NEXT: . | | `=ElaboratedType: class FooClass // CHECK-NEXT: . | | `=RecordType: FooClass class FooClass, // CHECK-NEXT: . | `=ParmVarDecl: // CHECK-NEXT: . | `=RecordType: FooClass FooClass); //////////////////////////////////////////////////////////// // Tests friend classes (templated and not) // CHECK-NEXT: . |=CXXRecordDecl: FriendClass class FriendClass { // CHECK-NEXT: . | |=AccessSpecDecl public: // CHECK-NEXT: . | |=CXXRecordDecl: FriendClass::NestedFriendClass class NestedFriendClass {}; // CHECK-NEXT: . | `=ClassTemplateDecl: FriendClass::NestedTemplateFriendClass // CHECK-NEXT: . | |=CXXRecordDecl: FriendClass::NestedTemplateFriendClass // CHECK-NEXT: . | `=TemplateTypeParmDecl: T // CHECK-NEXT: . | `=TemplateTypeParmType: T template<typename T> class NestedTemplateFriendClass {}; }; // CHECK-NEXT: . |=ClassTemplateDecl: TemplateFriendClass // CHECK-NEXT: . | |=CXXRecordDecl: TemplateFriendClass template<typename T> class TemplateFriendClass { // CHECK-NEXT: . | | |=AccessSpecDecl public: // CHECK-NEXT: . | | |=CXXRecordDecl: TemplateFriendClass::NestedFriendClass class NestedFriendClass {}; // CHECK-NEXT: . | | `=ClassTemplateDecl: TemplateFriendClass::NestedTemplateFriendClass // CHECK-NEXT: . | | |=CXXRecordDecl: TemplateFriendClass::NestedTemplateFriendClass // CHECK-NEXT: . | | `=TemplateTypeParmDecl: U // CHECK-NEXT: . | | `=TemplateTypeParmType: U template<typename U> class NestedTemplateFriendClass {}; // CHECK-NEXT: . | `=TemplateTypeParmDecl: T // CHECK-NEXT: . | `=TemplateTypeParmType: T }; // CHECK-NEXT: . |=CXXRecordDecl: BefriendingClass class BefriendingClass { // CHECK-NEXT: . | |=FriendDecl // CHECK-NEXT: . | | `=ElaboratedType: class FriendClass // CHECK-NEXT: . | | `=RecordType: FriendClass friend class FriendClass; // CHECK-NEXT: . | |=FriendDecl // CHECK-NEXT: . | | `=ClassTemplateDecl: TemplateFriendClass // CHECK-NEXT: . | | |=CXXRecordDecl: TemplateFriendClass // CHECK-NEXT: . | | `=TemplateTypeParmDecl: T // CHECK-NEXT: . | | `=TemplateTypeParmType: T template<typename T> friend class TemplateFriendClass; // CHECK-NEXT: . | |=FriendDecl // CHECK-NEXT: . | | `=ElaboratedType: class TemplateFriendClass<int> // CHECK-NEXT: . | | `=TemplateSpecializationType: TemplateFriendClass<int> // CHECK-NEXT: . | | `=BuiltinType: int friend class TemplateFriendClass<int>; // CHECK-NEXT: . | |=FriendDecl // CHECK-NEXT: . | | `=ElaboratedType: class FriendClass::NestedFriendClass // CHECK-NEXT: . | | |=RecordType: FriendClass // CHECK-NEXT: . | | `=RecordType: FriendClass::NestedFriendClass friend class FriendClass::NestedFriendClass; // CHECK-NEXT: . | `=FriendDecl // CHECK-NEXT: . | `=ClassTemplateDecl: FriendClass::NestedTemplateFriendClass // CHECK-NEXT: . | |=CXXRecordDecl: FriendClass::NestedTemplateFriendClass // CHECK-NEXT: . | | `=RecordType: FriendClass // CHECK-NEXT: . | `=TemplateTypeParmDecl: T // CHECK-NEXT: . | `=TemplateTypeParmType: T template<typename T> friend class FriendClass::NestedTemplateFriendClass; }; // CHECK-NEXT: . |=ClassTemplateDecl: TemplateBefriendingClass // CHECK-NEXT: . | |=CXXRecordDecl: TemplateBefriendingClass template<typename T> class TemplateBefriendingClass { // CHECK-NEXT: . | | |=FriendDecl // CHECK-NEXT: . | | | `=DependentNameType: class TemplateFriendClass<T>::NestedFriendClass // CHECK-NEXT: . | | | `=TemplateSpecializationType: TemplateFriendClass<T> // CHECK-NEXT: . | | | `=TemplateTypeParmType: T friend class TemplateFriendClass<T>::NestedFriendClass; // CHECK-NEXT: . | | `=FriendDecl // CHECK-NEXT: . | | `=ClassTemplateDecl: TemplateFriendClass::NestedTemplateFriendClass // CHECK-NEXT: . | | |=CXXRecordDecl: TemplateFriendClass::NestedTemplateFriendClass // CHECK-NEXT: . | | | `=TemplateSpecializationType: TemplateFriendClass<T> // CHECK-NEXT: . | | | `=TemplateTypeParmType: T // CHECK-NEXT: . | | `=TemplateTypeParmDecl: U // CHECK-NEXT: . | | `=TemplateTypeParmType: U template<typename U> friend class TemplateFriendClass<T>::NestedTemplateFriendClass; // CHECK-NEXT: . | `=TemplateTypeParmDecl: T // CHECK-NEXT: . | `=TemplateTypeParmType: T }; //////////////////////////////////////////////////////////// // Tests unresolved constructors: function-looking things involving tpl args // CHECK-NEXT: . |=ClassTemplateDecl: UnresolvedCtorHelper // CHECK-NEXT: . | |=CXXRecordDecl: UnresolvedCtorHelper // CHECK-NEXT: . | `=TemplateTypeParmDecl: A // CHECK-NEXT: . | `=TemplateTypeParmType: A template<typename A> struct UnresolvedCtorHelper { }; template <typename T, template<typename A> class U> // CHECK-NEXT: . `=FunctionTemplateDecl: TestUnresolvedCtor // CHECK-NEXT: . |=FunctionDecl: TestUnresolvedCtor // CHECK-NEXT: . | |=FunctionProtoType: void () // CHECK-NEXT: . | | `=BuiltinType: void // CHECK-NEXT: . | `=CompoundStmt void TestUnresolvedCtor() { // CHECK-NEXT: . | |=DeclStmt // CHECK-NEXT: . | | `=VarDecl: x // CHECK-NEXT: . | | |=BuiltinType: int // CHECK-NEXT: . | | `=CXXUnresolvedConstructExpr // CHECK-NEXT: . | | `=TemplateTypeParmType: T int x = T(); // CHECK-NEXT: . | |=BinaryOperator // CHECK-NEXT: . | | |=DeclRefExpr // CHECK-NEXT: . | | `=CXXUnresolvedConstructExpr // CHECK-NEXT: . | | `=TemplateSpecializationType: U<int> // CHECK-NEXT: . | | `=BuiltinType: int x = U<int>(); // CHECK-NEXT: . | |=BinaryOperator // CHECK-NEXT: . | | |=DeclRefExpr // CHECK-NEXT: . | | `=CXXUnresolvedConstructExpr // CHECK-NEXT: . | | `=TemplateSpecializationType: U<T> // CHECK-NEXT: . | | `=TemplateTypeParmType: T x = U<T>(); // CHECK-NEXT: . | `=BinaryOperator // CHECK-NEXT: . | |=DeclRefExpr // CHECK-NEXT: . | `=CXXUnresolvedConstructExpr // CHECK-NEXT: . | `=TemplateSpecializationType: UnresolvedCtorHelper<T> // CHECK-NEXT: . | `=TemplateTypeParmType: T x = UnresolvedCtorHelper<T>(); // CHECK-NEXT: . |=TemplateTypeParmDecl: T // CHECK-NEXT: . | `=TemplateTypeParmType: T // CHECK-NEXT: . `=TemplateTemplateParmDecl: U // CHECK-NEXT: . `=TemplateTypeParmDecl: A // CHECK-NEXT: . `=TemplateTypeParmType: A } // CHECK-NEXT: EOF _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
