private NodeMapBuilder(OrderPreservingMultiDictionary<CSharpSyntaxNode, BoundNode> map, CSharpSyntaxNode thisSyntaxNodeOnly) { _map = map; _thisSyntaxNodeOnly = thisSyntaxNodeOnly; }
private NodeMapBuilder(OrderPreservingMultiDictionary <SyntaxNode, BoundNode> map, SyntaxTree tree, SyntaxNode thisSyntaxNodeOnly) { _map = map; _tree = tree; _thisSyntaxNodeOnly = thisSyntaxNodeOnly; }
public static void AddToMap(BoundNode root, Dictionary <SyntaxNode, ImmutableArray <BoundNode> > map, SyntaxTree tree, SyntaxNode node = null) { Debug.Assert(node == null || root == null || !(root.Syntax is StatementSyntax), "individually added nodes are not supposed to be statements."); if (root == null || map.ContainsKey(root.Syntax)) { // root node is already in the map, children must be in the map too. return; } var additionMap = OrderPreservingMultiDictionary <SyntaxNode, BoundNode> .GetInstance(); var builder = new NodeMapBuilder(additionMap, tree, node); builder.Visit(root); foreach (CSharpSyntaxNode key in additionMap.Keys) { if (map.ContainsKey(key)) { #if DEBUG // It's possible that AddToMap was previously called with a subtree of root. If this is the case, // then we'll see an entry in the map. Since the incremental binder should also have seen the // pre-existing map entry, the entry in addition map should be identical. // Another, more unfortunate, possibility is that we've had to re-bind the syntax and the new bound // nodes are equivalent, but not identical, to the existing ones. In such cases, we prefer the // existing nodes so that the cache will always return the same bound node for a given syntax node. // EXAMPLE: Suppose we have the statement P.M(1); // First, we ask for semantic info about "P". We'll walk up to the statement level and bind that. // We'll end up with map entries for "1", "P", "P.M(1)", and "P.M(1);". // Next, we ask for semantic info about "P.M". That isn't in our map, so we walk up to the statement // level - again - and bind that - again. // Once again, we'll end up with map entries for "1", "P", "P.M(1)", and "P.M(1);". They will // have the same structure as the original map entries, but will not be ReferenceEquals. var existing = map[key]; var added = additionMap[key]; Debug.Assert(existing.Length == added.Length, "existing.Length == added.Length"); for (int i = 0; i < existing.Length; i++) { // TODO: it would be great if we could check !ReferenceEquals(existing[i], added[i]) (DevDiv #11584). // Known impediments include: // 1) Field initializers aren't cached because they're not in statements. // 2) Single local declarations (e.g. "int x = 1;" vs "int x = 1, y = 2;") aren't found in the cache // since nothing is cached for the statement syntax. if (existing[i].Kind != added[i].Kind) { Debug.Assert(!(key is StatementSyntax), "!(key is StatementSyntax)"); // This also seems to be happening when we get equivalent BoundTypeExpression and BoundTypeOrValueExpression nodes. if (existing[i].Kind == BoundKind.TypeExpression && added[i].Kind == BoundKind.TypeOrValueExpression) { Debug.Assert( TypeSymbol.Equals(((BoundTypeExpression)existing[i]).Type, ((BoundTypeOrValueExpression)added[i]).Type, TypeCompareKind.ConsiderEverything2), string.Format( System.Globalization.CultureInfo.InvariantCulture, "((BoundTypeExpression)existing[{0}]).Type == ((BoundTypeOrValueExpression)added[{0}]).Type", i)); } else if (existing[i].Kind == BoundKind.TypeOrValueExpression && added[i].Kind == BoundKind.TypeExpression) { Debug.Assert( TypeSymbol.Equals(((BoundTypeOrValueExpression)existing[i]).Type, ((BoundTypeExpression)added[i]).Type, TypeCompareKind.ConsiderEverything2), string.Format( System.Globalization.CultureInfo.InvariantCulture, "((BoundTypeOrValueExpression)existing[{0}]).Type == ((BoundTypeExpression)added[{0}]).Type", i)); } else { Debug.Assert(false, "New bound node does not match existing bound node"); } } else { Debug.Assert( (object)existing[i] == added[i] || !(key is StatementSyntax), string.Format( System.Globalization.CultureInfo.InvariantCulture, "(object)existing[{0}] == added[{0}] || !(key is StatementSyntax)", i)); } } #endif } else { map[key] = additionMap[key]; } } additionMap.Free(); }
private NodeMapBuilder(OrderPreservingMultiDictionary <CSharpSyntaxNode, BoundNode> map, CSharpSyntaxNode thisSyntaxNodeOnly) { _map = map; _thisSyntaxNodeOnly = thisSyntaxNodeOnly; }
private static SymbolTreeInfo TryReadSymbolTreeInfo( ObjectReader reader, Checksum checksum, Func <string, ImmutableArray <Node>, Task <SpellChecker> > createSpellCheckerTask) { try { var concatenatedNames = reader.ReadString(); var nodeCount = reader.ReadInt32(); var nodes = ArrayBuilder <Node> .GetInstance(nodeCount); for (var i = 0; i < nodeCount; i++) { var start = reader.ReadInt32(); var length = reader.ReadInt32(); var parentIndex = reader.ReadInt32(); nodes.Add(new Node(new TextSpan(start, length), parentIndex)); } var inheritanceMap = new OrderPreservingMultiDictionary <int, int>(); var inheritanceMapKeyCount = reader.ReadInt32(); for (var i = 0; i < inheritanceMapKeyCount; i++) { var key = reader.ReadInt32(); var valueCount = reader.ReadInt32(); for (var j = 0; j < valueCount; j++) { var value = reader.ReadInt32(); inheritanceMap.Add(key, value); } } MultiDictionary <string, ExtensionMethodInfo> simpleTypeNameToExtensionMethodMap; ImmutableArray <ExtensionMethodInfo> extensionMethodOfComplexType; var keyCount = reader.ReadInt32(); if (keyCount == 0) { simpleTypeNameToExtensionMethodMap = null; } else { simpleTypeNameToExtensionMethodMap = new MultiDictionary <string, ExtensionMethodInfo>(); for (var i = 0; i < keyCount; i++) { var typeName = reader.ReadString(); var valueCount = reader.ReadInt32(); for (var j = 0; j < valueCount; j++) { var containerName = reader.ReadString(); var name = reader.ReadString(); simpleTypeNameToExtensionMethodMap.Add(typeName, new ExtensionMethodInfo(containerName, name)); } } } var arrayLength = reader.ReadInt32(); if (arrayLength == 0) { extensionMethodOfComplexType = ImmutableArray <ExtensionMethodInfo> .Empty; } else { var builder = ArrayBuilder <ExtensionMethodInfo> .GetInstance(arrayLength); for (var i = 0; i < arrayLength; ++i) { var containerName = reader.ReadString(); var name = reader.ReadString(); builder.Add(new ExtensionMethodInfo(containerName, name)); } extensionMethodOfComplexType = builder.ToImmutableAndFree(); } var nodeArray = nodes.ToImmutableAndFree(); var spellCheckerTask = createSpellCheckerTask(concatenatedNames, nodeArray); return(new SymbolTreeInfo( checksum, concatenatedNames, nodeArray, spellCheckerTask, inheritanceMap, extensionMethodOfComplexType, simpleTypeNameToExtensionMethodMap)); } catch { Logger.Log(FunctionId.SymbolTreeInfo_ExceptionInCacheRead); } return(null); }
private static void LookupMetadataDefinitions( MetadataReader reader, TypeDefinition typeDefinition, OrderPreservingMultiDictionary<string, MetadataDefinition> definitionMap) { // Only bother looking for extension methods in static types. if ((typeDefinition.Attributes & TypeAttributes.Abstract) != 0 && (typeDefinition.Attributes & TypeAttributes.Sealed) != 0) { foreach (var child in typeDefinition.GetMethods()) { var method = reader.GetMethodDefinition(child); if ((method.Attributes & MethodAttributes.SpecialName) != 0 || (method.Attributes & MethodAttributes.RTSpecialName) != 0) { continue; } // SymbolTreeInfo is only searched for types and extension methods. // So we don't want to pull in all methods here. As a simple approximation // we just pull in methods that have attributes on them. if ((method.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public && (method.Attributes & MethodAttributes.Static) != 0 && method.GetCustomAttributes().Count > 0) { var definition = new MetadataDefinition( MetadataDefinitionKind.Member, reader.GetString(method.Name)); definitionMap.Add(definition.Name, definition); } } } foreach (var child in typeDefinition.GetNestedTypes()) { var type = reader.GetTypeDefinition(child); // We don't include internals from metadata assemblies. It's less likely that // a project would have IVT to it and so it helps us save on memory. It also // means we can avoid loading lots and lots of obfuscated code in the case the // dll was obfuscated. if (IsPublic(type.Attributes)) { var definition = MetadataDefinition.Create(reader, type); definitionMap.Add(definition.Name, definition); } } }
private static void LookupMetadataDefinitions( MetadataReader reader, NamespaceDefinition namespaceDefinition, OrderPreservingMultiDictionary<string, MetadataDefinition> definitionMap) { foreach (var child in namespaceDefinition.NamespaceDefinitions) { var definition = MetadataDefinition.Create(reader, child); definitionMap.Add(definition.Name, definition); } foreach (var child in namespaceDefinition.TypeDefinitions) { var typeDefinition = reader.GetTypeDefinition(child); if (IsPublic(typeDefinition.Attributes)) { var definition = MetadataDefinition.Create(reader, typeDefinition); definitionMap.Add(definition.Name, definition); } } }
private static void GenerateMetadataNodes( MetadataReader reader, string name, int parentIndex, OrderPreservingMultiDictionary<string, MetadataDefinition>.ValueSet definitionsWithSameName, List<Node> unsortedNodes) { var node = new Node(name, parentIndex); var nodeIndex = unsortedNodes.Count; unsortedNodes.Add(node); // Add all child members var definitionMap = OrderPreservingMultiDictionary<string, MetadataDefinition>.GetInstance(); try { foreach (var definition in definitionsWithSameName) { LookupMetadataDefinitions(reader, definition, definitionMap); } foreach (var kvp in definitionMap) { if (UnicodeCharacterUtilities.IsValidIdentifier(kvp.Key)) { GenerateMetadataNodes(reader, kvp.Key, nodeIndex, kvp.Value, unsortedNodes); } } } finally { definitionMap.Free(); } }
private static void LookupMetadataDefinitions( MetadataReader reader, MetadataDefinition definition, OrderPreservingMultiDictionary<string, MetadataDefinition> definitionMap) { switch (definition.Kind) { case MetadataDefinitionKind.Namespace: LookupMetadataDefinitions(reader, definition.Namespace, definitionMap); break; case MetadataDefinitionKind.Type: LookupMetadataDefinitions(reader, definition.Type, definitionMap); break; } }
private SymbolTreeInfo( VersionStamp version, string concatenatedNames, Node[] sortedNodes, Task<SpellChecker> spellCheckerTask, OrderPreservingMultiDictionary<string, string> inheritanceMap) : this(version, concatenatedNames, sortedNodes, spellCheckerTask) { var indexBasedInheritanceMap = CreateIndexBasedInheritanceMap(inheritanceMap); _inheritanceMap = indexBasedInheritanceMap; }
private SymbolTreeInfo( VersionStamp version, string concatenatedNames, Node[] sortedNodes, Task<SpellChecker> spellCheckerTask, OrderPreservingMultiDictionary<int, int> inheritanceMap) : this(version, concatenatedNames, sortedNodes, spellCheckerTask) { _inheritanceMap = inheritanceMap; }
private OrderPreservingMultiDictionary<int, int> CreateIndexBasedInheritanceMap( OrderPreservingMultiDictionary<string, string> inheritanceMap) { // All names in metadata will be case sensitive. var comparer = GetComparer(ignoreCase: false); var result = new OrderPreservingMultiDictionary<int, int>(); foreach (var kvp in inheritanceMap) { var baseName = kvp.Key; var baseNameIndex = BinarySearch(baseName); Debug.Assert(baseNameIndex >= 0); foreach (var derivedName in kvp.Value) { foreach (var derivedNameIndex in FindNodeIndices(derivedName, comparer)) { result.Add(baseNameIndex, derivedNameIndex); } } } return result; }
private static SymbolTreeInfo CreateSymbolTreeInfo( Solution solution, VersionStamp version, string filePath, ImmutableArray<BuilderNode> unsortedNodes, OrderPreservingMultiDictionary<string, string> inheritanceMap) { string concatenatedNames; Node[] sortedNodes; SortNodes(unsortedNodes, out concatenatedNames, out sortedNodes); var createSpellCheckerTask = GetSpellCheckerTask( solution, version, filePath, concatenatedNames, sortedNodes); return new SymbolTreeInfo( version, concatenatedNames, sortedNodes, createSpellCheckerTask, inheritanceMap); }
private void GenerateMetadataNodes( MetadataNode parentNode, string nodeName, OrderPreservingMultiDictionary<string, MetadataDefinition>.ValueSet definitionsWithSameName) { if (!UnicodeCharacterUtilities.IsValidIdentifier(nodeName)) { return; } var childNode = MetadataNode.Allocate(nodeName); _parentToChildren.Add(parentNode, childNode); // Add all child members var definitionMap = OrderPreservingMultiDictionary<string, MetadataDefinition>.GetInstance(); try { foreach (var definition in definitionsWithSameName) { LookupMetadataDefinitions(definition, definitionMap); } foreach (var kvp in definitionMap) { GenerateMetadataNodes(childNode,kvp.Key, kvp.Value); } } finally { definitionMap.Free(); } }
public MetadataInfoCreator( Solution solution, VersionStamp version, PortableExecutableReference reference, CancellationToken cancellationToken) { _solution = solution; _version = version; _reference = reference; _cancellationToken = cancellationToken; _metadataReader = null; _allTypeDefinitions = new List<MetadataDefinition>(); _inheritanceMap = OrderPreservingMultiDictionary<string, string>.GetInstance(); _parentToChildren = OrderPreservingMultiDictionary<MetadataNode, MetadataNode>.GetInstance(); _rootNode = MetadataNode.Allocate(name: ""); }
private void LookupMetadataDefinitions( TypeDefinition typeDefinition, OrderPreservingMultiDictionary <string, MetadataDefinition> definitionMap) { // Only bother looking for extension methods in static types. // Note this check means we would ignore extension methods declared in assemblies // compiled from VB code, since a module in VB is compiled into class with // "sealed" attribute but not "abstract". // Although this can be addressed by checking custom attributes, // we believe this is not a common scenario to warrant potential perf impact. if ((typeDefinition.Attributes & TypeAttributes.Abstract) != 0 && (typeDefinition.Attributes & TypeAttributes.Sealed) != 0) { foreach (var child in typeDefinition.GetMethods()) { var method = _metadataReader.GetMethodDefinition(child); if ((method.Attributes & MethodAttributes.SpecialName) != 0 || (method.Attributes & MethodAttributes.RTSpecialName) != 0) { continue; } // SymbolTreeInfo is only searched for types and extension methods. // So we don't want to pull in all methods here. As a simple approximation // we just pull in methods that have attributes on them. if ((method.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public && (method.Attributes & MethodAttributes.Static) != 0 && method.GetParameters().Count > 0 && method.GetCustomAttributes().Count > 0) { // Decode method signature to get the receiver type name (i.e. type name for the first parameter) var blob = _metadataReader.GetBlobReader(method.Signature); var decoder = new SignatureDecoder <ParameterTypeInfo, object>(ParameterTypeInfoProvider.Instance, _metadataReader, genericContext: null); var signature = decoder.DecodeMethodSignature(ref blob); // It'd be good if we don't need to go through all parameters and make unnecessary allocations. // However, this is not possible with meatadata reader API right now (although it's possible by copying code from meatadata reader implementaion) if (signature.ParameterTypes.Length > 0) { _containsExtensionsMethod = true; var firstParameterTypeInfo = signature.ParameterTypes[0]; var definition = new MetadataDefinition(MetadataDefinitionKind.Member, _metadataReader.GetString(method.Name), firstParameterTypeInfo); definitionMap.Add(definition.Name, definition); } } } } foreach (var child in typeDefinition.GetNestedTypes()) { var type = _metadataReader.GetTypeDefinition(child); // We don't include internals from metadata assemblies. It's less likely that // a project would have IVT to it and so it helps us save on memory. It also // means we can avoid loading lots and lots of obfuscated code in the case the // dll was obfuscated. if (IsPublic(type.Attributes)) { var definition = MetadataDefinition.Create(_metadataReader, type); definitionMap.Add(definition.Name, definition); _allTypeDefinitions.Add(definition); } } }