private bool AnalyzeChildren()

in src/CTA.Rules.Analysis/RulesAnalysis.cs [103:393]


        private bool AnalyzeChildren(FileActions fileAction, UstList<UstNode> children, int level, string parentNamespace = "", string parentClass = "")
        {
            bool containsActions = false;

            if (children == null || level > Constants.MaxRecursionDepth)
            {
                return false;
            }

            foreach (var child in children)
            {
                try
                {
                    switch (child.NodeType)
                    {
                        case IdConstants.AnnotationIdName:
                            {
                                var annotation = (Annotation)child;
                                var compareToken = new AttributeToken() { Key = annotation.Identifier, Namespace = annotation.Reference.Namespace, Type = annotation.SemanticClassType };
                                _rootNodes.Attributetokens.TryGetValue(compareToken, out var token);
                                if (token != null)
                                {
                                    AddActions(fileAction, token, child.TextSpan);
                                    containsActions = true;
                                }
                                break;
                            }
                        case IdConstants.UsingDirectiveIdName:
                            {
                                var compareToken = new UsingDirectiveToken() { Key = child.Identifier };
                                _rootNodes.Usingdirectivetokens.TryGetValue(compareToken, out var token);
                                if (token != null)
                                {
                                    AddActions(fileAction, token, child.TextSpan);
                                    containsActions = true;
                                }
                                break;
                            }
                        case IdConstants.NamespaceIdName:
                            {
                                var compareToken = new NamespaceToken() { Key = child.Identifier };
                                _rootNodes.NamespaceTokens.TryGetValue(compareToken, out var token);
                                if (token != null)
                                {
                                    AddActions(fileAction, token, child.TextSpan);
                                    containsActions = true;
                                }
                                if (AnalyzeChildren(fileAction, child.Children, ++level, child.Identifier)) { containsActions = true; }
                                break;
                            }
                        case IdConstants.ClassIdName:
                            {
                                var classType = (ClassDeclaration)child;
                                var baseToken = new ClassDeclarationToken() { FullKey = classType.BaseType };
                                _rootNodes.Classdeclarationtokens.TryGetValue(baseToken, out var token);

                                if (token != null)
                                {
                                    //In case of class declarations, add actions on the class by name, instead of property                                
                                    AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan);
                                    AddActions(fileAction, token, child.TextSpan);
                                    containsActions = true;
                                }

                                token = null;
                                string name = string.Concat(classType.Reference != null ? string.Concat(classType.Reference.Namespace, ".") : string.Empty, classType.Identifier);
                                var nameToken = new ClassDeclarationToken() { FullKey = name };
                                _rootNodes.Classdeclarationtokens.TryGetValue(nameToken, out token);

                                if (token != null)
                                {
                                    //In case of class declarations, add actions on the class by name, instead of property                                
                                    AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan);
                                    AddActions(fileAction, token, child.TextSpan);
                                    containsActions = true;
                                }

                                token = null;
                                foreach (string interfaceName in classType.BaseList)
                                {
                                    var baseListToken = new ClassDeclarationToken() { FullKey = interfaceName };
                                    _rootNodes.Classdeclarationtokens.TryGetValue(baseListToken, out token);

                                    if (token != null)
                                    {
                                        AddNamedActions(fileAction, token, classType.Identifier, child.TextSpan);
                                        AddActions(fileAction, token, child.TextSpan);
                                        containsActions = true;
                                    }
                                    token = null;
                                }

                                if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, classType.Identifier)) { containsActions = true; }
                                break;
                            }
                        case IdConstants.InterfaceIdName:
                            {
                                var interfaceType = (InterfaceDeclaration)child;
                                var baseToken = new InterfaceDeclarationToken() { FullKey = interfaceType.BaseType };
                                InterfaceDeclarationToken token = null;

                                if (!string.IsNullOrEmpty(interfaceType.BaseType))
                                {
                                    _rootNodes.InterfaceDeclarationTokens.TryGetValue(baseToken, out token);
                                }

                                if (token != null)
                                {
                                    //In case of interface declarations, add actions on the interface by name, instead of property                                
                                    AddNamedActions(fileAction, token, interfaceType.Identifier, child.TextSpan);
                                    AddActions(fileAction, token, child.TextSpan);
                                    containsActions = true;
                                }

                                token = null;
                                string name = string.Concat(interfaceType.Reference != null ? string.Concat(interfaceType.Reference.Namespace, ".") : string.Empty, interfaceType.Identifier);
                                var nameToken = new InterfaceDeclarationToken() { FullKey = name };
                                _rootNodes.InterfaceDeclarationTokens.TryGetValue(nameToken, out token);

                                if (token != null)
                                {
                                    //In case of interface declarations, add actions on the interface by name, instead of property                                   
                                    AddNamedActions(fileAction, token, interfaceType.Identifier, child.TextSpan);
                                    AddActions(fileAction, token, child.TextSpan);
                                    containsActions = true;
                                }

                                if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace)) { containsActions = true; }
                                break;
                            }
                        case IdConstants.MethodIdName:
                            {
                                var compareToken = new MethodDeclarationToken() { FullKey = string.Concat(child.Identifier) };
                                _rootNodes.MethodDeclarationTokens.TryGetValue(compareToken, out var token);
                                if (token != null)
                                {
                                    AddNamedActions(fileAction, token, child.Identifier, child.TextSpan);
                                    AddActions(fileAction, token, child.TextSpan);
                                    containsActions = true;
                                }
                                if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; }
                                break;
                            }
                        case IdConstants.InvocationIdName:
                            {
                                string overrideKey = string.Empty;

                                InvocationExpression invocationExpression = (InvocationExpression)child;

                                ////If we don't have a semantic analysis, we dont want to replace invocation expressions, otherwise we'll be replacing expressions regardless of their class/namespace
                                if (string.IsNullOrEmpty(invocationExpression.SemanticOriginalDefinition)) break;

                                var compareToken = new InvocationExpressionToken() { Key = invocationExpression.SemanticOriginalDefinition, Namespace = invocationExpression.Reference.Namespace, Type = invocationExpression.SemanticClassType };
                                _rootNodes.Invocationexpressiontokens.TryGetValue(compareToken, out var token);

                                //Attempt a wildcard search, if applicable. This is invocation expression specific because it has to look inside the invocation expressions only
                                if(token == null)
                                {
                                    var wildcardMatches = _rootNodes.Invocationexpressiontokens.Where(i => i.Key.Contains("*"));
                                    if (wildcardMatches.Any())
                                    {
                                        token = wildcardMatches.FirstOrDefault(i => compareToken.Key.WildcardEquals(i.Key) && compareToken.Namespace == i.Namespace && compareToken.Type == i.Type);

                                        if (token != null)
                                        {
                                            //We set the key so that we don't do another wildcard search during replacement, we just use the name as it was declared in the code
                                            overrideKey = compareToken.Key;
                                        }
                                    }
                                    //If the semanticClassType is too specific to apply to all TData types
                                    if(token == null)
                                    {
                                        if(invocationExpression.SemanticClassType.Contains('<'))
                                        {
                                            string semanticClassType = invocationExpression.SemanticClassType.Substring(0,invocationExpression.SemanticClassType.IndexOf('<'));
                                            compareToken = new InvocationExpressionToken() { Key = invocationExpression.SemanticOriginalDefinition, Namespace = invocationExpression.Reference.Namespace, Type = semanticClassType };
                                            _rootNodes.Invocationexpressiontokens.TryGetValue(compareToken, out token);
                                        }
                                    }
                                }

                                if (token != null)
                                {
                                    AddActions(fileAction, token, child.TextSpan, overrideKey);
                                    containsActions = true;
                                }
                                if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; }
                                break;
                            }
                        case IdConstants.ElementAccessIdName:
                            {
                                ElementAccess elementAccess = (ElementAccess)child;
                                var compareToken = new ElementAccessToken()
                                {
                                    Key = elementAccess.Expression,
                                    FullKey = GetFullKey(elementAccess.Reference?.Namespace, elementAccess.SemanticClassType, elementAccess.Expression),
                                    Type = elementAccess.SemanticClassType,
                                    Namespace = elementAccess.Reference?.Namespace
                                };
                                _rootNodes.ElementAccesstokens.TryGetValue(compareToken, out var token);
                                if (token != null)
                                {
                                    AddActions(fileAction, token, child.TextSpan);
                                    containsActions = true;
                                }
                                if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; }
                                break;
                            }

                        case IdConstants.MemberAccessIdName:
                            {
                                MemberAccess memberAccess = (MemberAccess)child;
                                var compareToken = new MemberAccessToken()
                                {
                                    Key = memberAccess.Name,
                                    FullKey = GetFullKey(memberAccess.Reference?.Namespace, memberAccess.SemanticClassType, memberAccess.Name),
                                    Type = memberAccess.SemanticClassType,
                                    Namespace = memberAccess.Reference?.Namespace
                                };
                                _rootNodes.MemberAccesstokens.TryGetValue(compareToken, out var token);
                                if (token != null)
                                {
                                    AddActions(fileAction, token, child.TextSpan);
                                    containsActions = true;
                                }
                                if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; }
                                break;
                            }
                        case IdConstants.DeclarationNodeIdName:
                            {
                                var declarationNode = (DeclarationNode)child;
                                var compareToken = new IdentifierNameToken() { Key = string.Concat(declarationNode.Reference.Namespace, ".", declarationNode.Identifier), Namespace = declarationNode.Reference.Namespace };
                                _rootNodes.Identifiernametokens.TryGetValue(compareToken, out var token);
                                if (token != null)
                                {
                                    AddActions(fileAction, token, child.TextSpan);
                                    containsActions = true;
                                }
                                if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; }
                                break;
                            }
                        case IdConstants.ObjectCreationIdName:
                            {
                                var objectCreationNode = (ObjectCreationExpression)child;
                                //Rules based on Object Creation Parent Hierarchy
                                var compareToken = new ObjectCreationExpressionToken() { Key = objectCreationNode.Identifier, Namespace = objectCreationNode.Reference?.Namespace, Type = objectCreationNode.SemanticClassType };
                                _rootNodes.ObjectCreationExpressionTokens.TryGetValue(compareToken, out var token);
                                if (token != null)
                                {
                                    AddActions(fileAction, token, child.TextSpan);
                                    containsActions = true;
                                }

                                //Rules based on Object Creation location within code
                                var compareTokenLocation = new ObjectCreationExpressionToken() { Key = objectCreationNode.Identifier, Namespace = parentNamespace, Type = parentClass };
                                _rootNodes.ObjectCreationExpressionTokens.TryGetValue(compareTokenLocation, out var tokenLocation);
                                if (tokenLocation != null)
                                {
                                    AddActions(fileAction, tokenLocation, child.TextSpan);
                                    containsActions = true;
                                }

                                token = null;
                                if(!string.IsNullOrEmpty(objectCreationNode.SemanticOriginalDefinition))
                                {
                                    var nameToken = new ObjectCreationExpressionToken() { Key = objectCreationNode.SemanticOriginalDefinition, Namespace = objectCreationNode.SemanticNamespace, Type = objectCreationNode.SemanticClassType };
                                    _rootNodes.ObjectCreationExpressionTokens.TryGetValue(nameToken, out token);
                                    if (token != null)
                                    {
                                        AddActions(fileAction, token, child.TextSpan);
                                        containsActions = true;
                                    }
                                }

                                if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; }
                                break;
                            }
                        default:
                            {
                                if (AnalyzeChildren(fileAction, child.Children, ++level, parentNamespace, parentClass)) { containsActions = true; }
                                break;
                            }
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.LogError(ex, "Error loading actions for item {0} of type {1}", child.Identifier, child.NodeType);
                }
            }
            return containsActions;
        }