public AbstractData GetNodeData(SyntaxNode node, bool create = false, NamespaceData namespaceData = null, TypeData typeData = null, MethodData methodData = null) { AnonymousFunctionData functionData = null; SyntaxNode endNode; if (methodData != null) { endNode = methodData.Node; } else if (typeData != null) { endNode = typeData.Node; } else if (namespaceData != null) { endNode = namespaceData.Node; } else { endNode = Node; } foreach (var n in node.AncestorsAndSelf() .TakeWhile(o => !ReferenceEquals(o, endNode)) .Where( o => _validDataKinds.Contains(o.Kind())) .Reverse()) { switch (n.Kind()) { case SyntaxKind.ParenthesizedLambdaExpression: case SyntaxKind.AnonymousMethodExpression: case SyntaxKind.SimpleLambdaExpression: if (methodData == null) { throw new InvalidOperationException($"Anonymous function {n} is declared outside a {nameof(TypeDeclarationSyntax)}"); } var symbol = SemanticModel.GetSymbolInfo(n).Symbol as IMethodSymbol; functionData = functionData != null ? functionData.GetNestedAnonymousFunctionData((AnonymousFunctionExpressionSyntax)n, symbol, create) : methodData.GetAnonymousFunctionData((AnonymousFunctionExpressionSyntax)n, symbol, create); if (functionData == null) { return(null); } break; case SyntaxKind.MethodDeclaration: if (typeData == null) { throw new InvalidOperationException($"Method {n} is declared outside a {nameof(TypeDeclarationSyntax)}"); } var methodNode = (MethodDeclarationSyntax)n; var methodSymbol = SemanticModel.GetDeclaredSymbol(methodNode); methodData = typeData.GetMethodData(methodNode, methodSymbol, create); if (methodData == null) { return(null); } break; case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.StructDeclaration: if (namespaceData == null) { namespaceData = GlobalNamespaceData; } var typeNode = (TypeDeclarationSyntax)n; var typeSymbol = SemanticModel.GetDeclaredSymbol(typeNode); typeData = typeData != null ? typeData.GetNestedTypeData(typeNode, typeSymbol, create) : namespaceData.GetTypeData(typeNode, typeSymbol, create); if (typeData == null) { return(null); } break; case SyntaxKind.NamespaceDeclaration: var namespaceNode = (NamespaceDeclarationSyntax)n; var namespaceSymbol = SemanticModel.GetDeclaredSymbol(namespaceNode); namespaceData = namespaceData != null ? namespaceData.GetNestedNamespaceData(namespaceNode, namespaceSymbol, create) : GetNamespaceData(namespaceNode, namespaceSymbol, create); if (namespaceData == null) { return(null); } break; } } switch (node.Kind()) { case SyntaxKind.ParenthesizedLambdaExpression: case SyntaxKind.AnonymousMethodExpression: case SyntaxKind.SimpleLambdaExpression: return(functionData); case SyntaxKind.MethodDeclaration: return(methodData); case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.StructDeclaration: return(typeData); case SyntaxKind.NamespaceDeclaration: return(namespaceData); default: throw new InvalidOperationException($"Invalid node kind {Enum.GetName(typeof(SyntaxKind), node.Kind())}"); } }
public AbstractData GetNodeData(SyntaxNode node, bool create = false, NamespaceData namespaceData = null, TypeData typeData = null, BaseMethodData baseMethodData = null) { FunctionData functionData = null; PropertyData propertyData = null; BaseFieldData fieldData = null; FieldVariableDeclaratorData fieldVariableData = null; SyntaxNode endNode; if (baseMethodData != null) { endNode = baseMethodData.GetNode(); } else if (typeData != null) { endNode = typeData.Node; } else if (namespaceData != null) { endNode = namespaceData.Node; } else { endNode = Node; } foreach (var n in node.AncestorsAndSelf() .TakeWhile(o => !ReferenceEquals(o, endNode)) .Where(IsValid) .Reverse()) { switch (n.Kind()) { case SyntaxKind.ParenthesizedLambdaExpression: case SyntaxKind.AnonymousMethodExpression: case SyntaxKind.SimpleLambdaExpression: case SyntaxKind.LocalFunctionStatement: if (baseMethodData == null) { // ParenthesizedLambda, AnonymousMethod and SimpleLambda can be also defined inside a type if (!n.IsKind(SyntaxKind.LocalFunctionStatement)) { if (typeData != null) { return(null); // TODO: A type can have one or many FuncionData so we need to register them } } throw new InvalidOperationException($"Anonymous function {n} is declared outside a {nameof(TypeDeclarationSyntax)}"); } functionData = functionData != null ? functionData.GetChildFunction(n, SemanticModel, create) : baseMethodData.GetChildFunction(n, SemanticModel, create); if (functionData == null) { return(null); } break; case SyntaxKind.MethodDeclaration: if (typeData == null) { throw new InvalidOperationException($"Method {n} is declared outside a {nameof(TypeDeclarationSyntax)}"); } var methodNode = (MethodDeclarationSyntax)n; baseMethodData = typeData.GetMethodData(methodNode, SemanticModel, create); if (baseMethodData == null) { return(null); } break; case SyntaxKind.DestructorDeclaration: case SyntaxKind.ConstructorDeclaration: case SyntaxKind.OperatorDeclaration: case SyntaxKind.ConversionOperatorDeclaration: if (typeData == null) { throw new InvalidOperationException($"Method {n} is declared outside a {nameof(TypeDeclarationSyntax)}"); } var baseMethodNode = (BaseMethodDeclarationSyntax)n; baseMethodData = typeData.GetSpecialMethodData(baseMethodNode, SemanticModel, create); if (baseMethodData == null) { return(null); } break; case SyntaxKind.ArrowExpressionClause: if (propertyData == null) { continue; } functionData = propertyData.GetAccessorData; break; case SyntaxKind.GetAccessorDeclaration: if (propertyData == null) { throw new InvalidOperationException($"Get accessor property {n} is declared outside a {nameof(PropertyDeclarationSyntax)}"); } functionData = propertyData.GetAccessorData; if (functionData == null) { return(null); } break; case SyntaxKind.SetAccessorDeclaration: if (propertyData == null) { throw new InvalidOperationException($"Set accessor property {n} is declared outside a {nameof(PropertyDeclarationSyntax)}"); } functionData = propertyData.SetAccessorData; if (functionData == null) { return(null); } break; case SyntaxKind.PropertyDeclaration: if (typeData == null) { throw new InvalidOperationException($"Property {n} is declared outside a {nameof(TypeDeclarationSyntax)}"); } var propertyNode = (PropertyDeclarationSyntax)n; propertyData = typeData.GetPropertyData(propertyNode, SemanticModel, create); if (propertyData == null) { return(null); } break; case SyntaxKind.FieldDeclaration: case SyntaxKind.EventFieldDeclaration: if (typeData == null) { throw new InvalidOperationException($"Field {n} is declared outside a {nameof(TypeDeclarationSyntax)}"); } var fieldNode = (BaseFieldDeclarationSyntax)n; fieldData = typeData.GetBaseFieldData(fieldNode, SemanticModel, create); if (fieldData == null) { return(null); } break; case SyntaxKind.VariableDeclarator: if (fieldData == null) { throw new InvalidOperationException($"Field {n} is declared outside a {nameof(BaseFieldDeclarationSyntax)}"); } var variableNode = (VariableDeclaratorSyntax)n; fieldVariableData = fieldData.GetVariableDeclaratorData(variableNode, SemanticModel); if (fieldVariableData == null) { return(null); } break; case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.StructDeclaration: if (namespaceData == null) { namespaceData = GlobalNamespace; } var typeNode = (TypeDeclarationSyntax)n; typeData = typeData != null ? typeData.GetNestedTypeData(typeNode, SemanticModel, create) : namespaceData.GetTypeData(typeNode, SemanticModel, create); if (typeData == null) { return(null); } break; case SyntaxKind.NamespaceDeclaration: var namespaceNode = (NamespaceDeclarationSyntax)n; namespaceData = namespaceData != null ? namespaceData.GetNestedNamespaceData(namespaceNode, SemanticModel, create) : GetNamespaceData(namespaceNode, create); if (namespaceData == null) { return(null); } break; } } switch (node.Kind()) { case SyntaxKind.ParenthesizedLambdaExpression: case SyntaxKind.AnonymousMethodExpression: case SyntaxKind.SimpleLambdaExpression: case SyntaxKind.LocalFunctionStatement: case SyntaxKind.GetAccessorDeclaration: // Property getter case SyntaxKind.SetAccessorDeclaration: // Property setter return(functionData); case SyntaxKind.MethodDeclaration: case SyntaxKind.DestructorDeclaration: case SyntaxKind.ConstructorDeclaration: case SyntaxKind.OperatorDeclaration: case SyntaxKind.ConversionOperatorDeclaration: return(baseMethodData); case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.StructDeclaration: return(typeData); case SyntaxKind.NamespaceDeclaration: return(namespaceData); case SyntaxKind.PropertyDeclaration: return(propertyData); case SyntaxKind.FieldDeclaration: case SyntaxKind.EventFieldDeclaration: return(fieldData); case SyntaxKind.VariableDeclarator: return(fieldVariableData); case SyntaxKind.ArrowExpressionClause: // Arrow expression of a property getter or method return(functionData ?? baseMethodData); default: throw new InvalidOperationException($"Invalid node kind {Enum.GetName(typeof(SyntaxKind), node.Kind())}"); } }