/// <summary> /// Examines the identifier and if applicable, creates an instance of ObjectInformation /// which will be consumed later by the SyntaxBuilder /// </summary> /// <param name="node"></param> private void processIdentifierName(IdentifierNameSyntax node) { var symbol = _model.GetSymbolInfo(node).Symbol; var type = _model.GetTypeInfo(node).Type; if (type == null || symbol == null) { // We need a symbol // Method names are an example of identifiers with no types, and we ignore them return; } if (node.IsVar) { return; } if (symbol != null) { var typeName = type?.Name ?? String.Empty; // Handle generics (TODO: recursively go through all levels) var namedType = type as INamedTypeSymbol; if (namedType != null) { List<string> argumentNames = new List<string>(); foreach (var argument in namedType.TypeArguments) { var argumentName = argument.Name; argumentNames.Add(argumentName); } if (argumentNames.Any()) { typeName = $"{type?.Name}<{String.Join(", ", argumentNames)}>"; } } // Attempt to remove trivial identifiers like String.Empty var definitionName = symbol.OriginalDefinition.ToDisplayString(); var actualName = typeName + "." + symbol.MetadataName; if (String.Compare(definitionName, actualName, ignoreCase: true) == 0) { // This identifier is already well defined in the snippet. return; } foreach (var location in symbol.OriginalDefinition.Locations) { // Process only nodes defined outside of the target range if (!location.IsInSource || !(location.SourceSpan.Start < _end && location.SourceSpan.End > _start)) { var objectInfo = new ObjectInformation() { Identifier = node?.Identifier.ToString() ?? String.Empty, TypeName = typeName ?? String.Empty, Namespace = type?.ContainingNamespace?.ToString() ?? String.Empty, AssemblyName = type?.ContainingAssembly?.Name ?? String.Empty, Kind = symbol.Kind, }; definedWithinSnippet.Add(objectInfo); } } } }
private static string createDeclaration(ObjectInformation objectInfo) { return $"{objectInfo.TypeName} {objectInfo.Identifier}; // using {objectInfo.Namespace}; ({objectInfo.AssemblyName})"; }
private static string createUsingStatement(ObjectInformation objectInfo) { return $"using {objectInfo.Namespace}; // ({objectInfo.AssemblyName})"; }
/// <summary> /// Decides whether the element needs a declaration or just a usings statement /// </summary> /// <param name="objectInfo"></param> /// <returns></returns> private static bool canHaveDeclaration(ObjectInformation objectInfo) { // This is a naive approach. From my basic tests it looks like NamedType comes from a declaration // and thus doesn't need another declaration return objectInfo.Kind != SymbolKind.NamedType; }