public Session( RenameLocations renameLocationSet, Location renameSymbolDeclarationLocation, string originalText, string replacementText, OptionSet optionSet, Func <IEnumerable <ISymbol>, bool?> newSymbolsAreValid, CancellationToken cancellationToken) { _renameLocationSet = renameLocationSet; _renameSymbolDeclarationLocation = renameSymbolDeclarationLocation; _originalText = originalText; _replacementText = replacementText; _optionSet = optionSet; _hasConflictCallback = newSymbolsAreValid; _cancellationToken = cancellationToken; _renamedSymbolDeclarationAnnotation = new RenameAnnotation(); _conflictLocations = SpecializedCollections.EmptySet <ConflictLocationInfo>(); _replacementTextValid = true; _possibleNameConflicts = new List <string>(); // only process documents which possibly contain the identifiers. _documentsIdsToBeCheckedForConflict = new HashSet <DocumentId>(); _documentIdOfRenameSymbolDeclaration = renameLocationSet.Solution.GetDocument(renameSymbolDeclarationLocation.SourceTree).Id; _renameAnnotations = new AnnotationTable <RenameAnnotation>(RenameAnnotation.Kind); }
private static ISet <T> GetSymbolsForExplicitlyImplementedAccessor <T>(MethodSymbol accessor) where T : Symbol { if ((object)accessor == null) { return(SpecializedCollections.EmptySet <T>()); } ImmutableArray <MethodSymbol> implementedAccessors = accessor.ExplicitInterfaceImplementations; if (implementedAccessors.Length == 0) { return(SpecializedCollections.EmptySet <T>()); } var symbolsForExplicitlyImplementedAccessors = new HashSet <T>(); foreach (var implementedAccessor in implementedAccessors) { var associatedProperty = implementedAccessor.AssociatedSymbol as T; if ((object)associatedProperty != null) { symbolsForExplicitlyImplementedAccessors.Add(associatedProperty); } } return(symbolsForExplicitlyImplementedAccessors); }
/// <summary> /// Calculate the set of changes up to top-level types. The result /// will be used as a filter when traversing the module. /// /// Note that these changes only include user-defined source symbols, not synthesized symbols since those will be /// generated during lowering of the changed user-defined symbols. /// </summary> private static void CalculateChanges(IEnumerable <SemanticEdit> edits, out IReadOnlyDictionary <ISymbol, SymbolChange> changes, out ISet <ISymbol> replaceSymbols) { var changesBuilder = new Dictionary <ISymbol, SymbolChange>(); HashSet <ISymbol>?lazyReplaceSymbolsBuilder = null; foreach (var edit in edits) { SymbolChange change; switch (edit.Kind) { case SemanticEditKind.Update: change = SymbolChange.Updated; break; case SemanticEditKind.Insert: change = SymbolChange.Added; break; case SemanticEditKind.Replace: Debug.Assert(edit.NewSymbol != null); (lazyReplaceSymbolsBuilder ??= new HashSet <ISymbol>()).Add(edit.NewSymbol); change = SymbolChange.Added; break; case SemanticEditKind.Delete: // No work to do. continue; default: throw ExceptionUtilities.UnexpectedValue(edit.Kind); } var member = edit.NewSymbol; RoslynDebug.AssertNotNull(member); // Partial methods are supplied as implementations but recorded // internally as definitions since definitions are used in emit. if (member.Kind == SymbolKind.Method) { var method = (IMethodSymbol)member; // Partial methods should be implementations, not definitions. Debug.Assert(method.PartialImplementationPart == null); Debug.Assert((edit.OldSymbol == null) || (((IMethodSymbol)edit.OldSymbol).PartialImplementationPart == null)); var definitionPart = method.PartialDefinitionPart; if (definitionPart != null) { member = definitionPart; } } AddContainingTypesAndNamespaces(changesBuilder, member); changesBuilder.Add(member, change); } changes = changesBuilder; replaceSymbols = lazyReplaceSymbolsBuilder ?? SpecializedCollections.EmptySet <ISymbol>(); }
private static async Task <ISet <ProjectId> > GetProjectsThatCouldReferenceTypeAsync( INamedTypeSymbol type, Solution solution, bool searchInMetadata, CancellationToken cancellationToken ) { var dependencyGraph = solution.GetProjectDependencyGraph(); if (searchInMetadata) { // For a metadata type, find all projects that refer to the metadata assembly that // the type is defined in. Note: we pass 'null' for projects intentionally. We // Need to find all the possible projects that contain this metadata. var projectsThatReferenceMetadataAssembly = await DependentProjectsFinder .GetDependentProjectsAsync( solution, type, projects : null, cancellationToken : cancellationToken ) .ConfigureAwait(false); // Now collect all the dependent projects as well. var projectsThatCouldReferenceType = projectsThatReferenceMetadataAssembly .SelectMany(p => GetProjectsThatCouldReferenceType(dependencyGraph, p)) .ToSet(); return(projectsThatCouldReferenceType); } else { // For a source project, find the project that that type was defined in. var sourceProject = solution.GetProject(type.ContainingAssembly, cancellationToken); if (sourceProject == null) { return(SpecializedCollections.EmptySet <ProjectId>()); } // Now find all the dependent of those projects. var projectsThatCouldReferenceType = GetProjectsThatCouldReferenceType( dependencyGraph, sourceProject ) .ToSet(); return(projectsThatCouldReferenceType); } }
private ISet <INamedTypeSymbol> ComputeOuterTypes(CancellationToken cancellationToken) { var enclosingSymbol = this.SemanticModel.GetEnclosingSymbol(this.LeftToken.SpanStart, cancellationToken); if (enclosingSymbol != null) { var containingType = enclosingSymbol.GetContainingTypeOrThis(); if (containingType != null) { return(containingType.GetContainingTypes().ToSet()); } } return(SpecializedCollections.EmptySet <INamedTypeSymbol>()); }
[InlineData(true)] // use same tests against a BCL implementation to demonstrate test correctness. public void EmptySetRespectsInterfaceContract(bool useReferenceImplementation) { var emptySet = useReferenceImplementation ? ImmutableHashSet <int> .Empty : SpecializedCollections.EmptySet <int>(); // IEnumerable Assert.Empty(emptySet); Assert.False(emptySet.GetEnumerator().MoveNext()); Assert.False(((IEnumerable)emptySet).GetEnumerator().MoveNext()); // ICollection (read-only safe) Assert.Equal(0, emptySet.Count); Assert.True(emptySet.IsReadOnly); Assert.False(emptySet.Contains(0)); emptySet.CopyTo(new int[0], 0); // should not throw // ICollection (not supported when read-only) Assert.Throws <NotSupportedException>(() => ((ICollection <int>)(emptySet)).Add(0)); Assert.Throws <NotSupportedException>(() => emptySet.Remove(0)); Assert.Throws <NotSupportedException>(() => emptySet.Clear()); // ISet (read-only safe) Assert.False(emptySet.IsProperSubsetOf(new int[0])); Assert.True(emptySet.IsProperSubsetOf(new int[1])); Assert.False(emptySet.IsProperSupersetOf(new int[0])); Assert.False(emptySet.IsProperSupersetOf(new int[1])); Assert.True(emptySet.IsSubsetOf(new int[0])); Assert.True(emptySet.IsSubsetOf(new int[1])); Assert.True(emptySet.IsSupersetOf(new int[0])); Assert.False(emptySet.IsSupersetOf(new int[1])); Assert.False(emptySet.Overlaps(new int[0])); Assert.False(emptySet.Overlaps(new int[1])); Assert.True(emptySet.SetEquals(new int[0])); Assert.False(emptySet.SetEquals(new int[1])); // ISet (not supported when read-only) Assert.Throws <NotSupportedException>(() => emptySet.Add(0)); Assert.Throws <NotSupportedException>(() => emptySet.ExceptWith(new int[0])); Assert.Throws <NotSupportedException>(() => emptySet.IntersectWith(new int[0])); Assert.Throws <NotSupportedException>(() => emptySet.SymmetricExceptWith(new int[0])); Assert.Throws <NotSupportedException>(() => emptySet.UnionWith(new int[0])); }
public static ISet <INamespaceSymbol> GetUsingNamespacesInScope(this SemanticModel semanticModel, SyntaxNode location) { // Avoiding linq here for perf reasons. This is used heavily in the AddImport service HashSet <INamespaceSymbol> result = null; foreach (var @using in location.GetEnclosingUsingDirectives()) { if (@using.Alias == null) { var symbolInfo = semanticModel.GetSymbolInfo(@using.Name); if (symbolInfo.Symbol != null && symbolInfo.Symbol.Kind == SymbolKind.Namespace) { result = result ?? new HashSet <INamespaceSymbol>(); result.Add((INamespaceSymbol)symbolInfo.Symbol); } } } return(result ?? SpecializedCollections.EmptySet <INamespaceSymbol>()); }
public Session(RenameLocationSet renameLocationSet, Location renameSymbolDeclarationLocation, string originalText, string replacementText, OptionSet optionSet, CancellationToken cancellationToken) { this.renameLocationSet = renameLocationSet; this.renameSymbolDeclarationLocation = renameSymbolDeclarationLocation; this.originalText = originalText; this.replacementText = replacementText; this.optionSet = optionSet; this.cancellationToken = cancellationToken; this.renamedSymbolDeclarationAnnotation = new RenameAnnotation(); this.conflictLocations = SpecializedCollections.EmptySet <ConflictLocationInfo>(); this.replacementTextValid = true; this.possibleNameConflicts = new List <string>(); // only process documents which possibly contain the identifiers. this.documentsIdsToBeCheckedForConflict = new HashSet <DocumentId>(); this.documentIdOfRenameSymbolDeclaration = renameLocationSet.Solution.GetDocument(renameSymbolDeclarationLocation.SourceTree).Id; this.renameAnnotations = new AnnotationTable <RenameAnnotation>(RenameAnnotation.Kind); }
private async Task <Result> EncapsulateFieldAsync(IFieldSymbol field, Document document, bool updateReferences, CancellationToken cancellationToken) { var originalField = field; var finalNames = GeneratePropertyAndFieldNames(field); var finalFieldName = finalNames.Item1; var generatedPropertyName = finalNames.Item2; // Annotate the field declarations so we can find it after rename. var fieldDeclaration = field.DeclaringSyntaxReferences.First(); var declarationAnnotation = new SyntaxAnnotation(); document = document.WithSyntaxRoot(fieldDeclaration.SyntaxTree.GetRoot().ReplaceNode(fieldDeclaration.GetSyntax(), fieldDeclaration.GetSyntax().WithAdditionalAnnotations(declarationAnnotation))); var solution = document.Project.Solution; foreach (var linkedDocumentId in document.GetLinkedDocumentIds()) { var linkedDocument = solution.GetDocument(linkedDocumentId); var linkedRoot = await linkedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var linkedFieldNode = linkedRoot.FindNode(fieldDeclaration.Span); if (linkedFieldNode.Span != fieldDeclaration.Span) { continue; } var updatedRoot = linkedRoot.ReplaceNode(linkedFieldNode, linkedFieldNode.WithAdditionalAnnotations(declarationAnnotation)); solution = solution.WithDocumentSyntaxRoot(linkedDocumentId, updatedRoot); } document = solution.GetDocument(document.Id); // Resolve the annotated symbol and prepare for rename. var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var compilation = semanticModel.Compilation; field = field.GetSymbolKey().Resolve(compilation).Symbol as IFieldSymbol; Solution solutionNeedingProperty = null; // We couldn't resolve field after annotating its declaration. Bail if (field == null) { return(null); } if (updateReferences) { var locationsToIgnore = SpecializedCollections.EmptySet <TextSpan>(); var optionSet = document.Project.Solution.Workspace.Options; if (field.IsReadOnly) { var locationSet = await RenameLocationSet.FindAsync(field, document.Project.Solution, optionSet, cancellationToken).ConfigureAwait(false); var constructorSyntaxes = GetConstructorNodes(field.ContainingType); var locations = locationSet.Locations.Where(l => constructorSyntaxes.Any(c => c.Span.IntersectsWith(l.Location.SourceSpan))); if (locations.Any()) { locationsToIgnore = locations.Select(l => l.Location.SourceSpan).ToSet(); locationSet = new RenameLocationSet(locations.ToSet(), field, document.Project.Solution, locationSet.ReferencedSymbols, locationSet.ImplicitLocations); var resolution = await ConflictResolver.ResolveConflictsAsync(locationSet, field.Name, finalFieldName, optionSet, cancellationToken).ConfigureAwait(false); document = resolution.NewSolution.GetDocument(document.Id); semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); compilation = semanticModel.Compilation; field = field.GetSymbolKey().Resolve(compilation).Symbol as IFieldSymbol; } } var renameLocationSet = await RenameLocationSet.FindAsync(field, document.Project.Solution, optionSet, cancellationToken).ConfigureAwait(false); renameLocationSet = new RenameLocationSet(renameLocationSet.Locations.Where(l => !locationsToIgnore.Contains(l.Location.SourceSpan)).ToSet(), renameLocationSet.Symbol, renameLocationSet.Solution, renameLocationSet.ReferencedSymbols, renameLocationSet.ImplicitLocations); if (renameLocationSet.Locations.Any() || renameLocationSet.ImplicitLocations.Any()) { var conflictResolution = await ConflictResolver.ResolveConflictsAsync(renameLocationSet, field.Name, generatedPropertyName, optionSet, cancellationToken).ConfigureAwait(false); if (!conflictResolution.ReplacementTextValid) { return(null); } solutionNeedingProperty = conflictResolution.NewSolution; document = solutionNeedingProperty.GetDocument(document.Id); } } else { solutionNeedingProperty = document.Project.Solution; document = solutionNeedingProperty.GetDocument(document.Id); } var markFieldPrivate = field.DeclaredAccessibility != Accessibility.Private; var rewrittenFieldDeclaration = await RewriteFieldNameAndAccessibility(finalFieldName, markFieldPrivate, document, declarationAnnotation, cancellationToken).ConfigureAwait(false); document = await Formatter.FormatAsync(document.WithSyntaxRoot(rewrittenFieldDeclaration), Formatter.Annotation, cancellationToken : cancellationToken).ConfigureAwait(false); solution = document.Project.Solution; foreach (var linkedDocumentId in document.GetLinkedDocumentIds()) { var linkedDocument = solution.GetDocument(linkedDocumentId); var updatedLinkedRoot = await RewriteFieldNameAndAccessibility(finalFieldName, markFieldPrivate, linkedDocument, declarationAnnotation, cancellationToken).ConfigureAwait(false); var updatedLinkedDocument = await Formatter.FormatAsync(linkedDocument.WithSyntaxRoot(updatedLinkedRoot), Formatter.Annotation, cancellationToken : cancellationToken).ConfigureAwait(false); solution = updatedLinkedDocument.Project.Solution; } document = solution.GetDocument(document.Id); semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); compilation = semanticModel.Compilation; var newRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var newDeclaration = newRoot.GetAnnotatedNodes <SyntaxNode>(declarationAnnotation).First(); field = semanticModel.GetDeclaredSymbol(newDeclaration, cancellationToken) as IFieldSymbol; var generatedProperty = GenerateProperty(generatedPropertyName, finalFieldName, originalField.DeclaredAccessibility, originalField, field.ContainingType, new SyntaxAnnotation(), document, cancellationToken); var codeGenerationService = document.GetLanguageService <ICodeGenerationService>(); var solutionWithProperty = await AddPropertyAsync(document, document.Project.Solution, field, generatedProperty, cancellationToken).ConfigureAwait(false); return(new Result(solutionWithProperty, originalField.ToDisplayString(), originalField.GetGlyph())); }
/// <summary> /// Calculate the set of changes up to top-level types. The result /// will be used as a filter when traversing the module. /// /// Note that these changes only include user-defined source symbols, not synthesized symbols since those will be /// generated during lowering of the changed user-defined symbols. /// </summary> private static void CalculateChanges(IEnumerable <SemanticEdit> edits, out IReadOnlyDictionary <ISymbol, SymbolChange> changes, out ISet <ISymbol> replaceSymbols, out IReadOnlyDictionary <ISymbol, ISet <ISymbol> > deletedMembers) { var changesBuilder = new Dictionary <ISymbol, SymbolChange>(); HashSet <ISymbol>?lazyReplaceSymbolsBuilder = null; Dictionary <ISymbol, ISet <ISymbol> >?lazyDeletedMembersBuilder = null; foreach (var edit in edits) { SymbolChange change; switch (edit.Kind) { case SemanticEditKind.Update: change = SymbolChange.Updated; break; case SemanticEditKind.Insert: change = SymbolChange.Added; break; case SemanticEditKind.Replace: Debug.Assert(edit.NewSymbol != null); (lazyReplaceSymbolsBuilder ??= new HashSet <ISymbol>()).Add(edit.NewSymbol); change = SymbolChange.Added; break; case SemanticEditKind.Delete: // We allow method deletions only at the moment. // For deletions NewSymbol is actually containing symbol if (edit.OldSymbol is IMethodSymbol && edit.NewSymbol is { } newContainingSymbol) { Debug.Assert(edit.OldSymbol != null); lazyDeletedMembersBuilder ??= new(); if (!lazyDeletedMembersBuilder.TryGetValue(newContainingSymbol, out var set)) { set = new HashSet <ISymbol>(); lazyDeletedMembersBuilder.Add(newContainingSymbol, set); } set.Add(edit.OldSymbol); // We need to make sure we track the containing type of the member being // deleted, from the new compilation, in case the deletion is the only change. if (!changesBuilder.ContainsKey(newContainingSymbol)) { changesBuilder.Add(newContainingSymbol, SymbolChange.ContainsChanges); AddContainingTypesAndNamespaces(changesBuilder, newContainingSymbol); } } continue; default: throw ExceptionUtilities.UnexpectedValue(edit.Kind); } var member = edit.NewSymbol; RoslynDebug.AssertNotNull(member); // Partial methods are supplied as implementations but recorded // internally as definitions since definitions are used in emit. if (member.Kind == SymbolKind.Method) { var method = (IMethodSymbol)member; // Partial methods should be implementations, not definitions. Debug.Assert(method.PartialImplementationPart == null); Debug.Assert((edit.OldSymbol == null) || (((IMethodSymbol)edit.OldSymbol).PartialImplementationPart == null)); var definitionPart = method.PartialDefinitionPart; if (definitionPart != null) { member = definitionPart; } } AddContainingTypesAndNamespaces(changesBuilder, member); changesBuilder.Add(member, change); } changes = changesBuilder; replaceSymbols = lazyReplaceSymbolsBuilder ?? SpecializedCollections.EmptySet <ISymbol>(); deletedMembers = lazyDeletedMembersBuilder ?? SpecializedCollections.EmptyReadOnlyDictionary <ISymbol, ISet <ISymbol> >(); }