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;
}