Richard Thomson Senior Software Engineer

Richard Thomson Senior Software Engineer Fusion-io @LegalizeAdulthd http://LegalizeAdulthood.wordpress.com [email protected]         ...
Author: Vivien Byrd
0 downloads 0 Views 989KB Size
Richard Thomson Senior Software Engineer Fusion-io @LegalizeAdulthd http://LegalizeAdulthood.wordpress.com [email protected]



     

    

    

Statement of the problem Getting started with clang Examining remove-cstr-calls Bootstrapping remove-void-args Understanding clang's AST The compilation database Exploring matched function definitions Exploring a realistic source file Exploring matched function declarations Replacing matched function declarations and definitions Handling typedef statements Member functions Fields Uninitialized variable Initialized variable Constructors Cast operator expression

Outline 2

Dearth of refactoring tools for C/C++  Existing tools tightly coupled to IDEs  C/C++ code bases are often old  Old code bases need refactoring the most!  Tool adoption requires: 

 Easily invoked from workflow

 Accurate  Never produce incorrect code

The Problem 3



Visual Studio add-ons  Visual Assist/X by Whole Tomato  CodeRush by DevExpress



CLI  clang-modernize  remove-cstr-calls  clang-tidy



Eclipse  CDT



Email me about others! [email protected]

Some Existing Refactoring Tools 4

// dusty_deck.cpp int foo(void) { return 0; } void bar(void) { } struct gronk { gronk(void) { } ~gronk(void) { } void foo(void) { } void (*f)(void); void (gronk::*p)(void); };

The Problem 5

// dusty_deck.cpp Someone's been int foo(void) { Ugh. return 0; } bringing their dusty old C style void bar(void) {habits } into our C++ code. struct gronk { Let's get rid of these! gronk(void) { They } serve no purpose in C++. ~gronk(void) { } void foo(void) { } };

The Problem 6

void (*f)(void); void (gronk::*p)(void); typedef void (fn)(void); typedef void (gronk::*pm)(void); void ff(void (*f)(void)) { } f = (void (*)(void)) 0; f = static_cast(0); f = reinterpret_cast(0); extern void (*)(void) get_fn_ptr(); // you can think of more...

Expressions Also Participate 7

     

Download LLVM 3.4 Download Clang 3.4 Download Clang "Extra Tools" 3.4 Unpack source into correct location Configure build with Cmake Build:    

293 projects in VS 90+ minutes of 8 cores @ 100% CPU later... We get a 9 GB build tree Srsly?

Getting Started With Clang 8

Yes, for now.  Windows package doesn't include the necessary libraries or headers.  All packages are missing some useful tools.  In Clang 3.4, some useful tools require libedit as a prerequisite. 

Srsly? 9

libedit requirement eliminated.  Windows package build can be enhanced.  Additional tools added to package (patch forthcoming)  Goal is to have prebuilt binary packages for most environments to lower the bar for refactoring tool development. 

Will Be Better in Clang 3.5 10

We need to remove some (void) stuff  remove-cstr-calls removes redundant calls to c_str() 



We can use this tool as a starting point

Modify an Existing Tool to Learn 11

// // // // // // // //

remove-cstr-calls ... Where is a CMake build directory in which a file named compile_commands.json exists. ... specify the paths of files in the Cmake source tree. This path is looked up in the compile command database.

// this: void f1(const std::string &s) { f1(s.c_str()); } // becomes this: void f1(const std::string &s) { f1(s); }

remove-cstr-calls 12

// // // // // // // //

remove-cstr-calls ... Where is a CMake build directory in which a file named compile_commands.json exists. ... specify the paths of files in the Cmake source tree. This path is looked up in the compile command database.

// this: void f1(const std::string &s) { f1(s.c_str()); } // becomes this: void f1(const std::string &s) { f1(s); }

remove-cstr-calls 13

// // // // // // // //

remove-cstr-calls ... Where is a CMake build directory in which a file named compile_commands.json exists. ... specify the paths of files in the Cmake source tree. This path is looked up in the compile command database.

// this: void f1(const std::string &s) { f1(s.c_str()); } // becomes this: void f1(const std::string &s) { f1(s); }

remove-cstr-calls 14

cl::opt BuildPath( cl::Positional, cl::desc(""));

cl::list SourcePaths( cl::Positional, cl::desc(" [... ]"), cl::OneOrMore);

Setting Up Command-Line Args 15

