ostream& operator<<(ostream& os, const State& s)
{
+ os << indent << "" << s.name << "\n";
if (s.size()) {
+ os << indent << s.name << " -> " << s.initialInnerState << " [style = dashed]\n";
os << indent << "subgraph cluster_" << s.name << " {\n" << indent_inc;
os << indent << "label = \"" << s.name << "\"\n";
- }
- os << indent << "" << s.name << "\n";
- if (s.size()) {
os << indent << s.initialInnerState << " [peripheries=2]\n";
os << static_cast<Context>(s);
os << indent_dec << indent << "}\n";
}
};
+class FindTransitVisitor : public RecursiveASTVisitor<FindTransitVisitor>
+{
+ Model::Model &model;
+ const CXXRecordDecl *SrcState;
+ const Type *EventType;
+public:
+ explicit FindTransitVisitor(Model::Model &model, const CXXRecordDecl *SrcState, const Type *EventType)
+ : model(model), SrcState(SrcState), EventType(EventType) {}
+
+ bool VisitMemberExpr(MemberExpr *E) {
+ if (E->getMemberNameInfo().getAsString() != "transit")
+ return true;
+ if (E->hasExplicitTemplateArgs()) {
+ const Type *DstStateType = E->getExplicitTemplateArgs()[0].getArgument().getAsType().getTypePtr();
+ CXXRecordDecl *DstState = DstStateType->getAsCXXRecordDecl();
+ CXXRecordDecl *Event = EventType->getAsCXXRecordDecl();
+ Model::Transition *T = new Model::Transition(SrcState->getName(), DstState->getName(), Event->getName());
+ model.transitions.push_back(T);
+ }
+ return true;
+ }
+};
class Visitor : public RecursiveASTVisitor<Visitor>
{
Model::Model &model;
DiagnosticsEngine &Diags;
unsigned diag_unhandled_reaction_type, diag_unhandled_reaction_decl,
- diag_found_state, diag_found_statemachine;
+ diag_found_state, diag_found_statemachine, diag_no_history;
public:
bool shouldVisitTemplateInstantiations() const { return true; }
Diags.getCustomDiagID(DiagnosticsEngine::Error, "Unhandled reaction type '%0'");
diag_unhandled_reaction_decl =
Diags.getCustomDiagID(DiagnosticsEngine::Error, "Unhandled reaction decl '%0'");
+ diag_unhandled_reaction_decl =
+ Diags.getCustomDiagID(DiagnosticsEngine::Error, "History is not yet supported");
}
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { return Diags.Report(Loc, DiagID); }
+ void HandleCustomReaction(const CXXRecordDecl *SrcState, const Type *EventType)
+ {
+ IdentifierInfo& II = ASTCtx->Idents.get("react");
+ // TODO: Lookup for react even in base classes - probably by using Sema::LookupQualifiedName()
+ for (DeclContext::lookup_const_result ReactRes = SrcState->lookup(DeclarationName(&II));
+ ReactRes.first != ReactRes.second; ++ReactRes.first) {
+ if (CXXMethodDecl *React = dyn_cast<CXXMethodDecl>(*ReactRes.first))
+ if (const ParmVarDecl *p = React->getParamDecl(0)) {
+ const Type *ParmType = p->getType().getTypePtr();
+ if (ParmType->isLValueReferenceType())
+ ParmType = dyn_cast<LValueReferenceType>(ParmType)->getPointeeType().getTypePtr();
+ if (ParmType == EventType)
+ FindTransitVisitor(model, SrcState, EventType).TraverseStmt(React->getBody());
+ }
+ }
+ }
+
void HandleReaction(const Type *T, const SourceLocation Loc, CXXRecordDecl *SrcState)
{
// TODO: Improve Loc tracking
model.transitions.push_back(T);
} else if (name == "boost::statechart::custom_reaction") {
const Type *EventType = TST->getArg(0).getAsType().getTypePtr();
- CXXRecordDecl *Event = EventType->getAsCXXRecordDecl();
-
- Model::Transition *T = new Model::Transition(SrcState->getName(), "\"???\"", Event->getName());
- model.transitions.push_back(T);
+ HandleCustomReaction(SrcState, EventType);
} else if (name == "boost::statechart::deferral") {
const Type *EventType = TST->getArg(0).getAsType().getTypePtr();
CXXRecordDecl *Event = EventType->getAsCXXRecordDecl();
// Either we saw a reference to forward declared state
// before, or we create a new state.
if (!(state = model.removeFromUnknownContexts(name)))
+ // TODO: Fix the value of name
state = new Model::State(name);
CXXRecordDecl *Context = getTemplateArgDecl(Base->getType().getTypePtr(), 1);
if (CXXRecordDecl *InnerInitialState = getTemplateArgDecl(Base->getType().getTypePtr(), 2))
state->setInitialInnerState(InnerInitialState->getName());
+// if (CXXRecordDecl *History = getTemplateArgDecl(Base->getType().getTypePtr(), 3))
+// Diag(History->getLocStart(), diag_no_history);
+
IdentifierInfo& II = ASTCtx->Idents.get("reactions");
// TODO: Lookup for reactions even in base classes - probably by using Sema::LookupQualifiedName()
for (DeclContext::lookup_result Reactions = RecordDecl->lookup(DeclarationName(&II));