2 ////////////////////////////////////////////////////////////////////////////////////////
4 // This file is part of Boost Statechart Viewer.
6 // Boost Statechart Viewer is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
11 // Boost Statechart Viewer is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with Boost Statechart Viewer. If not, see <http://www.gnu.org/licenses/>.
19 ////////////////////////////////////////////////////////////////////////////////////////
21 //standard header files
25 #include "llvm/Support/raw_ostream.h"
26 #include "llvm/Support/Host.h"
27 #include "llvm/Config/config.h"
30 #include "clang/Frontend/TextDiagnosticPrinter.h"
31 #include "clang/Lex/HeaderSearch.h"
32 #include "clang/Basic/FileManager.h"
33 #include "clang/Frontend/Utils.h"
34 #include "clang/Basic/TargetInfo.h"
35 #include "clang/Lex/Preprocessor.h"
36 #include "clang/Frontend/CompilerInstance.h"
37 #include "clang/AST/ASTConsumer.h"
38 #include "clang/Sema/Lookup.h"
39 #include "clang/Parse/ParseAST.h"
40 #include "clang/Basic/Version.h"
41 #include "clang/Driver/Driver.h"
42 #include "clang/Driver/Compilation.h"
47 using namespace clang;
48 using namespace clang::driver;
51 class MyDiagnosticClient : public TextDiagnosticPrinter // My diagnostic Client
57 MyDiagnosticClient(llvm::raw_ostream &os, const DiagnosticOptions &diags, bool OwnsOutputStream = false):TextDiagnosticPrinter(os, diags, OwnsOutputStream = false)
63 virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, const DiagnosticInfo &Info)
65 TextDiagnosticPrinter::HandleDiagnostic(DiagLevel, Info); // print diagnostic information
68 case 0 : nignored+=1; break;
69 case 1 : nnotes+=1; break;
70 case 2 : nwarnings+=1; break;
71 default : print_stats(); exit(1);
77 cout<<"\n--Diagnostic Info--\n";
78 cout<<"Number of ignored: "<<nignored<<"\n";
79 cout<<"Number of notes: "<<nnotes<<"\n";
80 cout<<"Number of warnings: "<<nwarnings<<"\n";
81 cout<<"Number of errors and fatal errors: "<<1<<"\n";
84 int getNbrOfWarnings()
100 class FindStates : public ASTConsumer
102 list<string> transitions;
103 list<string> cReactions;
106 string name_of_machine;
107 string name_of_start;
108 FullSourceLoc *fsloc;
112 list<string> getStates()
117 list<string> getTransitions()
122 list<string> getEvents()
127 string getStateMachine()
129 return name_of_machine;
132 string getNameOfFirstState()
134 return name_of_start;
137 virtual void Initialize(ASTContext &ctx)//run after the AST is constructed before the consumer starts to work
139 fsloc = new FullSourceLoc(* new SourceLocation(), ctx.getSourceManager());
141 name_of_machine = "";
144 virtual void HandleTopLevelDecl(DeclGroupRef DGR)// traverse all top level declarations
147 string line, output, event;
148 llvm::raw_string_ostream x(output);
149 for (DeclGroupRef::iterator i = DGR.begin(), e = DGR.end(); i != e; ++i)
151 const Decl *decl = *i;
152 loc = decl->getLocation();
155 //cout<<decl->getKind()<<"ss\n";
156 if(decl->getKind()==35)
160 if (const TagDecl *tagDecl = dyn_cast<TagDecl>(decl))
162 if(tagDecl->isStruct() || tagDecl->isClass()) //is it a struct or class
167 if(const NamespaceDecl *namespaceDecl = dyn_cast<NamespaceDecl>(decl))
170 DeclContext *declCont = namespaceDecl->castToDeclContext(namespaceDecl);
171 //cout<<namedDecl->getNameAsString()<<" sss\n";
172 recursive_visit(declCont);
179 void recursive_visit(const DeclContext *declCont) //recursively visit all decls hidden inside namespaces
181 string line, output, event;
182 llvm::raw_string_ostream x(output);
184 for (DeclContext::decl_iterator i = declCont->decls_begin(), e = declCont->decls_end(); i != e; ++i)
186 const Decl *decl = *i;
187 //std::cout<<"a "<<decl->getDeclKindName()<<"\n";
188 loc = decl->getLocation();
191 if(decl->getKind()==35)
195 else if (const TagDecl *tagDecl = dyn_cast<TagDecl>(decl))
197 if(tagDecl->isStruct() || tagDecl->isClass()) //is it a structure or class
202 else if(const NamespaceDecl *namespaceDecl = dyn_cast<NamespaceDecl>(decl))
204 DeclContext *declCont = namespaceDecl->castToDeclContext(namespaceDecl);
205 //cout<<namedDecl->getNameAsString()<<" sss\n";
206 recursive_visit(declCont);
213 void struct_class(const Decl *decl) // works with struct or class decl
215 string output, line, ret, trans, event;
216 llvm::raw_string_ostream x(output);
218 line = get_line_of_code(x.str());
221 const NamedDecl *namedDecl = dyn_cast<NamedDecl>(decl);
224 const CXXRecordDecl *cRecDecl = dyn_cast<CXXRecordDecl>(decl);
226 if(find_events(cRecDecl, line))
228 events.push_back(namedDecl->getNameAsString());
229 cout<<"New event: "<<namedDecl->getNameAsString()<<"\n";
231 else if(name_of_machine == "")
233 ret = find_name_of_machine(cRecDecl, line);
237 name_of_machine = ret.substr(0,pos);
238 name_of_start = ret.substr(pos+1);
239 cout<<"Name of the state machine: "<<name_of_machine<<"\n";
240 cout<<"Name of the first state: "<<name_of_start<<"\n";
245 ret = find_states(cRecDecl, line);
248 cout << "New state: " << namedDecl->getNameAsString() << "\n";
249 states.push_back(ret);
250 methods_in_class(decl,namedDecl->getNameAsString());
256 void methods_in_class(const Decl *decl, const string state)
258 string output, line, ret, trans, event;
259 llvm::raw_string_ostream x(output);
261 const TagDecl *tagDecl = dyn_cast<TagDecl>(decl);
262 const DeclContext *declCont = tagDecl->castToDeclContext(tagDecl);
263 //states.push_back(namedDecl->getNameAsString());
266 for (DeclContext::decl_iterator i = declCont->decls_begin(), e = declCont->decls_end(); i != e; ++i)
268 if (i->getKind()==26)
272 line = clean_spaces(cut_type(output));
273 ret = find_transitions(state,line);
276 num = count(ret,';')+1;
277 for(int i = 0;i<num;i++)
284 if(pos==-1) cReactions.push_back(ret);
285 else cReactions.push_back(ret.substr(0,pos));
290 if(pos==-1) transitions.push_back(ret);
291 else transitions.push_back(ret.substr(0,pos));
294 if(i!=num-1) ret = ret.substr(pos+1);
299 if(i->getKind()==35) method_decl(decl);
303 void method_decl(const Decl *decl)
305 string output, line, event;
306 llvm::raw_string_ostream x(output);
310 line = get_return(x.str());
311 if(test_model(line,"result"))
313 const FunctionDecl *fDecl = dyn_cast<FunctionDecl>(decl);
314 const ParmVarDecl *pvd = fDecl->getParamDecl(0);
315 QualType qt = pvd->getOriginalType();
316 event = qt.getAsString();
317 if(event[event.length()-1]=='&') event = event.substr(0,event.length()-2);
318 event = event.substr(event.rfind(" ")+1);
319 line = dyn_cast<NamedDecl>(decl)->getQualifiedNameAsString();
320 line = cut_namespaces(line.substr(0,line.rfind("::")));
323 find_return_stmt(decl->getBody(),line);
324 for(list<string>::iterator i = cReactions.begin();i!=cReactions.end();i++)
327 if(line.compare(event)==0)
337 void find_return_stmt(Stmt *statemt,string event)
339 if(statemt->getStmtClass() == 99) test_stmt(dyn_cast<CaseStmt>(statemt)->getSubStmt(), event);
342 for (Stmt::child_range range = statemt->children(); range; ++range)
344 test_stmt(*range, event);
349 void test_stmt(Stmt *stmt, string event)
351 const SourceManager &sman = fsloc->getManager();
354 type = stmt->getStmtClass();
357 case 8 : find_return_stmt(dyn_cast<DoStmt>(stmt)->getBody(), event); // do
359 case 86 : find_return_stmt(dyn_cast<ForStmt>(stmt)->getBody(), event); // for
361 case 88 : find_return_stmt(dyn_cast<IfStmt>(stmt)->getThen(), event); //if then
362 find_return_stmt(dyn_cast<IfStmt>(stmt)->getElse(), event); //if else
364 case 90 : find_return_stmt(dyn_cast<LabelStmt>(stmt)->getSubStmt(), event); //label
366 case 98 : line = sman.getCharacterData(dyn_cast<ReturnStmt>(stmt)->getReturnLoc());
367 line = get_line_of_code(line).substr(6);
368 line = line.substr(0,line.find("("));
369 if(test_model(line,"transit"))
371 param = get_params(line);
372 transitions.push_back(event.append(",").append(param));
375 case 99 : find_return_stmt(stmt, event);
377 case 101 : find_return_stmt(dyn_cast<SwitchStmt>(stmt)->getBody(), event); // switch
379 case 102 : find_return_stmt(dyn_cast<WhileStmt>(stmt)->getBody(), event); // while
386 int main(int argc, char **argv)
388 string inputFilename = "";
389 string outputFilename = "graph.dot"; // initialize output Filename
390 DiagnosticOptions dopts;
392 MyDiagnosticClient *mdc = new MyDiagnosticClient(llvm::errs(), dopts);
393 llvm::IntrusiveRefCntPtr<DiagnosticIDs> dis(new DiagnosticIDs());
394 Diagnostic diag(dis,mdc);
395 FileManager fm( * new FileSystemOptions());
396 SourceManager sm (diag, fm);
397 HeaderSearch *headers = new HeaderSearch(fm);
399 Driver TheDriver(LLVM_BINDIR, llvm::sys::getHostTriple(), "", false, false, diag);
400 TheDriver.setCheckInputsExist(true);
401 TheDriver.CCCIsCXX = 1;
402 TheDriver.ResourceDir = LLVM_PREFIX "/lib/clang/" CLANG_VERSION_STRING;
404 CompilerInvocation compInv;
405 llvm::SmallVector<const char *, 16> Args(argv, argv + argc);
406 llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args.size(),
408 const driver::JobList &Jobs = C->getJobs();
409 const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
410 const driver::ArgStringList &CCArgs = Cmd->getArguments();
411 for(unsigned i = 0; i<Args.size();i++) // find -o in ArgStringList
413 if(strncmp(Args[i],"-o",2)==0)
415 if(strlen(Args[i])>2)
417 string str = Args[i];
418 outputFilename = str.substr(2);
420 else outputFilename = Args[i+1];
425 CompilerInvocation::CreateFromArgs(compInv,
426 const_cast<const char **>(CCArgs.data()),
427 const_cast<const char **>(CCArgs.data())+CCArgs.size(),
430 HeaderSearchOptions hsopts = compInv.getHeaderSearchOpts();
431 LangOptions lang = compInv.getLangOpts();
432 CompilerInvocation::setLangDefaults(lang, IK_ObjCXX);
433 TargetInfo *ti = TargetInfo::CreateTargetInfo(diag, compInv.getTargetOpts());
434 FrontendOptions f = compInv.getFrontendOpts();
435 inputFilename = f.Inputs[0].second;
437 cout<<"Input filename: "<<inputFilename<<"\n"; // print Input filename
438 cout<<"Output filename: "<<outputFilename<<"\n"; // print Output filename
441 Preprocessor pp(diag, lang, *ti, sm, *headers);
442 pp.getBuiltinInfo().InitializeBuiltins(pp.getIdentifierTable(), lang);
444 InitializePreprocessor(pp, compInv.getPreprocessorOpts(),hsopts,f);
446 const FileEntry *file = fm.getFile(inputFilename);
447 sm.createMainFileID(file);
448 IdentifierTable tab(lang);
449 Builtin::Context builtins(*ti);
451 ASTContext ctx(lang, sm, *ti, tab, * new SelectorTable(), builtins,0);
452 mdc->BeginSourceFile(lang, &pp);//start using diagnostic
453 ParseAST(pp, &c, ctx, false, false);
454 mdc->EndSourceFile(); //end using diagnostic
455 IO_operations *io = new IO_operations(outputFilename, c.getStateMachine(), c.getNameOfFirstState(), c.getTransitions(), c.getStates(), c.getEvents());