/*
* This file is part of PKM (Persistent Knowledge Monitor).
* Copyright (c) 2020 Capgemini Group, Commissariat à l'énergie atomique et aux énergies alternatives,
* OW2, Sysgo AG, Technikon, Tree Technology, Universitat Politècnica de València.
*
* PKM is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation.
*
* PKM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with PKM. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* find in source
*
* @memberof PKM
* @instance
* @param {string} dbName - database name
* @param {string} kind - either 'function', 'variable', 'type', 'filename', 'dir'
* @param {string} [query_value] - query value (optional)
*
* @return {Promise<Array.<Object>>} a promise that passes the result (an array) to resolve callback
*/
function find_in_c_source(dbName, kind, query_value)
{
return new Promise((resolve, reject) =>
{
const debug = this.debug;
this.get_collection(dbName, 'sourcecodeC').then((source_code_collection) =>
{
this.get_collection(dbName, 'RawSourcecode').then((raw_source_code_collection) =>
{
function find_functions_definitions(source_code_collection, raw_source_code_collection, function_name)
{
return new Promise((resolve, reject) =>
{
var results = [];
if(debug) console.warn("Searching AST files for function definition...");
const query = {"globals.GFun.fundec.svar.varinfo.vname": function_name ? function_name : { $exists: true }};
var source_code_cursor = source_code_collection.find(query);
let count = 0;
source_code_cursor.forEach((source_code_document) =>
{
if(Array.isArray(source_code_document.globals))
{
source_code_document.globals.forEach((global) =>
{
if(global.GFun &&
global.GFun.fundec &&
global.GFun.fundec.svar &&
global.GFun.fundec.svar.varinfo &&
(!function_name || (global.GFun.fundec.svar.varinfo.vname == function_name)))
{
var result = {};
count = count + 1;
if(debug) console.warn("> found function definition (" + count + ")");
result.fundef = global.GFun.fundec;
result.files = [];
if(global.GFun.loc && global.GFun.loc.pos_start && global.GFun.loc.pos_start.pos_path)
{
// searching for file associated to the current element:
let filename = global.GFun.loc.pos_start.pos_path;
if(debug) console.warn("> located in file " + filename + " (" + count + ")");
// Find the content of this file
var raw_source_code_cursor = raw_source_code_collection.find({"filename":filename});
if(debug) console.warn("Searching in raw files...");
raw_source_code_cursor.forEach((raw_source_code_document) =>
{
result.files.push(raw_source_code_document.filename);
}, (err) =>
{
if(err)
{
throw err;
}
else
{
results.push(result);
}
});
}
}
});
}
}, (err) =>
{
if(err)
{
reject(this.Error(err));
}
else
{
resolve(results);
}
});
});
}
function find_functions_declarations(source_code_collection, raw_source_code_collection, function_name)
{
return new Promise((resolve, reject) =>
{
var results = [];
// Lookup the GFunDecl
if(debug) console.warn("Searching AST files for function declaration...");
const query = {"globals.GFunDecl.varinfo.vname": function_name ? function_name : { $exists: true }};
var source_code_cursor = source_code_collection.find(query);
// var tab2= element2.toArray(function (err,documents) {
// console.log("> found function declaration (" + documents.length+")");
// });
let count = 0;
source_code_cursor.forEach((source_code_document) =>
{
if(Array.isArray(source_code_document.globals))
{
source_code_document.globals.forEach((global) =>
{
if(global.GFunDecl &&
global.GFunDecl.varinfo &&
(!function_name || (global.GFunDecl.varinfo.vname == function_name)))
{
var result = {};
count = count + 1;
if(debug) console.warn("> found function declaration (" + count + ")");
result.fundecl = global.GFunDecl.funspec;
result.files = [];
if(global.GFunDecl.loc && global.GFunDecl.loc.pos_start && global.GFunDecl.loc.pos_start.pos_path)
{
// searching for file associated to the current element:
let filename = global.GFunDecl.loc.pos_start.pos_path;
if(debug) console.warn("> located in file " + filename + " (" + count + ")");
// Find the content of this file
var raw_source_code_cursor = raw_source_code_collection.find({"filename":filename});
if(debug) console.warn("> Searching in raw files...");
raw_source_code_cursor.forEach((raw_source_code_document) =>
{
result.files.push(raw_source_code_document.filename);
}, (err) =>
{
if(err)
{
throw err;
}
else
{
results.push(result);
}
});
}
}
});
}
}, (err) =>
{
if(err)
{
reject(this.Error(err));
}
else
{
resolve(results);
}
});
});
}
function find_functions(source_code_collection, raw_source_code_collection, function_name)
// Search for function definitions and declarations.
// Returns a JSON document
// [{"fundecl|fundef": <AST>, "filename":"XXX"},...]
// if filename is "" the no file could be found.
{
return new Promise((resolve, reject) =>
{
find_functions_definitions(source_code_collection, raw_source_code_collection, function_name).then((function_definitions_results) =>
{
find_functions_declarations(source_code_collection, raw_source_code_collection, function_name).then((function_declarations_results) =>
{
const find_functions_results = function_definitions_results.concat(function_declarations_results);
if(find_functions_results.length)
{
resolve(find_functions_results);
}
else
{
reject(this.NotFound('No function named \'' + function_name + '\' found'));
}
}).catch((err) =>
{
reject(this.Error(err));
});
}).catch((err) =>
{
reject(this.Error(err));
});
});
}
function find_variable_definitions(source_code_collection, raw_source_code_collection, variable_name)
{
return new Promise((resolve, reject) =>
{
var results = [];
if(debug) console.warn("Searching AST files for variable definition...");
const query = {"globals.GVar.varinfo.vname": variable_name ? variable_name : { $exists: true }};
var source_code_cursor = source_code_collection.find(query);
let count = 0;
source_code_cursor.forEach((source_code_document) =>
{
if(Array.isArray(source_code_document.globals))
{
source_code_document.globals.forEach((global) =>
{
if(global.GVar &&
global.GVar.varinfo &&
(!variable_name || (global.GVar.varinfo.vname == variable_name)))
{
var result = {};
count = count+1;
if(debug) console.warn("> found definition (" + count + ")");
result.varinfo = global.GVar;
result.files = [];
if(global.GVar.loc && global.GVar.loc.pos_start && global.GVar.loc.pos_start.pos_path)
{
// searching for file associated to the current element:
let filename = global.GVar.loc.pos_start.pos_path;
if(debug) console.warn("> located in file " + filename + " (" + count + ")");
// Find the content of this file
var raw_source_code_cursor = raw_source_code_collection.find({"filename":filename});
if(debug) console.warn("Searching in raw files...");
raw_source_code_cursor.forEach((raw_source_code_document) =>
{
result.files.push(raw_source_code_document.filename);
}, (err) =>
{
if(err)
{
throw err;
}
else
{
results.push(result);
}
});
}
}
});
}
}, (err) =>
{
if(err)
{
reject(this.Error(err));
}
else
{
resolve(results);
}
});
});
}
function find_variable_declarations(source_code_collection, raw_source_code_collection, variable_name)
{
return new Promise((resolve, reject) =>
{
var results = [];
// Lookup the GVarDecl
if(debug) console.warn("Searching AST files for variable declaration...");
const query = {"globals.GVarDecl.varinfo.vname": variable_name ? variable_name : { $exists: true }};
var source_code_cursor = source_code_collection.find(query);
let count = 0;
source_code_cursor.forEach((source_code_document) =>
{
if(Array.isArray(source_code_document.globals))
{
source_code_document.globals.forEach((global) =>
{
if(global.GVarDecl &&
global.GVarDecl.varinfo &&
(!variable_name || (global.GVarDecl.varinfo == variable_name)))
{
var result = {};
count = count + 1;
if(debug) console.warn("> found variable declaration (" + count + ")");
result.varinfo = global.GVarDecl.varinfo;
result.files = [];
if(global.GVarDecl.loc && global.GVarDecl.loc.pos_start && global.GVarDecl.loc.pos_start.pos_path)
{
// searching for file associated to the current element:
let filename = global.GVarDecl.loc.pos_start.pos_path;
if(debug) console.warn("> located in file " + filename + " (" + count + ")");
// Find the content of this file
var raw_source_code_cursor = raw_source_code_collection.find({"filename":filename});
if(debug) console.warn("> Searching in raw files...");
raw_source_code_cursor.forEach((raw_source_code_document) =>
{
result.files.push(raw_source_code_document.filename);
}, (err) =>
{
if(err)
{
throw err;
}
else
{
results.push(result);
}
});
}
}
});
}
}, (err) =>
{
if(err)
{
reject(this.Error(err));
}
else
{
resolve(results);
}
});
});
}
function find_variables(source_code_collection, raw_source_code_collection, variable_name)
// Returns a JSON document
// [{"vardef|vardecl": <AST>, "filename":"XXX"},...]
// if filename is "" the no file could be found.
{
return new Promise((resolve, reject) =>
{
find_variable_definitions(source_code_collection, raw_source_code_collection, variable_name).then((variable_definitions_results) =>
{
find_variable_declarations(source_code_collection, raw_source_code_collection, variable_name).then((variable_declarations_results) =>
{
const find_variables_results = variable_definitions_results.concat(variable_declarations_results);
if(find_variables_results.length)
{
resolve(find_variables_results);
}
else
{
reject(this.NotFound('No variable named \'' + variable_name + '\' found'));
}
}).catch((err) =>
{
reject(this.Error(err));
});
}).catch((err) =>
{
reject(this.Error(err));
});
});
}
function find_type_definitions(source_code_collection, raw_source_code_collection, type_name)
// Returns a JSON document
// [{"typedef": <AST>, "filename":"XXX"},...]
// if filename is "" the no file could be found.
{
return new Promise((resolve, reject) =>
{
var results = [];
if(debug) console.warn("Searching AST files for type (Comp/Enum) definition...");
const query = {"globals.GCompTag.compinfo.cname": type_name ? type_name : { $exists: true }};
var source_code_cursor = source_code_collection.find(query);
let count = 0;
source_code_cursor.forEach((source_code_document) =>
{
if(Array.isArray(source_code_document.globals))
{
source_code_document.globals.forEach((global) =>
{
if(global.GCompTag &&
global.GCompTag.compinfo &&
(!type_name || (global.GCompTag.compinfo.cname == type_name)))
{
var result = {};
count = count + 1;
if(debug) console.warn("> found type definition (" + count + ")");
result.typedef = global.GCompTag.compinfo;
result.files = [];
if(global.GCompTag.loc && global.GCompTag.loc.pos_start && global.GCompTag.loc.pos_start.pos_path)
{
// searching for file associated to the current element:
let filename = global.GCompTag.loc.pos_start.pos_path;
if(debug) console.warn("> located in file " + filename + " (" + count + ")");
// Find the content of this file
var raw_source_code_cursor = raw_source_code_collection.find({"filename":filename});
if(debug) console.warn("Searching in raw files...");
raw_source_code_cursor.forEach((raw_source_code_document) =>
{
result.files.push(raw_source_code_document.filename);
}, (err) =>
{
if(err)
{
throw err;
}
else
{
results.push(result);
}
});
}
}
});
}
}, (err) =>
{
if(err)
{
reject(this.Error(err));
}
else
{
resolve(results);
}
});
});
}
function find_type_declarations(source_code_collection, raw_source_code_collection, type_name)
// Returns a JSON document
// [{"typedecl": <AST>, "filename":"XXX"},...]
// if filename is "" the no file could be found.
{
return new Promise((resolve, reject) =>
{
var results = [];
// Lookup the GCompTagDecl
if(debug) console.warn("Searching AST files for type declaration...");
const query = {"globals.GCompTagDecl.compinfo.cname": type_name ? type_name : { $exists: true }};
var source_code_cursor = source_code_collection.find(query);
let count = 0;
source_code_cursor.forEach((source_code_document) =>
{
if(Array.isArray(source_code_document.globals))
{
source_code_document.globals.forEach((global) =>
{
if(global.GCompTagDecl &&
global.GCompTagDecl.compinfo &&
(!type_name || (global.GCompTagDecl.compinfo.cname == type_name)))
{
var result = {};
count = count + 1;
if(debug) console.warn("> found type declaration (" + count + ")");
result.typedecl = global.GCompTagDecl.compinfo;
result.files = [];
if(global.GCompTagDecl.loc && global.GCompTagDecl.loc.pos_start && global.GCompTagDecl.loc.pos_start.pos_path)
{
// searching for file associated to the current element:
let filename = global.GCompTagDecl.loc.pos_start.pos_path;
if(debug) console.warn("> located in file " + filename + " (" + count + ")");
// Find the content of this file
var raw_source_code_cursor = raw_source_code_collection.find({"filename":filename});
if(debug) console.warn("> Searching raw files...");
raw_source_code_cursor.forEach((raw_source_code_document) =>
{
result.files.push(raw_source_code_document.filename);
}, (err) =>
{
if(err)
{
throw err;
}
else
{
results.push(result);
}
});
}
}
});
}
}, (err) =>
{
if(err)
{
reject(this.Error(err));
}
else
{
resolve(results);
}
});
});
}
function find_types(source_code_collection, raw_source_code_collection, type_name)
{
return new Promise((resolve, reject) =>
{
find_type_definitions(source_code_collection, raw_source_code_collection, type_name).then((type_definitions_results) =>
{
find_type_declarations(source_code_collection, raw_source_code_collection, type_name).then((type_declarations_results) =>
{
const find_types_results = type_definitions_results.concat(type_declarations_results);
if(find_types_results.length)
{
resolve(find_types_results);
}
else
{
reject(this.NotFound('No type named \'' + type_name + '\' found'));
}
}).catch((err) =>
{
reject(this.Error(err));
});
}).catch((err) =>
{
reject(this.Error(err));
});
});
}
function find_files(raw_source_code_collection, filename)
{
return new Promise((resolve, reject) =>
{
var results = [];
if(debug) console.warn("Searching for File " + filename + ".");
const query = {"filename" : filename ? filename : { $exists: true }};
var raw_source_code_cursor = raw_source_code_collection.find(query);
if(debug) console.warn("> found files ");
raw_source_code_cursor.forEach((raw_source_code_document) =>
{
results.push(
{
filename : raw_source_code_document.filename,
filecontent : raw_source_code_document.filecontent
}
);
}, (err) =>
{
if(err)
{
reject(this.Error(err));
}
else if(results.length)
{
resolve(results);
}
else
{
reject(this.NotFound('No file named \'' + filename + '\' found'));
}
});
});
}
function find_dir(raw_source_code_collection, dir_name)
{
const path = require ('path');
return new Promise((resolve, reject) =>
{
var results = [];
var raw_source_code_cursor = raw_source_code_collection.find({});
raw_source_code_cursor.forEach((raw_source_code_document) =>
{
let found_dir_name = path.dirname(raw_source_code_document.filename);
if(!dir_name || found_dir_name.startsWith(dir_name))
{
if(debug) console.warn("Found 1 file");
results.push(
{
filename : raw_source_code_document.filename,
filecontent : raw_source_code_document.filecontent
}
);
}
}, (err) =>
{
if(err)
{
reject(this.Error(err));
}
else if(results.length)
{
resolve(results);
}
else
{
reject(this.NotFound('No directory named \'' + dir_name + '\' found'));
}
});
});
}
if(kind == "function")
{
find_functions(source_code_collection, raw_source_code_collection, query_value)
.then((results) => resolve(results))
.catch((err) => reject(this.Error(err)));
}
else if(kind == "variable")
{
find_variables(source_code_collection, raw_source_code_collection, query_value)
.then((results) => resolve(results))
.catch((err) => reject(this.Error(err)));
}
else if(kind == "type")
{
find_types(source_code_collection, raw_source_code_collection, query_value)
.then((results) => resolve(results))
.catch((err) => reject(this.Error(err)));
}
else if(kind == "file")
{
// Extract the file including the raw file content in a JSON document:
// the filename is relative to DB_ROOT.
// Returns: {"filename": "XXX", "filecontent": "YYYY"}
find_files(raw_source_code_collection, query_value)
.then((results) => resolve(results))
.catch((err) => reject(this.Error(err)));
}
else if(kind == "dir")
{
// Extract all source files within the specified dir,in raw form:
// all filenames are relative to DB_ROOT
// Returns: [{"filename":"XXX", "filecontent":"YYY"}, {}, ...]
find_dir(raw_source_code_collection, query_value)
.then((results) => resolve(results))
.catch((err) => reject(this.Error(err)));
}
else
{
reject(this.NotFound('kind not found'));
}
}).catch((err) =>
{
reject(this.Error(err));
});
}).catch((err) =>
{
reject(this.Error(err));
});
});
}
exports.find_in_c_source = find_in_c_source;