diff --git a/include/CommandLineArgs.h b/include/CommandLineArgs.h
new file mode 100644
index 0000000000000000000000000000000000000000..bd24f4a09daef14aec11d936c6a9f15bea57666b
--- /dev/null
+++ b/include/CommandLineArgs.h
@@ -0,0 +1,40 @@
+//
+// Created by tim on 28.11.24.
+//
+
+#ifndef CTUAPEX_COMMANDLINEARGS_H
+#define CTUAPEX_COMMANDLINEARGS_H
+#include <clang/Tooling/CommonOptionsParser.h>
+using namespace llvm;
+//Die commandozeilen optionen die wir parsen wollen, gehören zu unserem program
+static cl::OptionCategory CTUApex("Cross Translation Unit App Extraction");
+
+static cl::opt<std::string> cg_file("cg-file", cl::desc("MetaCG file containing a whole programm call graph"),
+                                    cl::value_desc("filename"), cl::Required, cl::cat(CTUApex));
+
+enum class LogLevel {
+    Trace, Debug, Info, Warning, Error, /* Critical,*/ Off
+};
+
+static cl::list<std::string> extractionPoints("extract",
+                                              cl::desc("Qualified names of the function to start the extraction from"),
+                                              cl::value_desc("Comma separated list of function names"), cl::Optional,
+                                              cl::cat(CTUApex));
+
+static cl::opt<LogLevel> LoggingLevel("log-level", cl::desc("Select log level"),
+                                      cl::values(clEnumValN(LogLevel::Trace, "trace", "Enable Trace and higher logs"),
+                                                 clEnumValN(LogLevel::Debug, "debug", "Enable Debug and higher logs"),
+                                                 clEnumValN(LogLevel::Info, "info", "Enable Info and higher logs"),
+                                                 clEnumValN(LogLevel::Warning, "warning",
+                                                            "Enable Warning and higher logs"),
+                                                 clEnumValN(LogLevel::Error, "error", "Enable only Error logs"),
+                                                 clEnumValN(LogLevel::Off, "off", "Disable all logging")),
+                                      cl::init(LogLevel::Info), cl::cat(CTUApex));
+
+static cl::opt<bool> OnlyWrapper("generate-only-wrapper", cl::desc("Output only the wrapper function"),
+                                 cl::cat(CTUApex));
+static cl::opt<bool> DumpAnalysisResult("dump-analysis-result",
+                                        cl::desc("Dump the dependence analysis result to stdout"), cl::cat(CTUApex));
+
+
+#endif //CTUAPEX_COMMANDLINEARGS_H
diff --git a/include/FunctionFinderVisitor.h b/include/FunctionFinderVisitor.h
index 0d9ce1130110901b069ae6a903d5aed3abdb03cf..1298599970224c03557bfa6a7808ce94f589c02e 100644
--- a/include/FunctionFinderVisitor.h
+++ b/include/FunctionFinderVisitor.h
@@ -17,9 +17,11 @@ public:
 
     //This visits function declarations with the visitor pattern
     bool VisitFunctionDecl(clang::FunctionDecl *functionDecl);
+    bool VisitFunctionTemplateDecl(clang::FunctionTemplateDecl *D);
 
 private:
     metacg::Callgraph* callgraph;
+
 };
 
 
diff --git a/src/CTUApexVisitor.cpp b/src/CTUApexVisitor.cpp
index fbb2d0834f2730e938625a260709e7ec3d7d437d..761560c8a59d845e99476b3e003f6c318ddea69e 100644
--- a/src/CTUApexVisitor.cpp
+++ b/src/CTUApexVisitor.cpp
@@ -26,33 +26,64 @@ std::vector<std::string> getMangledName(clang::NamedDecl const *const nd) {
     return {NG.getName(nd)};
 }
 
