Exemple #1
0
            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);
            }
Exemple #2
0
        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>();
        }
Exemple #4
0
        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]));
        }
Exemple #7
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);
            }
Exemple #9
0
        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()));
        }
Exemple #10
0
        /// <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> >();
        }