internal static string GetValue(this GraphNodeId id, GraphNodeIdName idPartName) { if (idPartName == CodeGraphNodeIdName.Assembly || idPartName == CodeGraphNodeIdName.File) { try { Uri value = id.GetNestedValueByName <Uri>(idPartName); // for idPartName == CodeGraphNodeIdName.File it can be null, avoid unnecessary exception if (value == null) { return(null); } // Assembly and File are represented by a Uri, extract LocalPath string from Uri return((value.IsAbsoluteUri ? value.LocalPath : value.ToString()).Trim('/')); } catch { // for some node ids Uri might throw format exception, thus try to get string at least return(id.GetNestedValueByName <string>(idPartName)); } } else { return(id.GetNestedValueByName <string>(idPartName)); } }
private static async Task <GraphNodeId> GetPartialForArrayTypeAsync( IArrayTypeSymbol arrayType, GraphNodeIdName nodeName, Solution solution, CancellationToken cancellationToken ) { var partials = new List <GraphNodeId>(); var underlyingType = ChaseToUnderlyingType(arrayType); if (underlyingType.TypeKind == TypeKind.Dynamic) { partials.Add(GraphNodeId.GetPartial(CodeQualifiedName.Name, "Object")); } else if (underlyingType.TypeKind != TypeKind.TypeParameter) { partials.Add(GraphNodeId.GetPartial(CodeQualifiedName.Name, underlyingType.Name)); } partials.Add( GraphNodeId.GetPartial(CodeQualifiedName.ArrayRank, arrayType.Rank.ToString()) ); partials.Add( await GetPartialForTypeAsync( arrayType.ElementType, CodeGraphNodeIdName.ParentType, solution, cancellationToken ) .ConfigureAwait(false) ); return(GraphNodeId.GetPartial(nodeName, MakeCollectionIfNecessary(partials.ToArray()))); }
private static async Task <GraphNodeId> GetPartialForTypeAsync( ITypeSymbol symbol, GraphNodeIdName nodeName, Solution solution, CancellationToken cancellationToken, bool isInGenericArguments = false ) { if (symbol is IArrayTypeSymbol arrayType) { return(await GetPartialForArrayTypeAsync( arrayType, nodeName, solution, cancellationToken ) .ConfigureAwait(false)); } else if (symbol is INamedTypeSymbol namedType) { return(await GetPartialForNamedTypeAsync( namedType, nodeName, solution, cancellationToken, isInGenericArguments ) .ConfigureAwait(false)); } else if (symbol is IPointerTypeSymbol pointerType) { return(await GetPartialForPointerTypeAsync( pointerType, nodeName, solution, cancellationToken ) .ConfigureAwait(false)); } else if (symbol is ITypeParameterSymbol typeParameter) { return(await GetPartialForTypeParameterSymbolAsync( typeParameter, nodeName, solution, cancellationToken ) .ConfigureAwait(false)); } else if (symbol is IDynamicTypeSymbol) { return(GetPartialForDynamicType(nodeName)); } throw ExceptionUtilities.Unreachable; }
private static async Task <GraphNodeId> GetPartialForPointerTypeAsync( IPointerTypeSymbol pointerType, GraphNodeIdName nodeName, Solution solution, CancellationToken cancellationToken ) { var indirection = 1; while (pointerType.PointedAtType.TypeKind == TypeKind.Pointer) { indirection++; pointerType = (IPointerTypeSymbol)pointerType.PointedAtType; } var partials = new List <GraphNodeId>(); partials.Add( GraphNodeId.GetPartial(CodeQualifiedName.Name, pointerType.PointedAtType.Name) ); partials.Add( GraphNodeId.GetPartial(CodeQualifiedName.Indirection, indirection.ToString()) ); if (pointerType.PointedAtType.ContainingType != null) { partials.Add( await GetPartialForTypeAsync( pointerType.PointedAtType.ContainingType, CodeGraphNodeIdName.ParentType, solution, cancellationToken ) .ConfigureAwait(false) ); } return(GraphNodeId.GetPartial(nodeName, MakeCollectionIfNecessary(partials.ToArray()))); }
private string GetPartialValueFromGraphNodeId(GraphNodeId id, GraphNodeIdName idPartName) { if (idPartName == CodeGraphNodeIdName.Assembly || idPartName == CodeGraphNodeIdName.File) { try { var value = id.GetNestedValueByName <Uri>(idPartName); // Assembly and File are represented by a Uri, extract LocalPath string from Uri return((value.IsAbsoluteUri ? value.LocalPath : value.ToString()).Trim('/')); } catch { // for some node ids Uri might throw format exception, thus try to get string at least return(id.GetNestedValueByName <string>(idPartName)); } } else { return(id.GetNestedValueByName <string>(idPartName)); } }
private static async Task <GraphNodeId> GetPartialForTypeParameterSymbolAsync( ITypeParameterSymbol typeParameterSymbol, GraphNodeIdName nodeName, Solution solution, CancellationToken cancellationToken ) { if (typeParameterSymbol.TypeParameterKind == TypeParameterKind.Method) { return(GraphNodeId.GetPartial( nodeName, new GraphNodeIdCollection( false, GraphNodeId.GetPartial( CodeGraphNodeIdName.Parameter, typeParameterSymbol.Ordinal.ToString() ) ) )); } else { var nodes = await GetPartialsForNamespaceAndTypeAsync( typeParameterSymbol, false, solution, cancellationToken ) .ConfigureAwait(false); return(GraphNodeId.GetPartial( nodeName, new GraphNodeIdCollection(false, nodes.ToArray()) )); } }
private static async Task <GraphNodeId> GetPartialForNamedTypeAsync(INamedTypeSymbol namedType, GraphNodeIdName nodeName, Solution solution, CancellationToken cancellationToken, bool isInGenericArguments = false) { // If this is a simple type, then we don't have much to do if (namedType.ContainingType == null && namedType.ConstructedFrom == namedType && namedType.Arity == 0) { return(GraphNodeId.GetPartial(nodeName, namedType.Name)); } else { // For a generic type, we need to populate "type" property with the following form: // // Type = (Name =...GenericParameterCount = GenericArguments =...ParentType =...) // // where "Name" contains a symbol name // and "GenericParameterCount" contains the number of type parameters, // and "GenericArguments" contains its type parameters' node information. // and "ParentType" contains its containing type's node information. var partials = new List <GraphNodeId>(); partials.Add(GraphNodeId.GetPartial(CodeQualifiedName.Name, namedType.Name)); if (namedType.Arity > 0) { partials.Add(GraphNodeId.GetPartial(CodeGraphNodeIdName.GenericParameterCountIdentifier, namedType.Arity.ToString())); } // For the property "GenericArguments", we only populate them // when type parameters are constructed using instance types (i.e., namedType.ConstructedFrom != namedType). // However, there is a case where we need to populate "GenericArguments" even though arguments are not marked as "constructed" // because a symbol is not marked as "constructed" when a type is constructed using its own type parameters. // To distinguish this case, we use "isInGenericArguments" flag which we pass either to populate arguments recursively or to populate "ParentType". bool hasGenericArguments = (namedType.ConstructedFrom != namedType || isInGenericArguments) && namedType.TypeArguments != null && namedType.TypeArguments.Any(); if (hasGenericArguments) { var genericArguments = new List <GraphNodeId>(); foreach (var arg in namedType.TypeArguments) { var nodes = await GetPartialsForNamespaceAndTypeAsync(arg, includeNamespace : true, solution : solution, cancellationToken : cancellationToken, isInGenericArguments : true).ConfigureAwait(false); genericArguments.Add(GraphNodeId.GetNested(nodes.ToArray())); } partials.Add(GraphNodeId.GetArray( CodeGraphNodeIdName.GenericArgumentsIdentifier, genericArguments.ToArray())); } if (namedType.ContainingType != null) { partials.Add(await GetPartialForTypeAsync(namedType.ContainingType, CodeGraphNodeIdName.ParentType, solution, cancellationToken, hasGenericArguments).ConfigureAwait(false)); } return(GraphNodeId.GetPartial(nodeName, MakeCollectionIfNecessary(false, partials.ToArray()))); } }
private static GraphNodeId GetPartialForDynamicType(IDynamicTypeSymbol dt, GraphNodeIdName nodeName) { // We always consider this to be the "Object" type since Progression takes a very metadata-ish view of the type return(GraphNodeId.GetPartial(nodeName, "Object")); }
private static async Task<GraphNodeId> GetPartialForTypeParameterSymbolAsync(ITypeParameterSymbol typeParameterSymbol, GraphNodeIdName nodeName, Solution solution, CancellationToken cancellationToken) { if (typeParameterSymbol.TypeParameterKind == TypeParameterKind.Method) { return GraphNodeId.GetPartial(nodeName, new GraphNodeIdCollection(false, GraphNodeId.GetPartial(CodeGraphNodeIdName.Parameter, typeParameterSymbol.Ordinal.ToString()))); } else { var nodes = await GetPartialsForNamespaceAndTypeAsync(typeParameterSymbol, false, solution, cancellationToken).ConfigureAwait(false); return GraphNodeId.GetPartial(nodeName, new GraphNodeIdCollection(false, nodes.ToArray())); } }
private static async Task<GraphNodeId> GetPartialForArrayTypeAsync(IArrayTypeSymbol arrayType, GraphNodeIdName nodeName, Solution solution, CancellationToken cancellationToken) { var partials = new List<GraphNodeId>(); var underlyingType = ChaseToUnderlyingType(arrayType); if (underlyingType.TypeKind == TypeKind.Dynamic) { partials.Add(GraphNodeId.GetPartial(CodeQualifiedName.Name, "Object")); } else if (underlyingType.TypeKind != TypeKind.TypeParameter) { partials.Add(GraphNodeId.GetPartial(CodeQualifiedName.Name, underlyingType.Name)); } partials.Add(GraphNodeId.GetPartial(CodeQualifiedName.ArrayRank, arrayType.Rank.ToString())); partials.Add(await GetPartialForTypeAsync(arrayType.ElementType, CodeGraphNodeIdName.ParentType, solution, cancellationToken).ConfigureAwait(false)); return GraphNodeId.GetPartial(nodeName, MakeCollectionIfNecessary(false, partials.ToArray())); }
private static async Task<GraphNodeId> GetPartialForPointerTypeAsync(IPointerTypeSymbol pointerType, GraphNodeIdName nodeName, Solution solution, CancellationToken cancellationToken) { var indirection = 1; while (pointerType.PointedAtType.TypeKind == TypeKind.Pointer) { indirection++; pointerType = (IPointerTypeSymbol)pointerType.PointedAtType; } var partials = new List<GraphNodeId>(); partials.Add(GraphNodeId.GetPartial(CodeQualifiedName.Name, pointerType.PointedAtType.Name)); partials.Add(GraphNodeId.GetPartial(CodeQualifiedName.Indirection, indirection.ToString())); if (pointerType.PointedAtType.ContainingType != null) { partials.Add(await GetPartialForTypeAsync(pointerType.PointedAtType.ContainingType, CodeGraphNodeIdName.ParentType, solution, cancellationToken).ConfigureAwait(false)); } return GraphNodeId.GetPartial(nodeName, MakeCollectionIfNecessary(false, partials.ToArray())); }
private static async Task<GraphNodeId> GetPartialForNamedTypeAsync(INamedTypeSymbol namedType, GraphNodeIdName nodeName, Solution solution, CancellationToken cancellationToken, bool isInGenericArguments = false) { // If this is a simple type, then we don't have much to do if (namedType.ContainingType == null && namedType.ConstructedFrom == namedType && namedType.Arity == 0) { return GraphNodeId.GetPartial(nodeName, namedType.Name); } else { // For a generic type, we need to populate "type" property with the following form: // // Type = (Name =...GenericParameterCount = GenericArguments =...ParentType =...) // // where "Name" contains a symbol name // and "GenericParameterCount" contains the number of type parameters, // and "GenericArguments" contains its type parameters' node information. // and "ParentType" contains its containing type's node information. var partials = new List<GraphNodeId>(); partials.Add(GraphNodeId.GetPartial(CodeQualifiedName.Name, namedType.Name)); if (namedType.Arity > 0) { partials.Add(GraphNodeId.GetPartial(CodeGraphNodeIdName.GenericParameterCountIdentifier, namedType.Arity.ToString())); } // For the property "GenericArguments", we only populate them // when type parameters are constructed using instance types (i.e., namedType.ConstructedFrom != namedType). // However, there is a case where we need to populate "GenericArguments" even though arguments are not marked as "constructed" // because a symbol is not marked as "constructed" when a type is constructed using its own type parameters. // To distinguish this case, we use "isInGenericArguments" flag which we pass either to populate arguments recursively or to populate "ParentType". bool hasGenericArguments = (namedType.ConstructedFrom != namedType || isInGenericArguments) && namedType.TypeArguments != null && namedType.TypeArguments.Any(); if (hasGenericArguments) { var genericArguments = new List<GraphNodeId>(); foreach (var arg in namedType.TypeArguments) { var nodes = await GetPartialsForNamespaceAndTypeAsync(arg, includeNamespace: true, solution: solution, cancellationToken: cancellationToken, isInGenericArguments: true).ConfigureAwait(false); genericArguments.Add(GraphNodeId.GetNested(nodes.ToArray())); } partials.Add(GraphNodeId.GetArray( CodeGraphNodeIdName.GenericArgumentsIdentifier, genericArguments.ToArray())); } if (namedType.ContainingType != null) { partials.Add(await GetPartialForTypeAsync(namedType.ContainingType, CodeGraphNodeIdName.ParentType, solution, cancellationToken, hasGenericArguments).ConfigureAwait(false)); } return GraphNodeId.GetPartial(nodeName, MakeCollectionIfNecessary(false, partials.ToArray())); } }
private static GraphNodeId GetPartialForDynamicType(IDynamicTypeSymbol dt, GraphNodeIdName nodeName) { // We always consider this to be the "Object" type since Progression takes a very metadata-ish view of the type return GraphNodeId.GetPartial(nodeName, "Object"); }
private static async Task<GraphNodeId> GetPartialForTypeAsync(ITypeSymbol symbol, GraphNodeIdName nodeName, Solution solution, CancellationToken cancellationToken, bool isInGenericArguments = false) { if (symbol is IArrayTypeSymbol) { return await GetPartialForArrayTypeAsync((IArrayTypeSymbol)symbol, nodeName, solution, cancellationToken).ConfigureAwait(false); } else if (symbol is INamedTypeSymbol) { return await GetPartialForNamedTypeAsync((INamedTypeSymbol)symbol, nodeName, solution, cancellationToken, isInGenericArguments).ConfigureAwait(false); } else if (symbol is IPointerTypeSymbol) { return await GetPartialForPointerTypeAsync((IPointerTypeSymbol)symbol, nodeName, solution, cancellationToken).ConfigureAwait(false); } else if (symbol is ITypeParameterSymbol) { return await GetPartialForTypeParameterSymbolAsync((ITypeParameterSymbol)symbol, nodeName, solution, cancellationToken).ConfigureAwait(false); } else if (symbol is IDynamicTypeSymbol) { return GetPartialForDynamicType((IDynamicTypeSymbol)symbol, nodeName); } throw ExceptionUtilities.Unreachable; }