private void SetPorts(ClassDeclarationSyntax classNode, AbstractionModel model, bool isInputPort = false) { try { if (isInputPort) { var parser = new CodeParser(); var baseList = (parser.GetBaseObjects(classNode)); var portNodeList = (baseList.First() as BaseListSyntax)?.Types.ToList(); if (portNodeList == null) { return; } var portSyntaxNodes = portNodeList.Where(n => MatchStartOfString(n.ToString(), ProgrammingParadigms)); var docLines = model.SourceCode.Split(new [] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); var classDeclaration = docLines.First(line => line.Trim().Contains($"class {model.Type}")); var implementedPortNames = new List <string>(); if (classDeclaration.Contains("//")) { // Get implemented port names // string implementedPortsInlineComment = baseList.LastOrDefault()?.GetTrailingTrivia().ToString().Trim(new []{' ', '/', '\r', '\n'}) ?? ""; var implementedPortsInlineComment = classDeclaration.Split(new[] { "//" }, StringSplitOptions.RemoveEmptyEntries).LastOrDefault(); if (!string.IsNullOrEmpty(implementedPortsInlineComment)) { implementedPortNames = implementedPortsInlineComment.Split(new[] { ", " }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToList(); } } var modelGenerics = model.GetGenerics(); var implementedPortCount = 0; foreach (var portSyntaxNode in portSyntaxNodes) { var port = new Port() { Type = portSyntaxNode.Type.ToString() }; if (implementedPortCount < implementedPortNames.Count) { port.Name = implementedPortNames[implementedPortCount]; } else { port.Name = "?" + port.Type; } // Handle reverse ports (e.g. IDataFlowB and IEventB) // var typeWithoutGenerics = TypeWithoutGenerics(port.Type); // port.IsReversePort = typeWithoutGenerics.EndsWith("B"); port.IsReversePort = IsReversePort(port.Type); if (port.IsReversePort) { port.IsInputPort = false; model.AddAcceptedPort(port.Type, port.Name, true); } else { port.IsInputPort = true; model.AddImplementedPort(port.Type, port.Name); } var indexList = new List <int>(); if (portSyntaxNode.Type is GenericNameSyntax gen) { var portGenerics = gen .DescendantNodesAndSelf().OfType <GenericNameSyntax>() .SelectMany(n => n.TypeArgumentList.Arguments.Select(a => a.ToString())) .ToHashSet(); foreach (var portGeneric in portGenerics) { var index = modelGenerics.IndexOf(portGeneric); if (index != -1) { indexList.Add(index); } } } model.AddPortGenericIndices(port.Name, indexList); implementedPortCount++; } } else { var parser = new CodeParser() { AccessLevel = "private" }; var privateFields = parser.GetFields(classNode); var portSyntaxNodes = privateFields.Where(n => n is FieldDeclarationSyntax field && (MatchStartOfString(field.Declaration.Type.ToString(), ProgrammingParadigms) || MatchStartOfString(field.Declaration.Type.ToString(), ProgrammingParadigms, prefix: "List<"))) .Select(s => s as FieldDeclarationSyntax); var modelGenerics = model.GetGenerics(); foreach (var portSyntaxNode in portSyntaxNodes) { var port = new Port() { Type = portSyntaxNode.Declaration.Type.ToString(), Name = portSyntaxNode.Declaration.Variables.First().Identifier.ToString(), }; port.Description = portSyntaxNode.HasLeadingTrivia ? ParsePortDocumentation(portSyntaxNode.GetLeadingTrivia().ToString()) : ""; // Handle reverse ports (e.g. IDataFlowB and IEventB) // var typeWithoutGenerics = TypeWithoutGenerics(port.Type); // port.IsReversePort = typeWithoutGenerics.EndsWith("B"); port.IsReversePort = IsReversePort(port.Type); if (port.IsReversePort) { port.IsInputPort = true; model.AddImplementedPort(port.Type, port.Name, isReversePort: true, description: port.Description); } else { port.IsInputPort = false; model.AddAcceptedPort(port.Type, port.Name, description: port.Description); } var indexList = new List <int>(); if (portSyntaxNode.Declaration.Type is GenericNameSyntax gen) { var portGenerics = gen .DescendantNodesAndSelf().OfType <GenericNameSyntax>() .SelectMany(n => n.TypeArgumentList.Arguments.Select(a => a.ToString()).Where(a => modelGenerics.Contains(a))) .ToHashSet(); foreach (var portGeneric in portGenerics) { var index = modelGenerics.IndexOf(portGeneric); if (index != -1) { indexList.Add(index); } } } model.AddPortGenericIndices(port.Name, indexList); } } } catch (Exception e) { Logging.Log($"Failed to set {(isInputPort ? "implemented" : "accepted")} ports in AbstractionModelManager.\nError: {e}"); } }