+bool FunctionFinderVisitor::VisitFunctionTemplateDecl(clang::FunctionTemplateDecl *D) {
+    if (!D->getASTContext().getSourceManager().isInMainFile(D->getSourceRange().getBegin())) {
+        return true;
+    }
+    SPDLOG_DEBUG("FunctionTemplateDecl {} is visited", D->getNameAsString());
+
+    for (const auto &s: D->specializations()) {
+        for (const auto &name: getMangledName(s)) {
+
+            assert(callgraph->hasNode(name));
+
+            // we should find every node in the whole program callgraph
+            if (!callgraph->hasNode(name)) {
+                SPDLOG_WARN("Node {} is not in the call-graph. Graph might be wrong or incomplete!", name);
+                continue;
+            }
+
+            // We should only override if we have a body or if it is null
+            if (s->hasBody() || callgraph->getNode(name)->getOrCreateMD<ExtractionMetadata>()->get_decl_node() == nullptr) {
+                callgraph->getNode(name)->getOrCreateMD<ExtractionMetadata>()->set_decl_node(s);
+            }
+
+        }
+    }
+
+    return true;
+}
+
 bool FunctionFinderVisitor::VisitFunctionDecl(clang::FunctionDecl *functionDecl) {
     //If the function is not from main file (e.g a header defined function, don't mark
-    if(!functionDecl->getASTContext().getSourceManager().isInMainFile(functionDecl->getSourceRange().getBegin())){
+    if (!functionDecl->getASTContext().getSourceManager().isInMainFile(functionDecl->getSourceRange().getBegin())) {
         return true;
     }
 
-    if(functionDecl->isDependentContext()){
-        SPDLOG_DEBUG("Function {} is context dependent",functionDecl->getNameAsString());
+
+    if (functionDecl->isDependentContext()) {
+        SPDLOG_DEBUG("Function {} is context dependent", functionDecl->getNameAsString());
         return true;
     }
 
-    const auto possibleNames = getMangledName(functionDecl);
+    SPDLOG_DEBUG("Function {} is visited", functionDecl->getNameAsString());
+
+    const auto &possibleNames = getMangledName(functionDecl);
 
     //std::cout<<functionDecl->getNameAsString()<<col2str(possibleNames," All possible manglings are:(",",",")")<<"\n";
 
-    for(const auto& name : possibleNames){
+    for (const auto &name: possibleNames) {
 
         assert(callgraph->hasNode(name));
 
         // we should find every node in the whole program callgraph
-        if(!callgraph->hasNode(name)){
-            SPDLOG_WARN("Node {} is not in the call-graph. Graph might be wrong or incomplete!",name);
+        if (!callgraph->hasNode(name)) {
+            SPDLOG_WARN("Node {} is not in the call-graph. Graph might be wrong or incomplete!", name);
             continue;
         }
 
         // We should only override if we have a body or if it is null
-        if (functionDecl->hasBody() || callgraph->getNode(name)->getOrCreateMD<ExtractionMetadata>()->get_decl_node()==
+        if (functionDecl->hasBody() || callgraph->getNode(name)->getOrCreateMD<ExtractionMetadata>()->get_decl_node() ==
                                        nullptr) {
             callgraph->getNode(name)->getOrCreateMD<ExtractionMetadata>()->set_decl_node(functionDecl);
         }
diff --git a/src/main.cpp b/src/main.cpp
index c7e9e8efa23da6537ae933a5f2492b4ab9817dd9..35f25c794aae69d2fc2835f4df849fe967449dc9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -19,46 +19,34 @@
 #include "Util.h"
 #include "ExtractionMetadata.h"
 
+#include "CommandLineArgs.h"
+
+#include "llvm/Demangle/Demangle.h"
 
 //Das sind convenience definitionen, dass wir nicht so viel tippen müssen
 using namespace llvm;
 using namespace clang;
 using namespace clang::tooling;
-using namespace clang;
 
-//Die commandozeilen optionen die wir parsen wollen, gehören zu unserem program
-static cl::OptionCategory CTUApex("Cross Translation Unit App Extraction");
-//static cl::opt<std::string> callsites_file_opt("callsites-file", cl::desc("Config file with the callsites to outline"),
-//                                               cl::value_desc("filename"), cl::Required, cl::cat(CTUApex));
-static cl::opt<std::string> cg_file("cg-file", cl::desc("MetaCG file containing a whole programm call graph"),
-                                    cl::value_desc("filename"), cl::Required, cl::cat(CTUApex));
-enum class LogLevel {
-    Trace, Debug, Info, Warning, Error, /* Critical,*/ Off
-};
+template<typename T, class... Args>
+std::unique_ptr<clang::tooling::FrontendActionFactory> argumentParsingFrontendActionFactory(Args... args) {
+
+    class SimpleFrontendActionFactory : public clang::tooling::FrontendActionFactory {
+    public:
+        explicit SimpleFrontendActionFactory(Args... constructorArgs) {
+            fn1 = [=]() { return std::make_unique<T>(constructorArgs...); };
+        }
+
+        std::unique_ptr<clang::FrontendAction> create() override {
+            return fn1();
+        }
+
+    private:
+        std::function<std::unique_ptr<T>()> fn1; // function
+    };
 
-//static cl::opt<std::string> extractionStart("extract",
-//                                            cl::desc("Qualified name of the function to start the extraction from"),
-//                                            cl::value_desc("functionname"), cl::Optional, cl::cat(CTUApex));
-
-static cl::list<std::string> extractionPoints("extract",
-                                              cl::desc("Qualified names of the function to start the extraction from"),
-                                              cl::value_desc("Comma separated list of function names"), cl::Optional,
-                                              cl::cat(CTUApex));
-
-static cl::opt<LogLevel> LoggingLevel("log-level", cl::desc("Select log level"),
-                                      cl::values(clEnumValN(LogLevel::Trace, "trace", "Enable Trace and higher logs"),
-                                                 clEnumValN(LogLevel::Debug, "debug", "Enable Debug and higher logs"),
-                                                 clEnumValN(LogLevel::Info, "info", "Enable Info and higher logs"),
-                                                 clEnumValN(LogLevel::Warning, "warning",
-                                                            "Enable Warning and higher logs"),
-                                                 clEnumValN(LogLevel::Error, "error", "Enable only Error logs"),
-                                                 clEnumValN(LogLevel::Off, "off", "Disable all logging")),
-                                      cl::init(LogLevel::Info), cl::cat(CTUApex));
-
-static cl::opt<bool> OnlyWrapper("generate-only-wrapper", cl::desc("Output only the wrapper function"),
-                                 cl::cat(CTUApex));
-static cl::opt<bool> DumpAnalysisResult("dump-analysis-result",
-                                        cl::desc("Dump the dependence analysis result to stdout"), cl::cat(CTUApex));
+    return std::unique_ptr<FrontendActionFactory>(new SimpleFrontendActionFactory(args...));
+}
 
 class CTUApexFrontendAction : clang::ASTFrontendAction {
 public:
@@ -99,23 +87,14 @@ void markFunctionsAlongCallpaths(metacg::Callgraph &cg) {
     }
 }
 
-#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/FrontendAction.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Tooling/Tooling.h"
-
-using namespace clang;
-using namespace clang::tooling;
 
-std::vector<std::string> clangIncludeBasedArgumentAdjustor(const CommandLineArguments & cla , StringRef sr){
+std::vector<std::string> clangIncludeBasedArgumentAdjustor(const CommandLineArguments &cla, StringRef sr) {
     //call the compiler specified in cla[0] with -S and -v like so
     std::string command = "clang";
     //command.append(" -S -v");
     command.append("  -W,p -v -fsyntax-only");
-    for(int i=1;i<cla.size();i++){
-        command.append(" "+cla[i]);
+    for (int i = 1; i < cla.size(); i++) {
+        command.append(" " + cla[i]);
     }
     command.append(" 2>&1");
     std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command.c_str(), "r"), pclose);
@@ -126,20 +105,20 @@ std::vector<std::string> clangIncludeBasedArgumentAdjustor(const CommandLineArgu
         txt += buffer.data();
     }
     //search for "include search starts here" string and add all the paths with -I to the tool invocation
-    txt=txt.substr(txt.rfind("search starts here:")+20,txt.rfind("End of search list.")-txt.rfind("search starts here:")-20);
+    txt = txt.substr(txt.rfind("search starts here:") + 20,
+                     txt.rfind("End of search list.") - txt.rfind("search starts here:") - 20);
     std::vector<std::string> ret;
-    ret.assign(cla.begin(),cla.end());
+    ret.assign(cla.begin(), cla.end());
     std::string::size_type pos;
     std::string::size_type prev = 0;
-    while ((pos = txt.find('\n', prev)) != std::string::npos)
-    {
-        ret.push_back("-I"+txt.substr(prev, pos - prev));
+    while ((pos = txt.find('\n', prev)) != std::string::npos) {
+        ret.push_back("-I" + txt.substr(prev, pos - prev));
         prev = pos + 2;
     }
     return ret;
 }
 
-std::vector<std::string> clangResourceDirBasedAdjuster(const CommandLineArguments & cla , StringRef){
+std::vector<std::string> clangResourceDirBasedAdjuster(const CommandLineArguments &cla, StringRef) {
     //call the compiler specified in cla[0] with -S and -v like so
     std::string command = "clang --print-resource-dir 2>1&";
     std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command.c_str(), "r"), pclose);
@@ -150,13 +129,15 @@ std::vector<std::string> clangResourceDirBasedAdjuster(const CommandLineArgument
         txt += buffer.data();
     }
     std::vector<std::string> ret;
-    ret.assign(cla.begin(),cla.end());
+    ret.assign(cla.begin(), cla.end());
     trim(txt);
     txt.pop_back();
-    ret.push_back("-I"+txt+"/include");
+    ret.push_back("-I" + txt + "/include");
     return ret;
 }
 
+
+
 int main(int argc, const char **argv) {
 
     auto ExpectedParser = CommonOptionsParser::create(argc, argv, CTUApex);
@@ -192,7 +173,7 @@ int main(int argc, const char **argv) {
 
 
     ClangTool tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList());
-    tool.clearArgumentsAdjusters();
+    //tool.clearArgumentsAdjusters();
     tool.appendArgumentsAdjuster(clangResourceDirBasedAdjuster);
 
     metacg::io::FileSource fs(cg_file.getValue());
@@ -208,38 +189,28 @@ int main(int argc, const char **argv) {
     }
 
     auto &mcgManager = metacg::graph::MCGManager::get();
-    mcgManager.addToManagedGraphs("activeGraph",mcgReader->read());
+
+    //As the mcgReader spits out a warning for every occurance of a missing metadata,
+    //we silence all warnings for the duration of the read
+    const auto &lv = spdlog::get_level();
+    spdlog::set_level(spdlog::level::off);
+    mcgManager.addToManagedGraphs("activeGraph", mcgReader->read());
+    spdlog::set_level(lv);
 
     auto &cg = *mcgManager.getCallgraph();
 
     //Add extraction point gotten via the CLI
-    for(const auto& extractionFunc : extractionPoints){
+    for (const auto &extractionFunc: extractionPoints) {
         if (cg.hasNode(extractionFunc)) {
             auto *md = new ExtractionMetadata();
             md->setMarkedToExtract(true);
             cg.getNode(extractionFunc)->addMetaData(md);
-        }else{
-            SPDLOG_ERROR("The given function: "+ extractionFunc + " does not exist in the given callgraph");
+        } else {
+            SPDLOG_ERROR("The given function: " + extractionFunc + " does not exist in the given callgraph");
         }
     }
 
     markFunctionsAlongCallpaths(cg);
-
-    tool.run(clang::tooling::newFrontendActionFactory<CTUApexFrontendAction>(
-            new CTUApexFrontendAction(*mcgManager.getCallgraph())).get());
+    tool.run(argumentParsingFrontendActionFactory<CTUApexAction>(mcgManager.getCallgraph()).get());
     return 0;
 }
-
-
-
-
-
-
-
-
-
-
-
-
-
-