Instantiator
Generate c++ template instantiations
Loading...
Searching...
No Matches
InjectInstantiation.cpp
Go to the documentation of this file.
2
3#include <filesystem>
4#include <iostream>
5
6#include "spdlog/spdlog.h"
7
8#include "clang/AST/Decl.h"
9#include "clang/AST/DeclCXX.h"
10#include "clang/AST/DeclTemplate.h"
11#include "clang/AST/TemplateName.h"
12#include "clang/ASTMatchers/ASTMatchers.h"
13#include "clang/Rewrite/Core/Rewriter.h"
14#include "llvm/ADT/APInt.h"
15#include "llvm/ADT/StringRef.h"
16
17#include "Injection.hpp"
18#include "Template.hpp"
19
20void InjectInstantiation::run(const clang::ast_matchers::MatchFinder::MatchResult& Result)
21{
22 clang::PrintingPolicy pp(Result.Context->getLangOpts());
23 pp.PrintInjectedClassNameWithArguments = true;
24 pp.PrintCanonicalTypes = true;
25 pp.SuppressDefaultTemplateArgs = true;
26 pp.FullyQualifiedName = true;
27 pp.SuppressScope = false;
28 // pp.UsePreferredNames = true;
29
30 if(const clang::CXXMethodDecl* MFS = Result.Nodes.getNodeAs<clang::CXXMethodDecl>("func_definition")) {
31 spdlog::debug("Processing memfunc {}", MFS->getNameAsString());
32 spdlog::debug("TI={}, CTI={}", MFS->isTemplateInstantiation(), (MFS->getParent()->getMemberSpecializationInfo() != nullptr));
33 if(MFS->isTemplateInstantiation() or (MFS->getParent()->getMemberSpecializationInfo() != nullptr)) {
34 if(const clang::MemberSpecializationInfo* MSI = MFS->getMemberSpecializationInfo()) {
35 if(MSI->getTemplateSpecializationKind() != clang::TSK_ExplicitInstantiationDefinition) { return; }
36 } else if(const clang::FunctionTemplateSpecializationInfo* TSI = MFS->getTemplateSpecializationInfo()) {
37 if(TSI->getTemplateSpecializationKind() != clang::TSK_ExplicitInstantiationDefinition) { return; }
38 }
39 auto candidate = Injection::createFromMFS(MFS, pp);
40
41 // search in toDoList if this instantation is needed. if yes -> delete
42 // it from list.
43 spdlog::debug("Check if the instantiation is already present.");
44 for(auto it = toDoList->begin(); it != toDoList->end();) {
45 Injection& toDo = *it;
46
47 if(candidate.match(toDo)) {
48 spdlog::debug("Erasing element from toDolist:\n {} because of: {}", toDo, candidate);
49 it = toDoList->erase(it);
50 } else {
51 it++;
52 }
53 }
54 } else {
55 // search in toDoList if this instantiation is needed. inject the
56 // instantation in the Rewriter.
57 spdlog::debug("Check for match.");
58 auto candidate = Template::createFromMFS(MFS, pp);
59 spdlog::debug("Processing candidate: {}", candidate);
60 for(auto it = toDoList->begin(); it != toDoList->end();) {
61 Injection& toDo = *it;
62 spdlog::debug("CHecking toDo entry: {}", toDo);
63 if(candidate.isTemplateFor(toDo)) {
64 if(invasive) {
65 rewriter->InsertText(MFS->getBodyRBrace().getLocWithOffset(1), llvm::StringRef(it->getInstantiation()), true, true);
66 } else {
67 spdlog::debug("Match!!! Call the rewriter and delete entry from toDoList.");
68 auto sc = MFS->getBodyRBrace().getLocWithOffset(1);
69 auto fid = rewriter->getSourceMgr().getFileID(sc);
70 auto fileentry = rewriter->getSourceMgr().getFileEntryRefForID(fid);
71 auto fname_ = rewriter->getSourceMgr().getFileManager().getCanonicalName(*fileentry);
72 std::string fname(fname_.data(), fname_.size());
73 auto new_name = std::filesystem::path(fname);
74 new_name.replace_extension("gen.cpp");
75 auto& sm = rewriter->getSourceMgr();
76 auto& fm = sm.getFileManager();
77 auto new_name_str = new_name.string();
78 llvm::StringRef gen_name(new_name_str);
79 auto file_ref = fm.getFileRef(gen_name, true);
80 auto new_fid = sm.getOrCreateFileID(*file_ref, clang::SrcMgr::C_User);
81 auto new_loc = sm.getLocForEndOfFile(new_fid);
82 rewriter->InsertText(new_loc, llvm::StringRef(it->getInstantiation()), true, true);
83 }
84 it = toDoList->erase(it);
85 } else {
86 it++;
87 }
88 }
89 }
90 } else if(const clang::FunctionDecl* FS = Result.Nodes.getNodeAs<clang::FunctionDecl>("func_definition")) {
91 spdlog::debug("Processing func {}", FS->getNameAsString());
92 if(FS->isTemplateInstantiation()) {
93 if(const clang::FunctionTemplateSpecializationInfo* TSI = FS->getTemplateSpecializationInfo()) {
94 if(TSI->getTemplateSpecializationKind() != clang::TSK_ExplicitInstantiationDefinition) { return; }
95 }
96 auto candidate = Injection::createFromFS(FS, pp);
97 // search in toDoList if this instantation is needed. if yes -> delete
98 // it from list.
99 spdlog::debug("Check if the instantiation is already present.");
100 for(auto it = toDoList->begin(); it != toDoList->end();) {
101 Injection& toDo = *it;
102 if(candidate.match(toDo)) {
103 spdlog::debug("Erase from toDolist.");
104 it = toDoList->erase(it);
105 } else {
106 it++;
107 }
108 }
109 } else {
110 // search in toDoList if this instantation is needed. inject the
111 // instantation in the Rewriter.
112 spdlog::debug("Check if the correct prototype is present for explicit instantiation.");
113 auto candidate = Template::createFromFS(FS, pp);
114 for(auto it = toDoList->begin(); it != toDoList->end();) {
115 Injection& toDo = *it;
116 if(candidate.isTemplateFor(toDo)) {
117 spdlog::debug("Match!!! Call the rewriter and delete entry from toDoList.");
118 spdlog::debug("Injection: {}", it->getInstantiation());
119 if(invasive) {
120 rewriter->InsertText(FS->getBodyRBrace().getLocWithOffset(1), llvm::StringRef(it->getInstantiation()), true, true);
121 } else {
122 auto sc = FS->getBodyRBrace().getLocWithOffset(1);
123 auto fid = rewriter->getSourceMgr().getFileID(sc);
124 auto fileentry = rewriter->getSourceMgr().getFileEntryRefForID(fid);
125 auto fname_ = rewriter->getSourceMgr().getFileManager().getCanonicalName(*fileentry);
126 std::string fname(fname_.data(), fname_.size());
127 auto new_name = std::filesystem::path(fname);
128 new_name.replace_extension("gen.cpp");
129 std::cout << "Injecting in file " << new_name << std::endl;
130 auto& sm = rewriter->getSourceMgr();
131 auto& fm = sm.getFileManager();
132 auto new_name_str = new_name.string();
133 llvm::StringRef gen_name(new_name_str);
134 auto file_ref = fm.getFileRef(gen_name, true);
135 auto new_fid = sm.getOrCreateFileID(*file_ref, clang::SrcMgr::C_User);
136 auto new_loc = sm.getLocForEndOfFile(new_fid);
137 rewriter->InsertText(new_loc, llvm::StringRef(it->getInstantiation()), true, true);
138 }
139 it = toDoList->erase(it);
140 } else {
141 it++;
142 }
143 }
144 }
145 }
146}
virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) override
clang::Rewriter * rewriter
std::vector< Injection > * toDoList
Struct for the collection of all relevant data for a template instantiation which needs to be inserte...
Definition Injection.hpp:21
static Injection createFromFS(const clang::FunctionDecl *FS, clang::PrintingPolicy pp)
Definition Injection.cpp:30
static Injection createFromMFS(const clang::CXXMethodDecl *MFS, clang::PrintingPolicy pp)
Definition Injection.cpp:52
static Template createFromFS(const clang::FunctionDecl *FS, clang::PrintingPolicy pp)
Definition Template.cpp:18
static Template createFromMFS(const clang::CXXMethodDecl *MFS, clang::PrintingPolicy pp)
Definition Template.cpp:33