cl::opt BuildPath( cl::Positional, cl::desc("")); LLVM Support library provides command-line cl::list argument SourcePaths( classes in cl namespace cl::Positional,

cl::desc(" [... ]"), cl::OneOrMore);

Setting Up Command-Line Args 16

cl::opt BuildPath( cl::Positional, cl::desc(""));

cl::list cl::Positional, cl::desc(" cl::OneOrMore);

SourcePaths( The first positional argument stored in a string gives us [... the build]"), path.

Setting Up Command-Line Args 17

cl::opt BuildPath( The second positional argument stored in a list of cl::Positional, string gives us one or more cl::desc("")); source files to refactor

cl::list SourcePaths( cl::Positional, cl::desc(" [... ]"), cl::OneOrMore);

Setting Up Command-Line Args 18

int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::OwningPtr Compilations( tooling::FixedCompilationDatabase::loadFromCommandLine( argc, argv)); cl::ParseCommandLineOptions(argc, argv); if (!Compilations) { std::string ErrorMessage; Compilations.reset( CompilationDatabase::loadFromDirectory( BuildPath, ErrorMessage)); if (!Compilations) llvm::report_fatal_error(ErrorMessage); } tooling::RefactoringTool Tool(*Compilations, SourcePaths);

main(): Startup 19

int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::OwningPtr Compilations( tooling::FixedCompilationDatabase::loadFromCommandLine( argc, argv)); cl::ParseCommandLineOptions(argc, argv);library utility LLVM Support if (!Compilations) { for printing out a stack trace std::string ErrorMessage; diagnostic when an Compilations.reset( unhandled signal(2) occurs. CompilationDatabase::loadFromDirectory( BuildPath, ErrorMessage)); if (!Compilations) llvm::report_fatal_error(ErrorMessage); } tooling::RefactoringTool Tool(*Compilations, SourcePaths);

main(): Startup 20

int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::OwningPtr Compilations( tooling::FixedCompilationDatabase::loadFromCommandLine( argc, argv)); cl::ParseCommandLineOptions(argc, argv); if (!Compilations) { std::string ErrorMessage; Compilations.reset( Let's us build a compilation CompilationDatabase::loadFromDirectory( database directly from the BuildPath, ErrorMessage)); command-line. if (!Compilations) llvm::report_fatal_error(ErrorMessage); More on the compilation } tooling::RefactoringTool Tool(*Compilations, database later! SourcePaths);

main(): Startup 21

int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::OwningPtr Compilations( tooling::FixedCompilationDatabase::loadFromCommandLine( argc, argv)); cl::ParseCommandLineOptions(argc, argv); if (!Compilations) { std::string ErrorMessage; Compilations.reset( Get the command-line options CompilationDatabase::loadFromDirectory( parsed. BuildPath, ErrorMessage)); if (!Compilations) llvm::report_fatal_error(ErrorMessage); } tooling::RefactoringTool Tool(*Compilations, SourcePaths);

main(): Startup 22

int main(int argc, const char **argv) { Locate the compilation database llvm::sys::PrintStackTraceOnErrorSignal(); using the given directory. llvm::OwningPtr Compilations( tooling::FixedCompilationDatabase::loadFromCommandLine( argc, argv)); cl::ParseCommandLineOptions(argc, argv); if (!Compilations) { std::string ErrorMessage; Compilations.reset( CompilationDatabase::loadFromDirectory( BuildPath, ErrorMessage)); if (!Compilations) llvm::report_fatal_error(ErrorMessage); } tooling::RefactoringTool Tool(*Compilations, SourcePaths);

main(): Startup 23

int main(int argc, const char **argv) { No, really, we need this thing to llvm::sys::PrintStackTraceOnErrorSignal(); continue! llvm::OwningPtr Compilations( tooling::FixedCompilationDatabase::loadFromCommandLine( argc, argv)); cl::ParseCommandLineOptions(argc, argv); if (!Compilations) { std::string ErrorMessage; Compilations.reset( CompilationDatabase::loadFromDirectory( BuildPath, ErrorMessage)); if (!Compilations) llvm::report_fatal_error(ErrorMessage); } tooling::RefactoringTool Tool(*Compilations, SourcePaths);

main(): Startup 24

int main(int argc, const char **argv) { Get our refactoring tool instance created. llvm::sys::PrintStackTraceOnErrorSignal(); llvm::OwningPtr Compilations( RefactoringTool is a ClangTool that knows how to parse tooling::FixedCompilationDatabase::loadFromCommandLine( sourceargc, files into an AST, match nodes in the AST and argv)); create a list of source file text replacements. cl::ParseCommandLineOptions(argc, argv); if (!Compilations) { We std::string build it from the ErrorMessage; compilation database and the Compilations.reset( source files to refactor. CompilationDatabase::loadFromDirectory( BuildPath, ErrorMessage)); if (!Compilations) llvm::report_fatal_error(ErrorMessage); } tooling::RefactoringTool Tool(*Compilations, SourcePaths);

main(): Startup 25

ast_matchers::MatchFinder Finder; FixCStrCall Callback(&Tool.getReplacements()); Finder.addMatcher(/* ... */); Finder.addMatcher(/* ... */); return Tool.runAndSave( newFrontendActionFactory(&Finder));

main(): AST Matching 26

ast_matchers::MatchFinder Finder; FixCStrCall Callback(&Tool.getReplacements()); Finder.addMatcher(/* ... */); Finder.addMatcher(/* ... */); return Tool.runAndSave( newFrontendActionFactory(&Finder)); Create an instance of MatchFinder. MatchFinder provides an implementation of ASTConsumer to consume the AST created by the compiler.

The AST is matched in pre-order traversal, applying matchers in the order in which they are added to the finder.

main(): AST Matching 27

ast_matchers::MatchFinder Finder; FixCStrCall Callback(&Tool.getReplacements()); Finder.addMatcher(/* ... */); Finder.addMatcher(/* ... */); return Tool.runAndSave( newFrontendActionFactory(&Finder)); Create an instance of our refactoring code. We pass it the address of the tool's source file replacements list so it can add replacements as it processes matches.

main(): AST Matching 28

ast_matchers::MatchFinder Finder; FixCStrCall Callback(&Tool.getReplacements()); Finder.addMatcher(/* ... */); Finder.addMatcher(/* ... */); return Tool.runAndSave( newFrontendActionFactory(&Finder)); Add AST matchers to the MatchFinder. Matchers are built up using a "builder" style interface. This lets us express matchers using a fluent API.

main(): AST Matching 29

ast_matchers::MatchFinder Finder; FixCStrCall Callback(&Tool.getReplacements()); Finder.addMatcher(/* ... */); Finder.addMatcher(/* ... */); return Tool.runAndSave( newFrontendActionFactory(&Finder));

Connect the MatchFinder to the front end of the compiler and pass this front end to the RefactoringTool to process source files, match AST nodes, build replacement lists and then modify the source files from the replacement lists.

main(): AST Matching 30

Finder.addMatcher( constructExpr( hasDeclaration( methodDecl(hasName(StringConstructor))), argumentCountIs(2), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), on(id("arg", expr()))))), hasArgument( 1, defaultArgExpr())), &Callback);

1st Matcher std::string(s.c_str()) 31

Finder.addMatcher( constructExpr( hasDeclaration( methodDecl(hasName(StringConstructor))), argumentCountIs(2), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), Matches on(id("arg", constructor call expr()))))), expressions, hasArgument( including implicit constructor expressions. 1, defaultArgExpr())), &Callback);

