+const string &InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_func, Block &tgt_blk, const NodeList<Statement>::iterator &ins_pt, FunctionDeclaration &src)
+{
+ target_block = &tgt_blk;
+ source_func = &src;
+ for(NodeList<Statement>::iterator i=src.body.body.begin(); i!=src.body.body.end(); ++i)
+ {
+ r_inlined_statement = 0;
+ (*i)->visit(*this);
+ if(!r_inlined_statement)
+ r_inlined_statement = (*i)->clone();
+
+ SetFlag set_remap(remap_names);
+ r_inlined_statement->visit(*this);
+ tgt_blk.body.insert(ins_pt, r_inlined_statement);
+ }
+
+ NodeReorderer().apply(stage, target_func, dependencies);
+
+ return r_result_name;
+}
+
+string InlineContentInjector::create_unused_name(const string &base, bool always_prefix)
+{
+ string result = base;
+ if(always_prefix || target_block->variables.count(result))
+ result = format("_%s_%s", source_func->name, base);
+ unsigned initial_size = result.size();
+ for(unsigned i=1; target_block->variables.count(result); ++i)
+ {
+ result.erase(initial_size);
+ result += format("_%d", i);
+ }
+ return result;
+}
+
+void InlineContentInjector::visit(VariableReference &var)
+{
+ if(remap_names)
+ {
+ map<string, VariableDeclaration *>::const_iterator i = variable_map.find(var.name);
+ if(i!=variable_map.end())
+ var.name = i->second->name;
+ }
+ else if(var.declaration)
+ {
+ SetFlag set_deps(deps_only);
+ dependencies.insert(var.declaration);
+ var.declaration->visit(*this);
+ }
+}
+
+void InlineContentInjector::visit(InterfaceBlockReference &iface)
+{
+ if(!remap_names && iface.declaration)
+ {
+ SetFlag set_deps(deps_only);
+ dependencies.insert(iface.declaration);
+ iface.declaration->visit(*this);
+ }
+}
+
+void InlineContentInjector::visit(FunctionCall &call)
+{
+ if(!remap_names && call.declaration)
+ dependencies.insert(call.declaration);
+ TraversingVisitor::visit(call);
+}
+
+void InlineContentInjector::visit(VariableDeclaration &var)
+{
+ TraversingVisitor::visit(var);
+
+ if(var.type_declaration)
+ {
+ SetFlag set_deps(deps_only);
+ dependencies.insert(var.type_declaration);
+ var.type_declaration->visit(*this);
+ }
+
+ if(!remap_names && !deps_only)
+ {
+ RefPtr<VariableDeclaration> inlined_var = var.clone();
+ inlined_var->name = create_unused_name(var.name, false);
+ r_inlined_statement = inlined_var;
+
+ variable_map[var.name] = inlined_var.get();
+ }
+}
+
+void InlineContentInjector::visit(Return &ret)
+{
+ TraversingVisitor::visit(ret);
+
+ if(ret.expression)
+ {
+ /* Create a new variable to hold the return value of the inlined
+ function. */
+ r_result_name = create_unused_name("return", true);
+ RefPtr<VariableDeclaration> var = new VariableDeclaration;
+ var->source = ret.source;
+ var->line = ret.line;
+ var->type = source_func->return_type;
+ var->name = r_result_name;
+ var->init_expression = ret.expression->clone();
+ r_inlined_statement = var;
+ }
+}
+
+
+FunctionInliner::FunctionInliner():
+ current_function(0),
+ r_any_inlined(false)
+{ }
+
+bool FunctionInliner::apply(Stage &s)
+{
+ stage = &s;
+ inlineable = InlineableFunctionLocator().apply(s);
+ r_any_inlined = false;
+ s.content.visit(*this);
+ return r_any_inlined;
+}
+