using Codelyzer.Analysis.Common; using Codelyzer.Analysis.VisualBasic.Handlers; using Codelyzer.Analysis.Model; using Microsoft.CodeAnalysis; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; namespace Codelyzer.Analysis.VisualBasic { /// /// Processor that traverses the Syntax tree nodes /// public class VisualBasicRoslynProcessor : VisualBasicSyntaxVisitor, IDisposable { private readonly CodeContext _context; protected SemanticModel SemanticModel { get => _context.SemanticModel; } protected SyntaxTree SyntaxTree { get => _context.SyntaxTree; } protected ILogger Logger { get => _context.Logger; } protected MetaDataSettings MetaDataSettings { get => _context.AnalyzerConfiguration.MetaDataSettings; } protected RootUstNode RootNode { get; set; } public VisualBasicRoslynProcessor(CodeContext context) { _context = context; } /// /// Start traversing the syntax tree /// /// The node to start the traversal from /// [return: MaybeNull] public override UstNode Visit(SyntaxNode node) { if (node == null) { return null; } if (RootNode == null) { RootNode = new RootUstNode(); } var children = new List(); foreach (SyntaxNode child in node.ChildNodes()) { var result = HandleGenericVisit(child); if (result != null) { children.Add(result); } } RootNode.SetPaths(_context.SourceFilePath, SyntaxTree.FilePath); RootNode.Language = node.Language; RootNode.Children.AddRange(children); AssignParentNode(RootNode.Children, RootNode); return RootNode; } [return: MaybeNull] public override UstNode DefaultVisit(SyntaxNode node) { return null; } /* ---- Overrides ----------------------*/ public override UstNode VisitImportsStatement(ImportsStatementSyntax node) { ImportsStatementHandler handler = new ImportsStatementHandler(_context, node); return handler.UstNode; } public override UstNode VisitClassBlock(ClassBlockSyntax node) { ClassBlockHandler handler = new ClassBlockHandler(_context, node); return handler.UstNode; } public override UstNode VisitClassStatement(ClassStatementSyntax node) { ClassStatementHandler handler = new ClassStatementHandler(_context, node); return handler.UstNode; } public override UstNode VisitFieldDeclaration(FieldDeclarationSyntax node) { FieldDeclarationHandler handler = new FieldDeclarationHandler(_context, node); return handler.UstNode; } public override UstNode VisitVariableDeclarator(VariableDeclaratorSyntax node) { VariableDeclaratorHandler handler = new VariableDeclaratorHandler(_context, node); return handler.UstNode; } public override UstNode VisitAttributeList(AttributeListSyntax node) { if (!MetaDataSettings.Annotations) return null; AttributeListHandler handler = new AttributeListHandler(_context, node); return handler.UstNode; } public override UstNode VisitConstructorBlock(ConstructorBlockSyntax node) { ConstructorBlockHandler handler = new ConstructorBlockHandler(_context, node); return handler.UstNode; } public override UstNode VisitInvocationExpression(InvocationExpressionSyntax node) { if (!MetaDataSettings.MethodInvocations) return null; InvocationExpressionHandler handler = new InvocationExpressionHandler(_context, node); HandleReferences(((InvocationExpression)handler.UstNode).Reference); return handler.UstNode; } public override UstNode VisitExpressionStatement(ExpressionStatementSyntax node) { return base.VisitExpressionStatement(node); } public override UstNode VisitMethodBlock(MethodBlockSyntax node) { MethodBlockHandler handler = new MethodBlockHandler(_context, node); return handler.UstNode; } public override UstNode VisitMethodStatement(MethodStatementSyntax node) { MethodStatementHandler handler = new MethodStatementHandler(_context, node); return handler.UstNode; } public override UstNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node) { MemberAccessExpressionHandler handler = new MemberAccessExpressionHandler(_context, node); return handler.UstNode; } public override UstNode VisitEndBlockStatement(EndBlockStatementSyntax node) { EndBlockStatementHandler handler = new EndBlockStatementHandler(_context, node); return handler.UstNode; } public override UstNode VisitArgumentList(ArgumentListSyntax node) { if (!MetaDataSettings.InvocationArguments) return null; ArgumentListHandler handler = new ArgumentListHandler(_context, node); return handler.UstNode; } public override UstNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node) { LocalDeclarationStatementHandler handler = new LocalDeclarationStatementHandler(_context, node); return handler.UstNode; } public override UstNode VisitReturnStatement(ReturnStatementSyntax node) { ReturnStatementHandler handler = new ReturnStatementHandler(_context, node); return handler.UstNode; } public override UstNode VisitPropertyBlock(PropertyBlockSyntax node) { PropertyBlockHandler handler = new PropertyBlockHandler(_context, node); return handler.UstNode; } public override UstNode VisitPropertyStatement(PropertyStatementSyntax node) { PropertyStatementHandler handler = new PropertyStatementHandler(_context, node); return handler.UstNode; } public override UstNode VisitAccessorBlock(AccessorBlockSyntax node) { AccessorBlockHandler handler = new AccessorBlockHandler(_context, node); return handler.UstNode; } public override UstNode VisitAccessorStatement(AccessorStatementSyntax node) { AccessorStatementHandler handler = new AccessorStatementHandler(_context, node); return handler.UstNode; } public override UstNode VisitModuleBlock(ModuleBlockSyntax node) { ModuleBlockHandler handler = new ModuleBlockHandler(_context, node); return handler.UstNode; } public override UstNode VisitModuleStatement(ModuleStatementSyntax node) { ModuleStatementHandler handler = new ModuleStatementHandler(_context, node); return handler.UstNode; } public override UstNode VisitImplementsStatement(ImplementsStatementSyntax node) { ImplementsStatementHandler handler = new ImplementsStatementHandler(_context, node); return handler.UstNode; } public override UstNode VisitMultiLineIfBlock(MultiLineIfBlockSyntax node) { MultiLineIfBlockHandler handler = new MultiLineIfBlockHandler(_context, node); return handler.UstNode; } public override UstNode VisitIfStatement(IfStatementSyntax node) { IfStatementHandler handler = new IfStatementHandler(_context, node); return handler.UstNode; } public override UstNode VisitBinaryExpression(BinaryExpressionSyntax node) { BinaryExpressionHandler handler = new BinaryExpressionHandler(_context, node); return handler.UstNode; } public override UstNode VisitElseBlock(ElseBlockSyntax node) { ElseBlockHandler handler = new ElseBlockHandler(_context, node); return handler.UstNode; } public override UstNode VisitElseStatement(ElseStatementSyntax node) { ElseStatementHandler handler = new ElseStatementHandler(_context, node); return handler.UstNode; } public override UstNode VisitEnumBlock(EnumBlockSyntax node) { if (MetaDataSettings.EnumDeclarations) { EnumBlockHandler handler = new EnumBlockHandler(_context, node); if (!string.IsNullOrEmpty(handler.UstNode.Identifier)) { HandleReferences(((EnumBlock)handler.UstNode).Reference); return handler.UstNode; } } return null; } public override UstNode VisitEnumStatement(EnumStatementSyntax node) { if (MetaDataSettings.EnumDeclarations) { EnumStatementHandler handler = new EnumStatementHandler(_context, node); return handler.UstNode; } return null; } public override UstNode VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) { EnumMemberDeclarationHandler handler = new EnumMemberDeclarationHandler(_context, node); return handler.UstNode; } public override UstNode VisitIdentifierName(IdentifierNameSyntax node) { if (MetaDataSettings.DeclarationNodes) { IdentifierNameHandler handler = new IdentifierNameHandler(_context, node); if (!string.IsNullOrEmpty(handler.UstNode.Identifier)) { HandleReferences(((DeclarationNode)handler.UstNode).Reference); return handler.UstNode; } } return null; } public override UstNode VisitLiteralExpression(LiteralExpressionSyntax node) { if (!MetaDataSettings.LiteralExpressions) return null; LiteralExpressionHandler handler = new LiteralExpressionHandler(_context, node); return handler.UstNode; } public override UstNode VisitSingleLineLambdaExpression(SingleLineLambdaExpressionSyntax node) { if (!MetaDataSettings.LambdaMethods) return null; var handler = new SingleLineLambdaExpressionHandler(_context, node); return handler.UstNode; } public override UstNode VisitMultiLineLambdaExpression(MultiLineLambdaExpressionSyntax node) { if (!MetaDataSettings.LambdaMethods) return null; var handler = new MultiLineLambdaExpressionHandler(_context, node); return handler.UstNode; } public override UstNode VisitObjectCreationExpression(ObjectCreationExpressionSyntax node) { ObjectCreationExpressionHandler handler = new ObjectCreationExpressionHandler(_context, node); return handler.UstNode; } public override UstNode VisitNamespaceBlock(NamespaceBlockSyntax node) { NamespaceBlockHandler handler = new NamespaceBlockHandler(_context, node); return handler.UstNode; } public override UstNode VisitNamespaceStatement(NamespaceStatementSyntax node) { NamespaceStatementHandler handler = new NamespaceStatementHandler(_context, node); return handler.UstNode; } public override UstNode VisitInterfaceBlock(InterfaceBlockSyntax node) { if (!MetaDataSettings.InterfaceDeclarations) return null; InterfaceBlockHandler handler = new InterfaceBlockHandler(_context, node); HandleReferences(((InterfaceBlock)handler.UstNode).Reference); return handler.UstNode; } public override UstNode VisitInterfaceStatement(InterfaceStatementSyntax node) { InterfaceStatementHandler handler = new InterfaceStatementHandler(_context, node); return handler.UstNode; } public override UstNode VisitSimpleAsClause(SimpleAsClauseSyntax node) { SimpleAsClauseHandler handler = new SimpleAsClauseHandler(_context, node); return handler.UstNode; } public override UstNode VisitSimpleArgument(SimpleArgumentSyntax node) { SimpleArgumentHandler handler = new SimpleArgumentHandler(_context, node); return handler.UstNode; } private void HandleReferences(in Reference reference) { if (MetaDataSettings.ReferenceData && !RootNode.References.Contains(reference)) { var rootReference = new Reference() { Assembly = reference.Assembly, Namespace = reference.Namespace, Version = reference.Version }; if (reference.AssemblySymbol != null) { var metaDataReference = SemanticModel?.Compilation.GetMetadataReference(reference.AssemblySymbol); if (metaDataReference != null) { rootReference.AssemblyLocation = metaDataReference.Display; } } RootNode.References.Add(rootReference); } } private List HandleGenericMembers(List children) { List childUstNodes = new List(); foreach (var child in children) { var childUstNode = HandleGenericVisit(child); if (childUstNode != null) { childUstNodes.Add(childUstNode); } //If we're not handling the node, we'll collapse the level into the parent so that we can still visit the children else { var grandChildren = child.ChildNodes(); if (grandChildren.Any()) { var grandChildUstNodes = HandleGenericMembers(grandChildren.ToList()); if (grandChildUstNodes.Any()) { childUstNodes.AddRange(grandChildUstNodes); } } } } return childUstNodes; } private UstNode HandleGenericVisit(SyntaxNode node) { try { var ustNode = base.Visit(node); if (ustNode != null) { AddChildNodes(ustNode.Children, node); AssignParentNode(ustNode.Children, ustNode); } return ustNode; } catch (Exception ex) { Logger.LogError(ex, node.ToString()); return null; } } private void AddChildNodes(UstList nodeChildren, SyntaxNode syntaxNode) { var children = HandleGenericMembers(syntaxNode.ChildNodes()?.ToList()); if (children != null && nodeChildren != null) { nodeChildren.AddRange(children); } } private void AssignParentNode(List children, UstNode parentNode) { foreach (var child in children) { child.Parent = parentNode; } } public void Dispose() { _context?.Dispose(); RootNode = null; } } }