1st Matcher std::string(s.c_str()) 32

Finder.addMatcher( constructExpr( hasDeclaration( methodDecl(hasName(StringConstructor))), argumentCountIs(2), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), expr()))))), Matches on(id("arg", a method declaration whose name ishasArgument( the name of the c'tor for std::string. 1, defaultArgExpr())), &Callback);

1st Matcher std::string(s.c_str()) 33

Finder.addMatcher( constructExpr( hasDeclaration( methodDecl(hasName(StringConstructor))), argumentCountIs(2), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), expr()))))), The c'toron(id("arg", call takes two arguments. hasArgument( 1, defaultArgExpr())), &Callback);

1st Matcher std::string(s.c_str()) 34

Finder.addMatcher( The first argument is a call to the constructExpr( std::string::c_str() method. hasDeclaration( methodDecl(hasName(StringConstructor))), argumentCountIs(2), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), on(id("arg", expr()))))), hasArgument( 1, defaultArgExpr())), &Callback);

1st Matcher std::string(s.c_str()) 35

Finder.addMatcher( Bind to a member function call expression constructExpr( matching the list of passed matchers. hasDeclaration( methodDecl(hasName(StringConstructor))), argumentCountIs(2), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), on(id("arg", expr()))))), hasArgument( 1, defaultArgExpr())), &Callback);

1st Matcher std::string(s.c_str()) 36

