Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions plugins/csharp/parser/include/csharpparser/csharpparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ class CsharpParser : public AbstractParser

bool acceptProjectBuildPath(const std::string& buildDir_);
bool parseProjectBuildPath(
const std::vector<std::string>& path_,
const std::string& buildPath_);
void addSource(const std::string& filepath_, bool error_);
const std::vector<std::string>& path_
);
void addSource(const std::string& filepath_, const std::string& targetDll_, bool error_);
};

} // parser
Expand Down
73 changes: 40 additions & 33 deletions plugins/csharp/parser/src/csharpparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

#include <memory>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

namespace cc
{
namespace parser
Expand All @@ -27,11 +30,7 @@ CsharpParser::CsharpParser(ParserContext& ctx_): AbstractParser(ctx_)
{
_threadNum = _ctx.options["jobs"].as<int>();
}
/*
bool CsharpParser::acceptProjectBuildPath(const std::vector<std::string>& path_)
{
return path_.size() >= 2 && fs::is_directory(path_[0]) && fs::is_directory(path_[1]);
}*/

bool CsharpParser::acceptProjectBuildPath(const std::string& buildPath_)
{
return fs::is_directory(buildPath_);
Expand All @@ -42,26 +41,24 @@ bool CsharpParser::parse()
bool success = true;

std::vector<std::string> paths = _ctx.options["input"].as<std::vector<std::string>>();
std::string buildPath = _ctx.options["build-dir"].as<std::string>();

if (acceptProjectBuildPath(buildPath))
if (!paths.empty())
{
LOG(debug) << "C# parser parse path: " << paths[0];
LOG(debug) << "Parsed csharp project build path: " << buildPath;
success = success && parseProjectBuildPath(paths, buildPath);
LOG(debug) << "C# parser parse path: " << paths.size();
success = success && parseProjectBuildPath(paths);
}
else
{
LOG(error) << "Build path must be a directory!";
LOG(error) << "No input directories provided for C# parser!";
success = false;
}

return success;
}

bool CsharpParser::parseProjectBuildPath(
const std::vector<std::string>& paths_,
const std::string& buildPath_)
const std::vector<std::string>& paths_ //,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented out comma.

)
{
namespace ch = std::chrono;
std::future<std::string> log;
Expand All @@ -80,8 +77,6 @@ bool CsharpParser::parseProjectBuildPath(
command.append("'");
command.append(_ctx.options["database"].as<std::string>());
command.append("' '");
command.append(buildPath_);
command.append("' '");
command.append(csharp_path.string());
command.append("' ");
command.append(std::to_string(_ctx.options["jobs"].as<int>()));
Expand All @@ -108,22 +103,38 @@ bool CsharpParser::parseProjectBuildPath(

std::string line;
std::stringstream log_str(log.get());
//LOG(warning) << log_str.str();
int countFull = 0, countPart = 0;

while(std::getline(log_str, line, '\n'))
{
if (line[0] == '+' || line[0] == '-')
// Skip empty lines or non-JSON lines (like debug info "ParallelRun ...")
if (line.empty() || line[0] != '{') continue;

try
{
addSource(line.substr(1), line[0] == '-');
if (line[0] == '+')
{
countFull++;
}
else
{
countPart++;
}
std::stringstream jsonStream(line);
boost::property_tree::ptree pt;
boost::property_tree::read_json(jsonStream, pt);

bool fullyParsed = pt.get<bool>("fullyParsed");
std::string filepath = pt.get<std::string>("filePath");
std::string targetDll = pt.get<std::string>("targetDll");

// Check if it's an error based on 'fullyParsed'
bool isError = !fullyParsed;

addSource(filepath, targetDll, isError);

if (fullyParsed) { countFull++; }
else { countPart++; }
}
catch (const boost::property_tree::json_parser::json_parser_error& e)
{
LOG(warning) << "Failed to parse JSON output from C# parser: " << e.what() << " | Line: " << line;
}
catch (const boost::property_tree::ptree_error& e)
{
LOG(warning) << "Missing expected JSON field from C# parser: " << e.what() << " | Line: " << line;
}
}

Expand All @@ -138,12 +149,12 @@ bool CsharpParser::parseProjectBuildPath(
return result == 0;
}

void CsharpParser::addSource(const std::string& filepath_, bool error_)
void CsharpParser::addSource(const std::string& filepath_, const std::string& targetDll_, bool error_)
{
util::OdbTransaction transaction(_ctx.db);

model::BuildActionPtr buildAction(new model::BuildAction);
buildAction->command = " ";
buildAction->command = "dotnet build ";
buildAction->type = model::BuildAction::Compile;

model::BuildSource buildSource;
Expand Down Expand Up @@ -176,10 +187,6 @@ extern "C"
{
boost::program_options::options_description description("C# Plugin");

description.add_options()
("build-dir,b", po::value<std::string>()->default_value("Build directory"),
"The build directory of the parsed project.");

return description;
}

Expand Down
100 changes: 44 additions & 56 deletions plugins/csharp/parser/src_csharp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using CSharpParser.model;
using System.Xml.Linq;
using System.Text.Json;

namespace CSharpParser
{
class Program
{
//private readonly CsharpDbContext _context;
private static List<string> _rootDir;
private static string _buildDir = "";
private static string _buildDirBase = "";
private static string _connectionString = "";

Expand All @@ -28,11 +28,10 @@ static int Main(string[] args)
try
{
_connectionString = args[0].Replace("'", "");
_buildDir = args[1].Replace("'", "");
_buildDirBase = args[2].Replace("'", "");
threadNum = int.Parse(args[3]);
_buildDirBase = args[1].Replace("'", ""); //indexes
threadNum = int.Parse(args[2]);

for (int i = 4; i < args.Length; ++i)
for (int i = 3; i < args.Length; ++i)
{
_rootDir.Add(args[i].Replace("'", ""));
}
Expand All @@ -42,44 +41,6 @@ static int Main(string[] args)
WriteLine("Error in parsing command!");
return 1;
}
/*if (args.Length < 3)
{
WriteLine("Missing command-line arguments in CSharpParser!");
return 1;
}
else if (args.Length == 3)
{
_connectionString = args[0].Replace("'", "");
_rootDir = args[1].Replace("'", "");
_buildDir = args[2].Replace("'", "");
}
else if (args.Length == 4)
{
_connectionString = args[0].Replace("'", "");
_rootDir = args[1].Replace("'", "");
_buildDir = args[2].Replace("'", "");
bool success = int.TryParse(args[3], out threadNum);
if (!success){
WriteLine("Invalid threadnumber argument! Multithreaded parsing disabled!");
}
}
else if (args.Length == 5)
{
_connectionString = args[0].Replace("'", "");
_rootDir = args[1].Replace("'", "");
_buildDir = args[2].Replace("'", "");
_buildDirBase = args[3].Replace("'", "");
bool success = int.TryParse(args[4], out threadNum);
if (!success)
{
WriteLine("Invalid threadnumber argument! Multithreaded parsing disabled!");
}
}
else if (args.Length > 5)
{
WriteLine("Too many command-line arguments in CSharpParser!");
return 1;
}*/

//Converting the connectionstring into entiy framwork style connectionstring
string csharpConnectionString = transformConnectionString();
Expand All @@ -91,21 +52,35 @@ static int Main(string[] args)
CsharpDbContext _context = new CsharpDbContext(options);
_context.Database.Migrate();


List<string> allFiles = new List<string>();
// This dictionary will remember which file belongs to which DLL
Dictionary<string, string> fileToTargetDll = new Dictionary<string, string>();

foreach (var p in _rootDir)
{
Console.WriteLine(p);
allFiles.AddRange(GetSourceFilesFromDir(p, ".cs"));
}
allFiles = allFiles.Distinct().ToList();

foreach (var f in allFiles)
{
WriteLine(f);
}
IEnumerable<string> assemblies = GetSourceFilesFromDir(_buildDir, ".dll");
IEnumerable<string> assemblies_base = assemblies;
if (args.Length == 5)
assemblies_base = GetSourceFilesFromDir(_buildDirBase, ".dll");


IEnumerable<string> assemblies_base = GetSourceFilesFromDir(_buildDirBase, ".dll"); //loading basic dlls
Comment thread
mcserep marked this conversation as resolved.

List<string> assemblies = new List<string>();
foreach (var p in _rootDir)
{
// We search for all .dll files in all input directories
assemblies.AddRange(GetSourceFilesFromDir(p, ".dll"));
}
// Let's keep only one of each DLL based on the file name!
assemblies = assemblies.GroupBy(x => System.IO.Path.GetFileName(x))
.Select(g => g.First())
.ToList();

List<SyntaxTree> trees = new List<SyntaxTree>();
foreach (string file in allFiles)
Expand All @@ -129,14 +104,14 @@ static int Main(string[] args)
compilation = compilation.AddReferences(MetadataReference.CreateFromFile(file));
}

var runtask = ParalellRun(csharpConnectionString, threadNum, trees, compilation);
var runtask = ParalellRun(csharpConnectionString, threadNum, trees, compilation, fileToTargetDll);
int ret = runtask.Result;

return 0;
}

private static async Task<int> ParalellRun(string csharpConnectionString, int threadNum,
List<SyntaxTree> trees, CSharpCompilation compilation)
List<SyntaxTree> trees, CSharpCompilation compilation, Dictionary<string, string> fileToTargetDll)
{
var options = new DbContextOptionsBuilder<CsharpDbContext>()
.UseNpgsql(csharpConnectionString)
Expand All @@ -156,7 +131,7 @@ private static async Task<int> ParalellRun(string csharpConnectionString, int th
WriteLine(threadNum);
for (int i = 0; i < maxThread; i++)
{
ParsingTasks.Add(ParseTree(contextList[i],trees[i],compilation,i));
ParsingTasks.Add(ParseTree(contextList[i],trees[i],compilation,i,fileToTargetDll));
}

int nextTreeIndex = maxThread;
Expand All @@ -169,7 +144,7 @@ private static async Task<int> ParalellRun(string csharpConnectionString, int th
if (nextTreeIndex < trees.Count)
{
ParsingTasks.Add(ParseTree(contextList[nextContextIndex],
trees[nextTreeIndex],compilation,nextContextIndex));
trees[nextTreeIndex],compilation,nextContextIndex, fileToTargetDll));
++nextTreeIndex;
}
}
Expand All @@ -183,15 +158,28 @@ private static async Task<int> ParalellRun(string csharpConnectionString, int th
}

private static async Task<int> ParseTree(CsharpDbContext context,
SyntaxTree tree, CSharpCompilation compilation, int index)
SyntaxTree tree, CSharpCompilation compilation, int index,
Dictionary<string, string> fileToTargetDll)
{
var ParsingTask = Task.Run(() =>
{
WriteLine("ParallelRun " + tree.FilePath);
SemanticModel model = compilation.GetSemanticModel(tree);
var visitor = new AstVisitor(context, model, tree);
visitor.Visit(tree.GetCompilationUnitRoot());
WriteLine((visitor.FullyParsed ? "+" : "-") + tree.FilePath);
visitor.Visit(tree.GetCompilationUnitRoot());

// Find the DLL name and append a | to the filename.
string target = fileToTargetDll.ContainsKey(tree.FilePath) ? fileToTargetDll[tree.FilePath] : "Unknown.dll";

var resultData = new
{
fullyParsed = visitor.FullyParsed,
filePath = tree.FilePath,
targetDll = target
};

WriteLine(JsonSerializer.Serialize(resultData));

return index;
});
return await ParsingTask;
Expand Down
Loading