diff --git a/include/CTUApexConsumer.h b/include/CTUApexConsumer.h index cd41f28a9b4b88662c4541a08b3d6ff8a5e76f04..5293dd08962de994b720bfaeb767e0682e1bec13 100644 --- a/include/CTUApexConsumer.h +++ b/include/CTUApexConsumer.h @@ -46,6 +46,8 @@ private: ExtractionBlock getNextExtractionBlock(); void getAvailableFunctions(metacg::Callgraph callgraph); + + void filterExtrationBlocks(); }; #endif //CTUAPEX_CTUAPEXCONSUMER_H diff --git a/include/CommandLineArgs.h b/include/CommandLineArgs.h index bd24f4a09daef14aec11d936c6a9f15bea57666b..00766ccc00fe824cd6d91997a6922ecbf8ccca61 100644 --- a/include/CommandLineArgs.h +++ b/include/CommandLineArgs.h @@ -33,8 +33,5 @@ static cl::opt<LogLevel> LoggingLevel("log-level", cl::desc("Select log level"), 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/src/CTUApexConsumer.cpp b/src/CTUApexConsumer.cpp index cc852da4c8c6f84a51ee10204623c5c905451097..43181e805ee19dffe99d5f7cd16d12a384b426cf 100644 --- a/src/CTUApexConsumer.cpp +++ b/src/CTUApexConsumer.cpp @@ -10,32 +10,35 @@ void CTUApexConsumer::outlineFunctions() { for (const auto &node: call_graph->getNodes()) { + //check for each node in the graph, whether we found a corresponding node in the current ast if (auto md = node.second->checkAndGet<ExtractionMetadata>(); md.first && md.second->get_decl_node()) { ExtractionBlock eb; - if(md.second->isMarkedToExtract()){ - clang::SourceRange sourceRange; - if(md.second->get_decl_node()->isTemplateInstantiation()){ - sourceRange =md.second->get_decl_node()->getPrimaryTemplate()->getSourceRange(); - }else{ - sourceRange= md.second->get_decl_node()->getSourceRange(); - } - eb.begin = sourceRange.getBegin(); - eb.end = sourceRange.getEnd(); - //std::cout<<"Need to extract: "<<md.second->get_decl_node()->getNameAsString()<<"\n"; + clang::SourceRange sourceRange; + //The decl will refer to the instantiated template, but we need the contents of the original template specification + if (md.second->get_decl_node()->isTemplateInstantiation()) { + sourceRange = md.second->get_decl_node()->getPrimaryTemplate()->getSourceRange(); + } else { + sourceRange = md.second->get_decl_node()->getSourceRange(); + } + eb.begin = sourceRange.getBegin(); + eb.end = sourceRange.getEnd(); + //We only copy the contents if we are interested in them, but we do need an source-range bound extraction block for every function + //To later filter for pragmas and macros + if (md.second->isMarkedToExtract()) { eb.contents = clang::Lexer::getSourceText(clang::CharSourceRange::getTokenRange(sourceRange), md.second->get_decl_node()->getASTContext().getSourceManager(), clang::LangOptions(), nullptr).str(); - }else{ - //std::cout<<"Not extracting: "<<md.second->get_decl_node()->getNameAsString()<<"\n"; - eb.contents=""; + } else { + eb.contents = ""; } funcs.push_back(eb); } } //the callgraph nodes are unsorted, we need to sort the extraction blocks afterward - std::sort(funcs.begin(),funcs.end(),[](const ExtractionBlock& a, const ExtractionBlock& b){return a.begin<b.begin;}); + std::sort(funcs.begin(), funcs.end(), + [](const ExtractionBlock &a, const ExtractionBlock &b) { return a.begin < b.begin; }); } void CTUApexConsumer::outlineGlobals() { @@ -48,7 +51,8 @@ void CTUApexConsumer::outlineGlobals() { assert(clang::isa<clang::FunctionDecl>(md.second->get_decl_node()) && "Extractionset should only contain function decls at this point"); GlobalsMarker gMarker; - auto globalsSet = gMarker.get_nodes_to_outline(clang::cast<clang::FunctionDecl>(md.second->get_decl_node())); + auto globalsSet = gMarker.get_nodes_to_outline( + clang::cast<clang::FunctionDecl>(md.second->get_decl_node())); for (const auto &func: globalsSet) { ExtractionBlock eb; eb.begin = func->getBeginLoc(); @@ -64,6 +68,24 @@ void CTUApexConsumer::outlineGlobals() { } } +void CTUApexConsumer::filterExtrationBlocks() { + //Funcs has source-ranges for every function, but only contents for the relevant ones + //We remove all entries in the includes, macros, and pragmas that are inside ANY function + //We either get the chars by copying the function, then we do not need them + //Or we do not extract the function, then we do not want to copy the includes, macros and pragmas. + //We only want "out of function" includes, macros and pragmas + for (const auto &func: funcs) { + clang::SourceRange s = {func.begin, func.end}; + //Cast to void to ignore return-value of remove_if + (void) std::remove_if(includes.begin(), includes.end(), + [&s](const ExtractionBlock &e) { return s.fullyContains({e.begin, e.end}); }); + (void) std::remove_if(macros.begin(), macros.end(), + [&s](const ExtractionBlock &e) { return s.fullyContains({e.begin, e.end}); }); + (void) std::remove_if(pragmas.begin(), pragmas.end(), + [&s](const ExtractionBlock &e) { return s.fullyContains({e.begin, e.end}); }); + } +} + ExtractionBlock CTUApexConsumer::getNextExtractionBlock() { //find the earliest block by starting source location //we need to do a potentially expensive copy of the full struct @@ -143,6 +165,9 @@ void CTUApexConsumer::HandleTranslationUnit(clang::ASTContext &Context) { SPDLOG_INFO("Outlining Globals"); outlineGlobals(); + SPDLOG_INFO("Removing duplicate extraction blocks"); + filterExtrationBlocks(); + SPDLOG_INFO("Generate code skeleton"); const auto &sm = Context.getSourceManager(); std::string filename = sm.getFileEntryForID(sm.getMainFileID())->getName().str(); @@ -155,16 +180,16 @@ void CTUApexConsumer::HandleTranslationUnit(clang::ASTContext &Context) { outFile << getNextExtractionBlock().contents << "\n"; } - - SPDLOG_INFO("Generate wrapper calls"); SPDLOG_CRITICAL("WRAPPER CALLS CAN NOT YET BE IMPLEMENTED"); - if(auto md=call_graph->getMain()->checkAndGet<ExtractionMetadata>(); md.first && !md.second->isMarkedToExtract()){ + if (auto md = call_graph->getMain()->checkAndGet<ExtractionMetadata>(); md.first && + !md.second->isMarkedToExtract()) { //we have no main function and need to create or own - outFile<<"\nint main(){return 0;}\n"; + outFile << "\nint main(){return 0;}\n"; } + // Outline the code we want //SPDLOG_DEBUG("Generating outline"); //assert(output.empty()); @@ -190,3 +215,4 @@ void CTUApexConsumer::HandleTranslationUnit(clang::ASTContext &Context) { + diff --git a/src/main.cpp b/src/main.cpp index 8f6910bfda17111452b412791e0551912bc5efe3..bd214ffb91e8a9f69e40493a8e9b319dd2c710ae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -72,8 +72,11 @@ private: void markCalleesToExtract(const size_t nodeID, const metacg::Callgraph &cg) { for (const auto &call: cg.getCallees(nodeID)) { - call->getOrCreateMD<ExtractionMetadata>()->setMarkedToExtract(true); - markCalleesToExtract(call->getId(), cg); + //This check is probably? necessary in case of recursive functions + if(auto [h,v]=call->checkAndGet<ExtractionMetadata>(); !h || !v->isMarkedToExtract()){ + call->getOrCreateMD<ExtractionMetadata>()->setMarkedToExtract(true); + markCalleesToExtract(call->getId(), cg); + } } } @@ -112,14 +115,15 @@ std::vector<std::string> clangIncludeBasedArgumentAdjustor(const CommandLineArgu 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)); + auto t=std::prev(ret.end(),3); + ret.insert(t,{"-I" + txt.substr(prev, pos - prev)}); prev = pos + 2; } return ret; } std::vector<std::string> clangResourceDirBasedAdjuster(const CommandLineArguments &cla, StringRef) { - //call the compiler specified in cla[0] with -S and -v like so + //call the compiler specified in cla[0] with the job to print the resource directory for compiler specific includes std::string command = "clang --print-resource-dir 2>1&"; std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command.c_str(), "r"), pclose); //then read the output of the command like so: @@ -137,7 +141,6 @@ std::vector<std::string> clangResourceDirBasedAdjuster(const CommandLineArgument //additional search paths need to be inserted before these 3 auto t=std::prev(ret.end(),3); ret.insert(t,{"-I" + txt + "/include"}); - std::cout<<"\n"; return ret; } @@ -193,7 +196,6 @@ int main(int argc, const char **argv) { ClangTool tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList()); - //tool.clearArgumentsAdjusters(); tool.appendArgumentsAdjuster(clangResourceDirBasedAdjuster); metacg::io::FileSource fs(cg_file.getValue());