Finder.addMatcher( Bind the member function call expression to "call", constructExpr( so we can use this as the text to be replaced. hasDeclaration( methodDecl(hasName(StringConstructor))), argumentCountIs(2), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), on(id("arg", expr()))))), hasArgument( 1, defaultArgExpr())), &Callback);

1st Matcher std::string(s.c_str()) 37

Finder.addMatcher( Bind the member expression to "member", so we can constructExpr( determine if the member is invoked by value or by pointer. hasDeclaration( methodDecl(hasName(StringConstructor))), argumentCountIs(2), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), on(id("arg", expr()))))), hasArgument( 1, defaultArgExpr())), &Callback);

1st Matcher std::string(s.c_str()) 38

Finder.addMatcher( The method being called is a declaration matching the constructExpr( name for std::string::c_str() hasDeclaration( methodDecl(hasName(StringConstructor))), argumentCountIs(2), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), on(id("arg", expr()))))), hasArgument( 1, defaultArgExpr())), &Callback);

1st Matcher std::string(s.c_str()) 39

Finder.addMatcher( c_str() is invoked on some constructExpr( expression, which we bind to "arg". hasDeclaration( methodDecl(hasName(StringConstructor))), argumentCountIs(2), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), on(id("arg", expr()))))), hasArgument( 1, defaultArgExpr())), &Callback);

1st Matcher std::string(s.c_str()) 40

Finder.addMatcher( Matches if the callee matches the constructExpr( inner matcher. hasDeclaration( methodDecl(hasName(StringConstructor))), argumentCountIs(2), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), on(id("arg", expr()))))), hasArgument( 1, defaultArgExpr())), &Callback);

1st Matcher std::string(s.c_str()) 41

Finder.addMatcher( constructExpr( hasDeclaration( methodDecl(hasName(StringConstructor))), The second argument is a default argument. argumentCountIs(2), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), on(id("arg", expr()))))), hasArgument( 1, defaultArgExpr())), &Callback);

1st Matcher std::string(s.c_str()) 42

Finder.addMatcher( constructExpr( hasDeclaration( methodDecl(hasName(StringConstructor))), argumentCountIs(2), hasArgument( 0, the matcher to our refactoring callback. Connect id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), on(id("arg", expr()))))), hasArgument( 1, defaultArgExpr())), &Callback);

1st Matcher std::string(s.c_str()) 43

Finder.addMatcher( constructExpr( hasDeclaration(methodDecl(anyOf( hasName("::llvm::StringRef::StringRef"), hasName("::llvm::Twine::Twine")))), argumentCountIs(1), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), on(id("arg", expr())))))), &Callback);

2nd Matcher LLVM String Classes 44

Finder.addMatcher( constructExpr( hasDeclaration(methodDecl(anyOf( hasName("::llvm::StringRef::StringRef"), hasName("::llvm::Twine::Twine")))), argumentCountIs(1), hasArgument( Matches if any of the child matchers match. 0, id("call", memberCallExpr( callee(id("member", memberExpr())), callee(methodDecl(hasName(StringCStrMethod))), on(id("arg", expr())))))), &Callback);

2nd Matcher LLVM String Classes 45

Finder.addMatcher( constructExpr( hasDeclaration(methodDecl(anyOf( hasName("::llvm::StringRef::StringRef"), hasName("::llvm::Twine::Twine")))), argumentCountIs(1), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), LLVM StringRef and Twine classes should callee(methodDecl(hasName(StringCStrMethod))), be constructed from std::string directly on(id("arg", expr())))))), instead of from std:string::c_str(). &Callback);

2nd Matcher LLVM String Classes 46

