7 #include "llvm/Support/raw_ostream.h"
8 #include "llvm/System/Host.h"
9 #include "llvm/Config/config.h"
11 #include "clang/Frontend/DiagnosticOptions.h"
12 #include "clang/Frontend/TextDiagnosticPrinter.h"
14 #include "clang/Basic/LangOptions.h"
15 #include "clang/Basic/FileSystemOptions.h"
17 #include "clang/Index/TranslationUnit.h"
18 #include "clang/Basic/SourceManager.h"
19 #include "clang/Lex/HeaderSearch.h"
20 #include "clang/Basic/FileManager.h"
22 #include "clang/Frontend/HeaderSearchOptions.h"
23 #include "clang/Frontend/Utils.h"
25 #include "clang/Basic/TargetOptions.h"
26 #include "clang/Basic/TargetInfo.h"
28 #include "clang/Lex/Preprocessor.h"
29 #include "clang/Frontend/PreprocessorOptions.h"
30 #include "clang/Frontend/FrontendOptions.h"
32 #include "clang/Frontend/CompilerInvocation.h"
34 #include "clang/Basic/IdentifierTable.h"
35 #include "clang/Basic/Builtins.h"
37 #include "clang/AST/ASTContext.h"
38 #include "clang/AST/ASTConsumer.h"
39 #include "clang/Sema/Sema.h"
40 #include "clang/AST/DeclBase.h"
41 #include "clang/AST/Type.h"
42 #include "clang/AST/Decl.h"
43 #include "clang/Sema/Lookup.h"
44 #include "clang/Sema/Ownership.h"
45 #include "clang/AST/DeclGroup.h"
47 #include "clang/Parse/Parser.h"
49 #include "clang/Parse/ParseAST.h"
50 #include "clang/Basic/Version.h"
52 #include "llvm/Support/CommandLine.h"
55 #include "stringoper.h"
56 #include "commandlineopt.h"
58 using namespace clang;
61 class FindStates : public ASTConsumer
63 std::list<string> transitions;
64 std::list<string> events;
65 std::list<string> states;
66 std::string name_of_machine;
67 std::string name_of_start;
70 virtual void Initialize(ASTContext &ctx)//run after the AST is constructed
76 virtual void HandleTopLevelDecl(DeclGroupRef DGR)// traverse all top level declarations
80 std::string super_class, output;
81 llvm::raw_string_ostream x(output);
82 for (DeclGroupRef::iterator i = DGR.begin(), e = DGR.end(); i != e; ++i)
84 const Decl *decl = *i;
85 loc = decl->getLocation();
88 const NamedDecl *namedDecl = dyn_cast<NamedDecl>(decl);
89 //std::cout<<decl->getDeclKindName()<<"\n";
90 if (const TagDecl *tagDecl = dyn_cast<TagDecl>(decl))
92 if(tagDecl->isStruct() || tagDecl->isClass()) //is it a structure or class
94 const CXXRecordDecl *cRecDecl = dyn_cast<CXXRecordDecl>(decl);
97 line = cut_commentary(clean_spaces(get_line_of_code(x.str())));
101 if(name_of_machine == "")
103 find_name_of_machine(cRecDecl, line);
107 if(find_states(cRecDecl, line))
109 const DeclContext *declCont = tagDecl->castToDeclContext(tagDecl);
110 std::cout << "New state: " << namedDecl->getNameAsString() << "\n";
111 find_transitions(namedDecl->getNameAsString(), declCont);
117 if(const NamespaceDecl *namespaceDecl = dyn_cast<NamespaceDecl>(decl))
119 DeclContext *declCont = namespaceDecl->castToDeclContext(namespaceDecl);
120 //declCont->dumpDeclContext();
121 recursive_visit(declCont);
127 void recursive_visit(const DeclContext *declCont) //recursively visit all decls inside namespace
129 std::string line, output;
131 llvm::raw_string_ostream x(output);
132 for (DeclContext::decl_iterator i = declCont->decls_begin(), e = declCont->decls_end(); i != e; ++i)
134 const Decl *decl = *i;
135 const NamedDecl *namedDecl = dyn_cast<NamedDecl>(decl);
137 //std::cout<<"a "<<decl->getDeclKindName()<<"\n";
138 loc = decl->getLocation();
141 if (const TagDecl *tagDecl = dyn_cast<TagDecl>(decl))
143 if(tagDecl->isStruct() || tagDecl->isClass()) //is it a structure or class
145 const CXXRecordDecl *cRecDecl = dyn_cast<CXXRecordDecl>(decl);
147 line = cut_commentary(clean_spaces(get_line_of_code(x.str())));
151 if(name_of_machine == "")
153 find_name_of_machine(cRecDecl, line);
157 if(find_states(cRecDecl, line))
159 const DeclContext *declCont = tagDecl->castToDeclContext(tagDecl);
160 //states.push_back(namedDecl->getNameAsString());
161 std::cout << "New state: " << namedDecl->getNameAsString() << "\n";
162 find_transitions(namedDecl->getNameAsString(), declCont);
168 if(const NamespaceDecl *namespaceDecl = dyn_cast<NamespaceDecl>(decl))
170 DeclContext *declCont = namespaceDecl->castToDeclContext(namespaceDecl);
171 //declCont->dumpDeclContext();
172 recursive_visit(declCont);
177 bool find_states(const CXXRecordDecl *cRecDecl, std::string line)
179 std::string super_class = get_super_class(line), base;
180 if(cRecDecl->getNumBases()>1)
182 for(int i = 0; i<cRecDecl->getNumBases();i++ )
184 if(i!=cRecDecl->getNumBases()-1) base = get_first_base(super_class);
185 else base = super_class;
186 if(is_state(super_class))
188 //std::cout<<get_params(super_class);
189 states.push_back(get_params(super_class));
194 super_class = get_next_base(super_class);
201 if(is_state(super_class))
203 //std::cout<<get_params(super_class);
204 states.push_back(get_params(super_class));
211 void find_name_of_machine(const CXXRecordDecl *cRecDecl, std::string line)
213 std::string super_class = get_super_class(line), base, params;
216 if(cRecDecl->getNumBases()>1)
218 for(int i = 0; i<cRecDecl->getNumBases();i++ )
220 if(i!=cRecDecl->getNumBases()-1) base = get_first_base(super_class);
221 else base = super_class;
224 params = get_params(base);
225 pos = params.find(",");
226 name_of_machine = params.substr(0,pos);
227 name_of_start = params.substr(pos);
228 std::cout<<"Name of the state machine: "<<name_of_machine<<"\n";
229 std::cout<<"Name of the first state: "<<name_of_start<<"\n";
233 super_class = get_next_base(super_class);
239 if(is_machine(super_class))
241 //std::cout<<super_class;
242 params = get_params(super_class);
244 pos = params.find(",");
245 name_of_machine = cut_namespaces(params.substr(0,pos));
246 name_of_start = cut_namespaces(params.substr(pos+1));
247 std::cout<<"Name of the state machine:"<<name_of_machine<<"\n";
248 std::cout<<"Name of the first state:"<<name_of_start<<"\n";
253 void find_transitions (const std::string name_of_state,const DeclContext *declCont) // traverse all methods for finding declarations of transitions
255 std::string output, line, dest, params, base;
256 llvm::raw_string_ostream x(output);
259 for (DeclContext::decl_iterator i = declCont->decls_begin(), e = declCont->decls_end(); i != e; ++i)
261 const Decl *decl = *i;
263 if (const TypedefDecl *typeDecl = dyn_cast<TypedefDecl>(decl))
267 line = clean_spaces(cut_typedef(output));
268 num = count(output,'<');
274 line = get_inner_part(line);
277 for(int j = 0;j<num;j++)
279 if(j!=num-1) base = get_first_base(line);
281 if(is_transition(base))
283 dest = name_of_state;
284 params = get_params(base);
287 transitions.push_back(dest);
288 line = get_next_base(line);
292 line = get_next_base(line);
298 void save_to_file(std::string output)
300 std::string state, str, context, ctx;
301 int pos1, pos2, cnt, subs;
302 std::ofstream filestr(output.c_str());
303 std::cout<<output<<"\n";
304 filestr<<"digraph "<< name_of_machine<< " {\n";
305 context = name_of_machine;
306 for(list<string>::iterator i = states.begin();i!=states.end();i++)
309 cnt = count(state,',');
312 pos1 = state.find(",");
313 ctx = cut_namespaces(state.substr(pos1+1));
314 //std::cout<<name_of_machine.length();
315 if(ctx.compare(0,context.length(),context)==0)
317 filestr<<cut_namespaces(state.substr(0,pos1))<<";\n";
324 pos1 = state.find(",");
325 pos2 = state.rfind(",");
326 ctx = cut_namespaces(state.substr(pos1+1,pos2-pos1-1));
327 if(ctx.compare(0,context.length(),context))
329 filestr<<cut_namespaces(state.substr(0,pos1))<<";\n";
333 filestr<<name_of_start<<" [peripheries=2] ;\n";
335 while(!states.empty())
337 state = states.front();
338 filestr<<"subgraph cluster"<<subs<<" {\n";
339 pos1 = state.find(",");
340 pos2 = state.rfind(",");
341 context = cut_namespaces(state.substr(0,pos1));
342 filestr<<"label=\""<<context<<"\";\n";
343 filestr<<cut_namespaces(state.substr(pos2+1))<<" [peripheries=2] ;\n";
345 //std::cout<<states.size();
346 for(list<string>::iterator i = states.begin();i!=states.end();i++)
349 cnt = count(state,',');
350 //std::cout<<state<<"\n";
353 pos1 = state.find(",");
354 ctx = cut_namespaces(state.substr(pos1+1));
355 if(ctx.compare(0,context.length(),context)==0)
357 filestr<<cut_namespaces(state.substr(0,pos1))<<";\n";
364 pos1 = state.find(",");
365 pos2 = state.rfind(",");
366 ctx = cut_namespaces(state.substr(pos1+1,pos2-pos1-1));
367 if(ctx.compare(0,context.length(),context))
369 filestr<<cut_namespaces(state.substr(0,pos1))<<";\n";
376 for(list<string>::iterator i = transitions.begin();i!=transitions.end();i++)
379 pos1 = state.find(",");
380 filestr<<cut_namespaces(state.substr(0,pos1))<<"->";
381 pos2 = state.rfind(",");
382 filestr<<cut_namespaces(state.substr(pos2+1));
383 filestr<<"[label=\""<<cut_namespaces(state.substr(pos1+1,pos2-pos1-1))<<"\"];\n";
390 int main(int argc, char *argv[])
392 llvm::cl::ParseCommandLineOptions(argc, argv);
393 std::cout<<"Input file: "<<inputFilename<<"\n";
394 DiagnosticOptions diagnosticOptions;
395 TextDiagnosticPrinter *tdp = new TextDiagnosticPrinter(llvm::nulls(), diagnosticOptions);
396 llvm::IntrusiveRefCntPtr<DiagnosticIDs> dis(new DiagnosticIDs());
397 Diagnostic diag(dis,tdp);
398 FileSystemOptions fileSysOpt;
402 FileManager fm (fileSysOpt);
404 SourceManager sm ( diag, fm);
405 HeaderSearch *headers = new HeaderSearch(fm);
406 CompilerInvocation::setLangDefaults(lang, IK_ObjCXX);
408 HeaderSearchOptions hsopts;
409 hsopts.ResourceDir=LLVM_PREFIX "/lib/clang/" CLANG_VERSION_STRING;
410 for(int i = 0; i<includeFiles.size();i++)
412 hsopts.AddPath(includeFiles[i],
413 clang::frontend::Angled,
419 to.Triple = llvm::sys::getHostTriple();
420 TargetInfo *ti = TargetInfo::CreateTargetInfo(diag, to);
421 clang::ApplyHeaderSearchOptions(
426 Preprocessor pp(diag, lang, *ti, sm, *headers);
428 PreprocessorOptions ppio;
429 InitializePreprocessor(pp, ppio,hsopts,f);
430 const FileEntry *file = fm.getFile(inputFilename);
431 sm.createMainFileID(file);
432 IdentifierTable tab(lang);
434 Builtin::Context builtins(*ti);
436 ASTContext ctx(lang, sm, *ti, tab, sel, builtins,0);
437 tdp->BeginSourceFile(lang, &pp);
438 ParseAST(pp, &c, ctx, false, false);
439 tdp->EndSourceFile();
441 c.save_to_file(outputFile);