/// <summary> /// Get source of component/class /// Folder if Element name = Folder name /// Source-File if Element name = 'file name'.c or 'file name'.cpp /// </summary> /// <param name="el"></param> /// <param name="db"></param> /// <param name="getFolder"></param> /// <returns></returns> private static string GetSourceOfComponent(Element el, BROWSEVCDB db, bool getFolder = true) { string fileNameOfClass = (from f in db.Files where f.LeafName.ToLower() == $"{el.Name.ToLower()}.c" || f.LeafName.ToLower() == $"{el.Name.ToLower()}.h" || f.LeafName.ToLower() == $"{el.Name.ToLower()}.cpp" || f.LeafName.ToLower() == $"{el.Name.ToLower()}.hpp" || f.LeafName.ToLower() == $"{el.Name.ToLower()}.a2l" || f.LeafName.ToLower().StartsWith($"{ el.Name.ToLower()}_") orderby f.Name.Length select f.Name).FirstOrDefault(); if (fileNameOfClass == null) { MessageBox.Show($"Search for filename\r\n'{el.Name}' and extensions *.c,*.h,*.hpp, *.cpp\r\n'{el.Name}_'", $"Can't find source folder for '{el.Name}', Choose folder"); return(""); } // try to get folder name string folderNameOfClass = Path.GetDirectoryName(fileNameOfClass); if (Path.GetFileName(folderNameOfClass)?.ToLower() != el.Name.ToLower()) { folderNameOfClass = Directory.GetParent(folderNameOfClass).FullName; } if (Path.GetFileName(folderNameOfClass).ToLower() != el.Name.ToLower()) { folderNameOfClass = Directory.GetParent(folderNameOfClass).FullName; } if (Path.GetFileName(folderNameOfClass).ToLower() != el.Name.ToLower()) { folderNameOfClass = Directory.GetParent(folderNameOfClass).FullName; } // Folder not found, check if *.c,*.cpp file exists // Try the source file if the folder isn't the component / class name if (Path.GetFileName(folderNameOfClass).ToLower() != el.Name.ToLower()) { if (fileNameOfClass.ToLower().EndsWith($"{el.Name}.c".ToLower()) || fileNameOfClass.ToLower().EndsWith($"{el.Name}.cpp".ToLower()) ) { return(fileNameOfClass); } MessageBox.Show($"Checked file extensions (*.c,*.h,*.hpp,*.cpp)\r\nLast checked:{folderNameOfClass}", $"Can't find source folder for '{el.Name}', Break!!"); return(""); } return(folderNameOfClass); }
/// <summary> /// Get path of source folder VC Code SQLite Symbol table /// </summary> /// <param name="folderPathSource"></param> /// <returns>"" if nothing found</returns> private static string GetPath(string folderPathSource) { // get the newest db paths as string // - of every release history // - of every source folder supported by VS Code IEnumerable <string> vcDbs = (from f in Directory.GetFiles(GetVcPathSymbolDataBases(), "*.DB", SearchOption.AllDirectories) group f by Path.GetDirectoryName(f) into grpDir let newest = grpDir.Max(d => File.GetLastWriteTime(d)) from n in grpDir where File.GetLastWriteTime(n) == newest select n); foreach (var vcDb in vcDbs) { string connectionString = $"DataSource={vcDb};Read Only=True;"; using (BROWSEVCDB dc = new BROWSEVCDB(new SQLiteDataProvider("SQLite.Classic"), connectionString)) { try { var path = (from f in dc.Files where f.Name.ToLower().Contains(folderPathSource.ToLower()) where f.LeafName.EndsWith("c") orderby f.Name.Length select f.Name).FirstOrDefault(); if (path != null) { return(vcDb); } } catch (Exception e) { MessageBox.Show($@"Data Source: '{vcDb}' Connection: {connectionString} {e}", "Can't install SQLite database driver"); } } } return(""); }
public bool ShowFunctions(string folderPathCSourceCode) { // get connection string of repository // the provider to connect to database like Access, .. _folderRoot = folderPathCSourceCode; string connectionString = LinqUtil.GetConnectionString(folderPathCSourceCode, out IDataProvider provider, withErrorMessage: true); if (connectionString == "") { return(false); } using (BROWSEVCDB db = new BROWSEVCDB(provider, connectionString)) { folderPathCSourceCode = folderPathCSourceCode.ToUpper(); // Get all functions of implementation // store it to list to avoid SQL with something not possible via SQL // Currently there is a bug in VC-Code which ignores some c-files because of lacking #include files. var allFunctionsImpl1 = (from f in db.CodeItems join file in db.Files on f.FileId equals file.Id where f.Kind == 22 && (f.Name != "TASK" && f.Name != "ISR") && file.Name.Contains(folderPathCSourceCode) && ( file.LeafName.EndsWith(".C") || file.LeafName.EndsWith(".CPP") || file.LeafName.EndsWith(".H") || file.LeafName.EndsWith(".HPP") ) select new ImplFunctionItem("", f.Name, file.Name, (int)f.StartLine, (int)f.StartColumn, (int)f.EndLine, (int)f.EndColumn)).ToList() .Union( (from f in db.CodeItems join param in db.CodeItems on f.Id equals param.ParentId join file in db.Files on f.FileId equals file.Id where f.Kind == 22 && (f.Name == "TASK" || f.Name == "ISR") && (f.EndLine - f.StartLine) > 2 && // filter out extern..... file.Name.Contains(folderPathCSourceCode) && ( file.LeafName.EndsWith(".C") || file.LeafName.EndsWith(".CPP") || file.LeafName.EndsWith(".H") || file.LeafName.EndsWith(".HPP") ) select new ImplFunctionItem("", $"{f.Name}({param.Type})", file.Name, (int)f.StartLine, (int)f.StartColumn, (int)f.EndLine, (int)f.EndColumn, (int)f.Id)).ToList()); ; // Filter multiple function names var allFunctionsImpl = (from f in allFunctionsImpl1 orderby f.Implementation, f.FileName group f by new { a = f.Implementation, b = f.FileName.Substring(0, f.FileName.Length - 3) } into gs select gs.First()).ToList(); // get all implementations (C_Functions) // - Macro with Implementation // - Implementation without Macro // - Macro without implementation IEnumerable <ImplFunctionItem> allImplementations = ( // Implemented Interfaces (Macro with Interface and implementation with different name) from m in _macros join f in allFunctionsImpl on m.Key equals f.Implementation select new ImplFunctionItem(m.Value, m.Key, f.FilePath, f.LineStart, f.ColumnStart, f.LineEnd, f.ColumnEnd, true)) .Union (from f in allFunctionsImpl where _macros.All(m => m.Key != f.Implementation) select new ImplFunctionItem(f.Implementation, "", f.FilePath.Substring(_folderRoot.Length), f.LineStart, f.ColumnStart, f.LineEnd, f.ColumnEnd, false)) .Union // macros without implementation (from m in _macros where allFunctionsImpl.All(f => m.Key != f.Implementation) select new ImplFunctionItem(m.Value, m.Key, "", 0, 0, 0, 0, true)); string[] ignoreList = { @"_" }; _dtFunctions = (from f in allImplementations where ignoreList.All(l => !f.Interface.StartsWith(l)) // handle ignore list orderby(f.Interface) select f) .ToDataTable(); // new component if (_frmFunctions == null || _frmFunctions.IsDisposed) { _frmFunctions = new FrmFunctions(); } _frmFunctions.ChangeFolder(connectionString, folderPathCSourceCode, _dtFunctions); _frmFunctions.Show(); } return(true); }
/// <summary> /// Show all interfaces (provided/required) for this Component/Class /// - Provided (declaration on in header file /// -- Defined functions which start with Component-Name /// -- Defined functions per macro (#define NAME_functionname implName) /// - Required /// -- Called functions defined outside the component /// -- Takes macros in account /// </summary> /// <param name="el"></param> /// <param name="folderRoot">Root folder patch of C/C++ source code</param> /// <param name="fileFolderToAnalyze"></param> /// <returns></returns> public bool ShowInterfacesOfElement(EA.Element el, string folderRoot, string fileFolderToAnalyze = "") { // get connection string of repository // the provider to connect to database like Access, .. _folderRoot = folderRoot; string connectionString = LinqUtil.GetConnectionString(folderRoot, out IDataProvider provider); using (BROWSEVCDB db = new BROWSEVCDB(provider, connectionString)) { // Estimate file name of component if (el == null && fileFolderToAnalyze == "") { MessageBox.Show("You should select Element or a file/folder", "Nothing selected"); return(false); } string modName = "xxxxxx"; if (el != null) { modName = $"{el.Name.ToLower()}_"; } var folderNameOfClass = fileFolderToAnalyze != "" ? fileFolderToAnalyze : GetSourceOfComponent(el, db); if (folderNameOfClass == "") { return(false); } // estimate file names of component // Component and Module implementation file names beneath folder IQueryable <string> fileNamesOfClassTree = from f in db.Files where f.Name.StartsWith(folderNameOfClass) && (f.LeafName.EndsWith(".c") || f.LeafName.ToLower().EndsWith(".cpp")) select f.Name; // Get all functions of implementation // store it to list to avoid SQL with something not possible via SQL var allFunctionsImpl1 = (from f in db.CodeItems join file in db.Files on f.FileId equals file.Id where f.Kind == 22 && (f.Name != "TASK" && f.Name != "ISR") && (f.EndLine - f.StartLine) > 2 && // filter out extern..... file.Name.ToLower().Contains(folderRoot) && ( file.LeafName.ToLower().EndsWith(".c") || file.LeafName.ToLower().EndsWith(".cpp") || file.LeafName.ToLower().EndsWith(".h") || file.LeafName.ToLower().EndsWith(".hpp") ) select new ImplFunctionItem("", f.Name, file.Name, (int)f.StartLine, (int)f.StartColumn, (int)f.EndLine, (int)f.EndColumn, (int)f.Id)).ToList() // Task and ISR .Union( (from f in db.CodeItems join param in db.CodeItems on f.Id equals param.ParentId join file in db.Files on f.FileId equals file.Id where f.Kind == 22 && (f.Name == "TASK" || f.Name == "ISR") && (f.EndLine - f.StartLine) > 2 && // filter out extern..... file.Name.ToLower().Contains(folderRoot) && ( file.LeafName.ToLower().EndsWith(".c") || file.LeafName.ToLower().EndsWith(".cpp") || file.LeafName.ToLower().EndsWith(".h") || file.LeafName.ToLower().EndsWith(".hpp") ) select new ImplFunctionItem("", $"{f.Name}({param.Type})", file.Name, (int)f.StartLine, (int)f.StartColumn, (int)f.EndLine, (int)f.EndColumn, (int)f.Id)).ToList() ); // Filter multiple function names // If #includes aren't correct VS Code has some issues. var allFunctionsImpl = (from f in allFunctionsImpl1 orderby f.Implementation, f.FileName group f by new { a = f.Implementation, b = f.FileName.Substring(0, f.FileName.Length - 3) } into gs select gs.First()).ToList(); // Check macros //DataTable tMacro = _macros.OrderBy(x=>x.Key).ToDataTable(); //DataTable tx = ( // // Implemented Interfaces (Macro with Interface and implementation with different name) // from m in _macros // join f in allFunctionsImpl on m.Key equals f.Implementation // where f.FilePath.StartsWith(folderNameOfClass) // //where m.Value.ToLower().StartsWith(modName) // select new ImplFunctionItem(m.Value, m.Key, f.FilePath, f.LineStart, f.ColumnStart, f.LineEnd, // f.ColumnEnd)).ToDataTable(); IEnumerable <ImplFunctionItem> allCompImplementations = ( // Implemented Interfaces (Macro with Interface and implementation with different name) from m in _macros join f in allFunctionsImpl on m.Key equals f.Implementation where f.FilePath.StartsWith(folderNameOfClass) //where m.Value.ToLower().StartsWith(modName) select new ImplFunctionItem(m.Value, m.Key, f.FilePath, f.LineStart, f.ColumnStart, f.LineEnd, f.ColumnEnd)) .Union // all C-Implementations (from f in allFunctionsImpl where f.FilePath.StartsWith(folderNameOfClass) where _macros.All(m => m.Key != f.Implementation) select new ImplFunctionItem(f.Implementation, f.Implementation, f.FilePath, f.LineStart, f.ColumnStart, f.LineEnd, f.ColumnEnd)) .Union // macros without implementation, no link to path macro definition available (from m in _macros where m.Value.ToLower().StartsWith(modName) && allFunctionsImpl.All(f => m.Key != f.Implementation) select new ImplFunctionItem(m.Value, m.Key, "", 0, 0, 0, 0)); // get all implementations (C_Functions) // - Macro with Implementation // - Implementation without Macro // - Macro without implementation IEnumerable <ImplFunctionItem> allImplementations = ( // Implemented Interfaces (Macro with Interface and implementation with different name) from m in _macros join f in allFunctionsImpl on m.Key equals f.Implementation select new ImplFunctionItem(m.Value, m.Key, f.FilePath, f.LineStart, f.ColumnStart, f.LineEnd, f.ColumnEnd)) .Union( // Implementation without macros (from f in allFunctionsImpl where _macros.All(m => m.Key != f.Implementation) select new ImplFunctionItem(f.Implementation, f.Implementation, f.FilePath, f.LineStart, f.ColumnStart, f.LineEnd, f.ColumnEnd)) ) .Union // macros without implementation (from m in _macros where allFunctionsImpl.All(f => m.Key != f.Implementation) select new ImplFunctionItem(m.Value, m.Key, "", 0, 0, 0, 0)); // Test purposes //DataTable dt = allCompImplementations.ToDataTable(); //----------------------------------------- DataTable dtProvidedInterface = ShowProvidedInterface(db, folderNameOfClass, fileNamesOfClassTree, allCompImplementations); DataTable dtRequiredInterface = ShowRequiredInterface(db, folderNameOfClass, fileNamesOfClassTree, allImplementations); // new component if (_frm == null || _frm.IsDisposed) { _frm = new FrmComponentFunctions(connectionString, Rep, el, folderRoot, folderNameOfClass, dtProvidedInterface, dtRequiredInterface); _frm.Show(); } else { _frm.ChangeComponent(connectionString, Rep, el, _folderRoot, folderNameOfClass, dtProvidedInterface, dtRequiredInterface); _frm.Show(); _frm.BringToFront(); } return(true); } }
/// <summary> /// Generate provided Interface. All functions called from not component modules /// - /// </summary> /// <param name="db"></param> /// <param name="folderNameOfClass"></param> /// <param name="fileNamesOfClassTree"></param> /// <param name="allCompImplementations"></param> /// <returns></returns> private static DataTable ShowProvidedInterface(BROWSEVCDB db, string folderNameOfClass, IQueryable <string> fileNamesOfClassTree, IEnumerable <ImplFunctionItem> allCompImplementations) { var compImplementations = (from f in allCompImplementations where f.FilePath.StartsWith(folderNameOfClass) || f.FilePath == "" select new { Imp = new ImplFunctionItem(f.Interface, f.Implementation, f.FilePath, "", f.LineStart), // Rx to find a call to function, should be fast, later detailed test // 'function(' RxImplementation = new Regex($@"\b{f.Implementation}\s*\("), RxInterface = new Regex($@"\b{f.Interface}\s*\(") }).ToArray(); // over all files except Class/Component Tree (files not part of component/class/sub folder) IQueryable <string> fileNamesCalledImplementation = (from f in db.Files where !fileNamesOfClassTree.Any(x => x == f.Name) && (f.LeafName.ToLower().EndsWith(".c") || f.LeafName.ToLower().EndsWith(".cpp")) select f.Name).Distinct(); foreach (var fileName in fileNamesCalledImplementation) { if (!File.Exists(fileName)) { MessageBox.Show($@"File:{Environment.NewLine}'{fileName}'{Environment.NewLine}{Environment.NewLine}Root:{Environment.NewLine}{_folderRoot}", @"Can't open implementation of provided interface, skip!!!"); continue; } // only files in implementation if (fileName.ToLower().Contains(_folderRoot.ToLower())) { string code = HoService.DeleteComment(HoUtil.ReadAllText(fileName)); foreach (var f1 in compImplementations) { if (f1.RxImplementation.IsMatch(code) || f1.RxInterface.IsMatch(code)) { Regex rx = f1.Imp.Implementation == f1.Imp.Interface ? new Regex($@"^.*\b{f1.Imp.Implementation}\s*\([^}}{{;]*;", RegexOptions.Multiline) : new Regex($@"^.*\b({f1.Imp.Implementation}|{f1.Imp.Interface})\s*\([^}}{{;]*;", RegexOptions.Multiline); Match match = rx.Match(code); while (match.Success) { // That's not an call to a function if (match.Value.Trim().StartsWith("FUNC(") || match.Value.Trim().StartsWith("void ") || match.Value.Trim().StartsWith("static ") || match.Value.Trim().StartsWith("extern ")) { match = match.NextMatch(); continue; } f1.Imp.FilePathCallee = fileName; break; } //f1.Imp.FilePathCallee = fileName; } } } } // Sort: Function, FileName var outputList = (from f in compImplementations orderby f.Imp.Interface, f.Imp.Implementation select new { Interface = f.Imp.Interface, Implementation = f.Imp.Implementation == f.Imp.Interface ? "" : f.Imp.Implementation, FileName = f.Imp.FileName, FileNameCallee = f.Imp.FileNameCallee, // no root path FilePath = f.Imp.FilePath.Length > _folderRoot.Length ? f.Imp.FilePath.Substring(_folderRoot.Length) : "", FilePathCallee = f.Imp.FilePathCallee.Length > _folderRoot.Length ? f.Imp.FilePathCallee.Substring(_folderRoot.Length) : "", isCalled = f.Imp.IsCalled, LineStart = f.Imp.LineStart }).Distinct(); return(outputList.ToDataTable()); }
/// <summary> /// Get all required Interfaces of Component (root folder of component) /// </summary> /// <param name="db"></param> /// <param name="folderNameOfClass"></param> /// <param name="filesPathOfClassTree"></param> /// <param name="allImplementations"></param> /// <returns></returns> private static DataTable ShowRequiredInterface(BROWSEVCDB db, string folderNameOfClass, IQueryable <string> filesPathOfClassTree, IEnumerable <ImplFunctionItem> allImplementations) { // Estimate all possible function calls of passed files Regex rx = new Regex(@"(\b[A-Z]\w*_\w*)\s*\(", RegexOptions.IgnoreCase); List <CallFunctionItem> lFunctionCalls = new List <CallFunctionItem>(); foreach (var file in filesPathOfClassTree) { // only files that are in source folder, no library files. if (file.ToLower().Contains(_folderRoot.ToLower())) { string code = HoService.DeleteComment(HoUtil.ReadAllText(file)); Match match = rx.Match(code); while (match.Success) { lFunctionCalls.Add(new CallFunctionItem(match.Groups[1].Value, file)); match = match.NextMatch(); } } } // ignore the following function names (beginning) string[] ignoreList = { "Rte_Read", "Rte_Write", "Rte_Invalidate", "L2A_Rte_Read", "L2A_Rte_Write", "L2A_Rte_Invalidate", "L2B_Rte_Read", "L2B_Rte_Write", "L2B_Rte_Invalidate", "L2C_Rte_Read", "L2C_Rte_Write", "L2C_Rte_Invalidate" }; // filter only function implementation // - not current folder/subfolder (current component, required) // - not to ignore according to ignore list var filteredFunctions = (from f in lFunctionCalls join fAll in allImplementations on f.Function equals fAll.Implementation where (!fAll.FilePath.StartsWith(folderNameOfClass)) && ignoreList.All(l => !f.Function.StartsWith(l)) // handle ignore list orderby fAll.Implementation select new { Interface = fAll.Interface, Implementation = fAll.Implementation, FilePathImplementation = fAll.FilePath, FilePathCallee = f.FilePath, // no implementation available yet isCalled = false, LineStart = fAll.LineStart, LineEnd = fAll.LineEnd, ColumnEnd = fAll.ColumnEnd }).Distinct(); // check if filtered functions are implemented List <ImplFunctionItem> filteredImplemtedFunctions = new List <ImplFunctionItem>(); foreach (var f in filteredFunctions) { if (!File.Exists(f.FilePathImplementation)) { MessageBox.Show($"File:\r\n'{f.FilePathImplementation}'\r\n\r\nRoot:\r\n{_folderRoot}", "Can't open implementation of required interface, skip interface!!!"); continue; } string[] codeLines = File.ReadAllLines(f.FilePathImplementation); // declaration ends with ';' // implementation ends with '}' //codeLines[f.Line - 1].Dump(); if (f.LineEnd > 0 && f.ColumnEnd > 0) { string line = codeLines[f.LineEnd - 1]; if (line.Length > 0) { if (line.Substring(f.ColumnEnd - 1, 1) != ";") { filteredImplemtedFunctions.Add(new ImplFunctionItem( f.Interface, f.Interface == f.Implementation ? "" : f.Implementation, // no root path f.FilePathImplementation.Length > _folderRoot.Length ? f.FilePathImplementation.Substring(_folderRoot.Length) : "", f.FilePathCallee.Length > _folderRoot.Length ? f.FilePathCallee.Substring(_folderRoot.Length): "", f.LineStart)); } } } } return(filteredImplemtedFunctions.ToDataTable()); }