Finder.addMatcher( constructExpr( hasDeclaration(methodDecl(anyOf( hasName("::llvm::StringRef::StringRef"), hasName("::llvm::Twine::Twine")))), argumentCountIs(1), hasArgument( 0, id("call", memberCallExpr( callee(id("member", memberExpr())), These c'tors take a single argument. callee(methodDecl(hasName(StringCStrMethod))), on(id("arg", expr())))))), &Callback);

2nd Matcher LLVM String Classes 47

const char *StringConstructor = "::std::basic_string::basic_string"; const char *StringCStrMethod = "::std::basic_string::c_str";

std::string Method Names 48

const char *StringConstructor = "::std::basic_string::basic_string"; const char *StringCStrMethod The =real name of std::string. "::std::basic_string::c_str";

std::string Method Names 49

const char *StringConstructor = "::std::basic_string::basic_string"; const char *StringCStrMethod The =name of the constructor. "::std::basic_string::c_str";

std::string Method Names 50

const char *StringConstructor = "::std::basic_string::basic_string"; const char *StringCStrMethod The =name of the c_str method. "::std::basic_string::c_str";

std::string Method Names 51

Copy llvm/tools/clang/tools/extra/remove-cstrcalls directory to extra/remove-void-args 2. Rename RemoveCStrCalls.cpp to RemoveVoidArgs.cpp 3. Edit remove-void-args/CMakeLists.txt: 1.

1. 2.

Change remove-cstr-calls to remove-void-args Change RemoveCStrCalls.cpp to RemoveVoidArgs.cpp

Edit extra/CMakeLists.txt and add the line add_subdirectory(remove-void-args) 5. Test build 4.

Bootstrapping an LLVM Tree Build 52

// test.cpp int foo(void) { return 0; }

int bar() { return 0; } int feezle(int i) { return 0; }

Some Simple Test Cases 53

// test.cpp int foo(void) { return 0; }

Our item of interest.

int bar() { return 0; } int feezle(int i) { return 0; }

Some Simple Test Cases 54

// test.cpp int foo(void) { return 0; }

A related item of interest.

int bar() { return 0; } int feezle(int i) { return 0; }

Some Simple Test Cases 55

// test.cpp int foo(void) { return 0; }

An uninteresting item.

int bar() { return 0; } int feezle(int i) { return 0; }

Some Simple Test Cases 56

> clang -Xclang -ast-dump -fsyntax-only test.cpp TranslationUnitDecl 0x469850 |-TypedefDecl 0x469b40 __builtin_va_list 'char *' |-CXXRecordDecl 0x469b70 class type_info |-FunctionDecl 0x469c60 foo 'int (void)' | `-CompoundStmt 0x469d00 | `-ReturnStmt 0x469cf0 | `-IntegerLiteral 0x469cd0 'int' 0 |-FunctionDecl 0x469d40 bar 'int (void)' | `-CompoundStmt 0x469de0 | `-ReturnStmt 0x469dd0 | `-IntegerLiteral 0x469db0 'int' 0 `-FunctionDecl 0x469e90 feezle 'int (int)' |-ParmVarDecl 0x469e10 i 'int' `-CompoundStmt 0x469f38 `-ReturnStmt 0x469f28 `-IntegerLiteral 0x469f08 'int' 0

Dumping the AST 57

> clang -Xclang -ast-dump -fsyntax-only test.cpp TranslationUnitDecl 0x469850 |-TypedefDecl 0x469b40 __builtin_va_list 'char *' |-CXXRecordDecl 0x469b70 class type_info |-FunctionDecl 0x469c60 foo 'int (void)' | `-CompoundStmt 0x469d00 You can dump the AST from the | `-ReturnStmt 0x469cf0 | `-IntegerLiteral 0x469cd0command 'int' line! 0That is so cool! |-FunctionDecl 0x469d40 bar 'int (void)' | `-CompoundStmt 0x469de0 ...and col:12> it even works on Windows! | `-ReturnStmt 0x469dd0 clang -Xclang -ast-dump -fsyntax-only test.cpp TranslationUnitDecl 0x469850 |-TypedefDecl 0x469b40 __builtin_va_list 'char *' |-CXXRecordDecl 0x469b70 class type_info |-FunctionDecl 0x469c60 foo 'int (void)' | `-CompoundStmt 0x469d00 The mother of all nodes is a | `-ReturnStmt 0x469cf0 | `-IntegerLiteral 0x469cd0translation 'int' unit declaration. 0 |-FunctionDecl 0x469d40 bar 'int (void)' | `-CompoundStmt 0x469de0 | `-ReturnStmt 0x469dd0 | `-IntegerLiteral 0x469db0 'int' 0 `-FunctionDecl 0x469e90 feezle 'int (int)' |-ParmVarDecl 0x469e10 i 'int' `-CompoundStmt 0x469f38 `-ReturnStmt 0x469f28 `-IntegerLiteral 0x469f08 'int' 0

Dumping the AST 59

> clang -Xclang -ast-dump -fsyntax-only test.cpp TranslationUnitDecl 0x469850 |-TypedefDecl 0x469b40 __builtin_va_list 'char *' |-CXXRecordDecl 0x469b70 class type_info |-FunctionDecl 0x469c60 foo 'int (void)' | `-CompoundStmt 0x469d00 | `-ReturnStmt 0x469cf0 | `-IntegerLiteral 0x469cd0 'int' 0 |-FunctionDecl 0x469d40 bar 'int (void)' | `-CompoundStmt 0x469de0 | `-ReturnStmt 0x469dd0 | `-IntegerLiteral 0x469db0 'int' 0 `-FunctionDecl 0x469e90 feezle 'int (int)' |-ParmVarDecl 0x469e10 i 'int' `-CompoundStmt 0x469f38 Functions appear as a FunctionDecl `-ReturnStmt 0x469f28 `-IntegerLiteral 0x469f08 'int'by 0 a CompoundStmt for node, followed

the function body. This one is for int foo(void)

Dumping the AST 60

> clang -Xclang -ast-dump -fsyntax-only test.cpp TranslationUnitDecl 0x469850 |-TypedefDecl 0x469b40 __builtin_va_list 'char *' |-CXXRecordDecl 0x469b70 class type_info |-FunctionDecl 0x469c60 foo 'int (void)' | `-CompoundStmt 0x469d00 | `-ReturnStmt 0x469cf0 | `-IntegerLiteral 0x469cd0 'int' 0 |-FunctionDecl 0x469d40 bar 'int (void)' | `-CompoundStmt 0x469de0 | `-ReturnStmt 0x469dd0 | `-IntegerLiteral 0x469db0 0 Every node'int' is associated with a source `-FunctionDecl 0x469e90 feezle 'int (int)' range spanning the entire source text |-ParmVarDecl 0x469e10 i 'int' parsed into the node. `-CompoundStmt 0x469f38 `-ReturnStmt 0x469f28 This source range is in test.cpp from `-IntegerLiteral 0x469f08 'int' 0

line 1, character 1 to line 3, character 1.

Dumping the AST 61

> clang -Xclang -ast-dump -fsyntax-only test.cpp TranslationUnitDecl 0x469850 |-TypedefDecl 0x469b40 __builtin_va_list 'char *' |-CXXRecordDecl 0x469b70 class type_info |-FunctionDecl 0x469c60 foo 'int (void)' | `-CompoundStmt 0x469d00 | `-ReturnStmt 0x469cf0 | `-IntegerLiteral 0x469cd0 'int' 0 |-FunctionDecl 0x469d40 bar 'int (void)' | `-CompoundStmt 0x469de0 | `-ReturnStmt 0x469dd0 | `-IntegerLiteral 0x469db0 'int' 0 `-FunctionDecl 0x469e90 feezle 'int (int)' |-ParmVarDecl 0x469e10 i 'int' `-CompoundStmt 0x469f38 The FunctionDecl node for `-ReturnStmt 0x469f28 `-IntegerLiteral 0x469f08 'int' 0 int bar()

Dumping the AST 62

> clang -Xclang -ast-dump -fsyntax-only test.cpp TranslationUnitDecl 0x469850 |-TypedefDecl 0x469b40 __builtin_va_list 'char *' |-CXXRecordDecl 0x469b70 class type_info |-FunctionDecl 0x469c60 foo 'int (void)' | `-CompoundStmt 0x469d00 | `-ReturnStmt 0x469cf0 | `-IntegerLiteral 0x469cd0 'int' 0 |-FunctionDecl 0x469d40 bar 'int (void)' | `-CompoundStmt 0x469de0 | `-ReturnStmt 0x469dd0 | `-IntegerLiteral 0x469db0 'int' 0 `-FunctionDecl 0x469e90 feezle 'int (int)' |-ParmVarDecl 0x469e10 i 'int' `-CompoundStmt 0x469f38 The FunctionDecl node for `-ReturnStmt 0x469f28 `-IntegerLiteral 0x469f08 'int' 0 int feezle(int)

Dumping the AST 63

> clang -Xclang -ast-dump -fsyntax-only test.cpp TranslationUnitDecl 0x469850 Both FunctionDecl nodes for foo |-TypedefDecl 0x469b40 __builtin_va_list 'char *' |-CXXRecordDecl col:7> class type_info and bar printed0x469b70 out the clang -Xclang -ast-dump -fsyntax-only test.cpp TranslationUnitDecl 0x469850 clang prints out a summary of the |-TypedefDecl 0x469b40 __builtin_va_list 'char *' |-CXXRecordDecl class type_info node after the 0x469b70 source location. |-FunctionDecl 0x469c60 foo 'int (void)' clang prints a summary of line:3:1> |When `-CompoundStmt 0x469d00 it prints

Suggest Documents