Example #1
0
        private static Solution ObfuscateNames(Solution solution, List <DocumentId> documents, ObfuscationOptions obfuscationOptions)
        {
            #region RENAMER

            #region Rename classes
            if ((obfuscationOptions & ObfuscationOptions.CLASS) != 0)
            {
                Console.WriteLine("----------------------------------CLASSES----------------------------------");
                using (Watcher.Start(ts => Console.WriteLine("Timed: " + ts.ToString())))
                {
                    foreach (var documentId in documents)
                    {
                        while (true)
                        {
                            var doc     = solution.GetDocument(documentId);
                            var model   = doc.GetSemanticModelAsync().Result;
                            var syntax  = doc.GetSyntaxRootAsync().Result;
                            var classes = syntax.DescendantNodes()
                                          .OfType <ClassDeclarationSyntax>()
                                          .Where(x => !x.Identifier.ValueText.StartsWith("_") && x.Identifier.ValueText.IndexOf("ignore", StringComparison.OrdinalIgnoreCase) < 0)
                                          .ToList();

                            var cl = classes.FirstOrDefault();
                            if (cl == null)
                            {
                                break;
                            }
                            var symbol  = model.GetDeclaredSymbol(cl);
                            var newName = "_" + Utils.RandomString();
                            Console.WriteLine("Renaming class: " + cl.Identifier.ValueText + " to " + newName);
                            solution = Renamer.RenameSymbolAsync(solution, symbol, newName, null).Result;
                        }
                    }
                }
            }
            #endregion

            #region Rename methods
            if ((obfuscationOptions & ObfuscationOptions.METHODS) != 0)
            {
                Console.WriteLine("----------------------------------METHODS----------------------------------");
                using (Watcher.Start(ts => Console.WriteLine("Timed: " + ts.ToString())))
                {
                    foreach (var documentId in documents)
                    {
                        List <MethodDeclarationSyntax> methods;
                        int i;
                        do
                        {
                            var doc    = solution.GetDocument(documentId);
                            var model  = doc.GetSemanticModelAsync().Result;
                            var syntax = doc.GetSyntaxRootAsync().Result;
                            methods = syntax.DescendantNodes()
                                      .OfType <MethodDeclarationSyntax>()
                                      .Where(x => !x.Identifier.ValueText.StartsWith("_") && !x.Identifier.ToString().Equals("dispose", StringComparison.OrdinalIgnoreCase) && x.Modifiers.Count(z => z.IsKind(SyntaxKind.ProtectedKeyword) || z.IsKind(SyntaxKind.OverrideKeyword)) == 0)
                                      .ToList();

                            for (i = 0; i < methods.Count; i++)
                            {
                                var ms     = methods[i];
                                var symbol = model.GetDeclaredSymbol(ms);

                                if (ms.GetLeadingTrivia().ToString().IndexOf("ignore", StringComparison.OrdinalIgnoreCase) >= 0)
                                {
                                    continue;
                                }

                                var refcount = 0;
                                foreach (var rf in SymbolFinder.FindReferencesAsync(symbol, doc.Project.Solution).Result)
                                {
                                    refcount += rf.Locations.Count();
                                }
                                if (refcount <= 0)
                                {
                                    continue;
                                }

                                var newName = "_" + Utils.RandomString();
                                Console.WriteLine("Renaming method (" + refcount + "): " + ms.Identifier.ValueText + " to " + newName + $" {ms.Kind()} {string.Join(",", ms.Modifiers)}");
                                solution = Renamer.RenameSymbolAsync(solution, symbol, newName, null).Result;
                                break;
                            }
                        } while (i < methods.Count);
                    }
                }
            }
            #endregion

            #region Rename variables
            if ((obfuscationOptions & ObfuscationOptions.VARS) != 0)
            {
                Console.WriteLine("----------------------------------VARS&FIELDS----------------------------------");
                using (Watcher.Start(ts => Console.WriteLine("Timed: " + ts.ToString())))
                {
                    foreach (var documentId in documents)
                    {
                        List <VariableDeclarationSyntax> vars;
                        int i;
                        do
                        {
                            var doc    = solution.GetDocument(documentId);
                            var model  = doc.GetSemanticModelAsync().Result;
                            var syntax = doc.GetSyntaxRootAsync().Result;
                            vars = syntax.DescendantNodes()
                                   .OfType <VariableDeclarationSyntax>()
                                   .Where(x => x.Variables.Count(z => !z.Identifier.ValueText.StartsWith("_")) > 0)
                                   .ToList();

                            for (i = 0; i < vars.Count; i++)
                            {
                                bool end = true;
                                foreach (var vr in vars[i].Variables)
                                {
                                    if (vr.Identifier.ValueText.StartsWith("_"))
                                    {
                                        continue;
                                    }

                                    var symbol = model.GetDeclaredSymbol(vr);

                                    if (vr.GetLeadingTrivia().ToString().IndexOf("ignore", StringComparison.OrdinalIgnoreCase) >= 0)
                                    {
                                        continue;
                                    }

                                    var newName = "_" + Utils.RandomString();
                                    Console.WriteLine("Renaming variable: " + vr.Identifier.ValueText + " to " + newName + $" {vr.Kind()}");
                                    solution = Renamer.RenameSymbolAsync(solution, symbol, newName, null).Result;
                                    end      = true;
                                    break;
                                }
                                if (end)
                                {
                                    break;
                                }
                            }
                        } while (i < vars.Count);
                    }
                }
            }
            #endregion

            if ((obfuscationOptions & ObfuscationOptions.OTHERS) != 0)
            {
                #region Rename Enums
                Console.WriteLine("----------------------------------ENUMS----------------------------------");
                using (Watcher.Start(ts => Console.WriteLine("Timed: " + ts.ToString())))
                {
                    foreach (var documentId in documents)
                    {
                        List <EnumDeclarationSyntax> vars;
                        int i;
                        do
                        {
                            var doc    = solution.GetDocument(documentId);
                            var model  = doc.GetSemanticModelAsync().Result;
                            var syntax = doc.GetSyntaxRootAsync().Result;
                            vars = syntax.DescendantNodes()
                                   .OfType <EnumDeclarationSyntax>()
                                   .Where(x => !x.Identifier.ValueText.StartsWith("_"))
                                   .ToList();

                            for (i = 0; i < vars.Count; i++)
                            {
                                var vr = vars[i];
                                if (vr.Identifier.ValueText.StartsWith("_"))
                                {
                                    continue;
                                }

                                var symbol = model.GetDeclaredSymbol(vr);

                                if (vr.GetLeadingTrivia().ToString().IndexOf("ignore", StringComparison.OrdinalIgnoreCase) >= 0)
                                {
                                    continue;
                                }

                                var newName = "_" + Utils.RandomString();
                                Console.WriteLine("Renaming ENUM: " + vr.Identifier.ValueText + " to " + newName + $" {vr.Kind()}");
                                solution = Renamer.RenameSymbolAsync(solution, symbol, newName, null).Result;
                                break;
                            }
                        } while (i < vars.Count);
                    }
                }

                Console.WriteLine("----------------------------------ENUM MEMBERS----------------------------------");
                using (Watcher.Start(ts => Console.WriteLine("Timed: " + ts.ToString())))
                {
                    foreach (var documentId in documents)
                    {
                        List <EnumMemberDeclarationSyntax> vars;
                        int i;
                        do
                        {
                            var doc    = solution.GetDocument(documentId);
                            var model  = doc.GetSemanticModelAsync().Result;
                            var syntax = doc.GetSyntaxRootAsync().Result;
                            vars = syntax.DescendantNodes()
                                   .OfType <EnumMemberDeclarationSyntax>()
                                   .Where(x => !x.Identifier.ValueText.StartsWith("_"))
                                   .ToList();

                            for (i = 0; i < vars.Count; i++)
                            {
                                var vr = vars[i];
                                if (vr.Identifier.ValueText.StartsWith("_"))
                                {
                                    continue;
                                }

                                var symbol = model.GetDeclaredSymbol(vr);

                                if (vr.GetLeadingTrivia().ToString().IndexOf("ignore", StringComparison.OrdinalIgnoreCase) >= 0)
                                {
                                    continue;
                                }

                                var newName = "_" + Utils.RandomString();
                                Console.WriteLine("Renaming ENUM member: " + vr.Identifier.ValueText + " to " + newName + $" {vr.Kind()}");
                                solution = Renamer.RenameSymbolAsync(solution, symbol, newName, null).Result;
                                break;
                            }
                        } while (i < vars.Count);
                    }
                }

                #endregion

                #region Rename Structs
                Console.WriteLine("----------------------------------STRUCTS----------------------------------");
                using (Watcher.Start(ts => Console.WriteLine("Timed: " + ts.ToString())))
                {
                    foreach (var documentId in documents)
                    {
                        List <StructDeclarationSyntax> vars;
                        int i;
                        do
                        {
                            var doc    = solution.GetDocument(documentId);
                            var model  = doc.GetSemanticModelAsync().Result;
                            var syntax = doc.GetSyntaxRootAsync().Result;
                            vars = syntax.DescendantNodes()
                                   .OfType <StructDeclarationSyntax>()
                                   .Where(x => !x.Identifier.ValueText.StartsWith("_"))
                                   .ToList();

                            for (i = 0; i < vars.Count; i++)
                            {
                                var vr = vars[i];
                                if (vr.Identifier.ValueText.StartsWith("_"))
                                {
                                    continue;
                                }

                                var symbol = model.GetDeclaredSymbol(vr);

                                if (vr.GetLeadingTrivia().ToString().IndexOf("ignore", StringComparison.OrdinalIgnoreCase) >= 0)
                                {
                                    continue;
                                }

                                var newName = "_" + Utils.RandomString();
                                Console.WriteLine("Renaming STRUCTS: " + vr.Identifier.ValueText + " to " + newName + $" {vr.Kind()}");
                                solution = Renamer.RenameSymbolAsync(solution, symbol, newName, null).Result;
                                break;
                            }
                        } while (i < vars.Count);
                    }
                }
                #endregion
            }

            return(solution);

            #endregion
        }
        public async Task <GotoDefinitionResponse> Handle(GotoDefinitionRequest request)
        {
            var externalSourceService = _externalSourceServiceFactory.Create(_omnisharpOptions);
            var document = externalSourceService.FindDocumentInCache(request.FileName) ??
                           _workspace.GetDocument(request.FileName);

            var response = new GotoDefinitionResponse();

            if (document != null)
            {
                var semanticModel = await document.GetSemanticModelAsync();

                var sourceText = await document.GetTextAsync();

                var position = sourceText.Lines.GetPosition(new LinePosition(request.Line, request.Column));
                var symbol   = await SymbolFinder.FindSymbolAtPositionAsync(semanticModel, position, _workspace);

                // go to definition for namespaces is not supported
                if (symbol != null && !(symbol is INamespaceSymbol))
                {
                    // for partial methods, pick the one with body
                    if (symbol is IMethodSymbol method)
                    {
                        // Return an empty response for property accessor symbols like get and set
                        if (method.AssociatedSymbol is IPropertySymbol)
                        {
                            return(response);
                        }

                        symbol = method.PartialImplementationPart ?? symbol;
                    }

                    var location = symbol.Locations.First();

                    if (location.IsInSource)
                    {
                        var lineSpan = symbol.Locations.First().GetMappedLineSpan();
                        response = new GotoDefinitionResponse
                        {
                            FileName = lineSpan.Path,
                            Line     = lineSpan.StartLinePosition.Line,
                            Column   = lineSpan.StartLinePosition.Character
                        };
                    }
                    else if (location.IsInMetadata && request.WantMetadata)
                    {
                        var cancellationToken = _externalSourceServiceFactory.CreateCancellationToken(_omnisharpOptions, request.Timeout);
                        var(metadataDocument, _) = await externalSourceService.GetAndAddExternalSymbolDocument(document.Project, symbol, cancellationToken);

                        if (metadataDocument != null)
                        {
                            cancellationToken = _externalSourceServiceFactory.CreateCancellationToken(_omnisharpOptions, request.Timeout);
                            var metadataLocation = await externalSourceService.GetExternalSymbolLocation(symbol, metadataDocument, cancellationToken);

                            var lineSpan = metadataLocation.GetMappedLineSpan();

                            response = new GotoDefinitionResponse
                            {
                                Line           = lineSpan.StartLinePosition.Line,
                                Column         = lineSpan.StartLinePosition.Character,
                                MetadataSource = new MetadataSource()
                                {
                                    AssemblyName = symbol.ContainingAssembly.Name,
                                    ProjectName  = document.Project.Name,
                                    TypeName     = symbol.GetSymbolName()
                                },
                            };
                        }
                    }
                }
            }

            return(response);
        }
Example #3
0
        public static async Task <ISymbol> GetRenameSymbol(
            Document document, SyntaxToken triggerToken, CancellationToken cancellationToken)
        {
            var syntaxFactsService = document.Project.LanguageServices.GetService <ISyntaxFactsService>();

            if (syntaxFactsService.IsKeyword(triggerToken))
            {
                return(null);
            }

            var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var semanticFacts = document.GetLanguageService <ISemanticFactsService>();

            var tokenRenameInfo = RenameUtilities.GetTokenRenameInfo(semanticFacts, semanticModel, triggerToken, cancellationToken);

            // Rename was invoked on a member group reference in a nameof expression.
            // Trigger the rename on any of the candidate symbols but force the
            // RenameOverloads option to be on.
            var triggerSymbol = tokenRenameInfo.HasSymbols ? tokenRenameInfo.Symbols.First() : null;

            if (triggerSymbol == null)
            {
                return(null);
            }

            // see https://github.com/dotnet/roslyn/issues/10898
            // we are disabling rename for tuple fields for now
            // 1) compiler does not return correct location information in these symbols
            // 2) renaming tuple fields seems a complex enough thing to require some design
            if (triggerSymbol.ContainingType?.IsTupleType == true)
            {
                return(null);
            }

            // If rename is invoked on a member group reference in a nameof expression, then the
            // RenameOverloads option should be forced on.
            var forceRenameOverloads = tokenRenameInfo.IsMemberGroup;

            if (syntaxFactsService.IsTypeNamedVarInVariableOrFieldDeclaration(triggerToken, triggerToken.Parent))
            {
                // To check if var in this context is a real type, or the keyword, we need to
                // speculatively bind the identifier "var". If it returns a symbol, it's a real type,
                // if not, it's the keyword.
                // see bugs 659683 (compiler API) and 659705 (rename/workspace api) for examples
                var symbolForVar = semanticModel.GetSpeculativeSymbolInfo(
                    triggerToken.SpanStart,
                    triggerToken.Parent,
                    SpeculativeBindingOption.BindAsTypeOrNamespace).Symbol;

                if (symbolForVar == null)
                {
                    return(null);
                }
            }

            var symbolAndProjectId = await RenameLocations.ReferenceProcessing.GetRenamableSymbolAsync(document, triggerToken.SpanStart, cancellationToken : cancellationToken).ConfigureAwait(false);

            var symbol = symbolAndProjectId.Symbol;

            if (symbol == null)
            {
                return(null);
            }

            if (symbol.Kind == SymbolKind.Alias && symbol.IsExtern)
            {
                return(null);
            }

            // Cannot rename constructors in VB.  TODO: this logic should be in the VB subclass of this type.
            var workspace = document.Project.Solution.Workspace;

            if (symbol.Kind == SymbolKind.NamedType &&
                symbol.Language == LanguageNames.VisualBasic &&
                triggerToken.ToString().Equals("New", StringComparison.OrdinalIgnoreCase))
            {
                var originalSymbol = await SymbolFinder.FindSymbolAtPositionAsync(semanticModel, triggerToken.SpanStart, workspace, cancellationToken : cancellationToken);

                if (originalSymbol != null && originalSymbol.IsConstructor())
                {
                    return(null);
                }
            }

            if (syntaxFactsService.IsTypeNamedDynamic(triggerToken, triggerToken.Parent))
            {
                if (symbol.Kind == SymbolKind.DynamicType)
                {
                    return(null);
                }
            }

            // we allow implicit locals and parameters of Event handlers
            if (symbol.IsImplicitlyDeclared &&
                symbol.Kind != SymbolKind.Local &&
                !(symbol.Kind == SymbolKind.Parameter &&
                  symbol.ContainingSymbol.Kind == SymbolKind.Method &&
                  symbol.ContainingType != null &&
                  symbol.ContainingType.IsDelegateType() &&
                  symbol.ContainingType.AssociatedSymbol != null))
            {
                // We enable the parameter in RaiseEvent, if the Event is declared with a signature. If the Event is declared as a
                // delegate type, we do not have a connection between the delegate type and the event.
                // this prevents a rename in this case :(.
                return(null);
            }

            if (symbol.Kind == SymbolKind.Property && symbol.ContainingType.IsAnonymousType)
            {
                return(null);
            }

            if (symbol.IsErrorType())
            {
                return(null);
            }

            if (symbol.Kind == SymbolKind.Method && ((IMethodSymbol)symbol).MethodKind == MethodKind.UserDefinedOperator)
            {
                return(null);
            }

            var symbolLocations = symbol.Locations;

            // Does our symbol exist in an unchangeable location?
            foreach (var location in symbolLocations)
            {
                if (location.IsInMetadata)
                {
                    return(null);
                }
                if (location.IsInSource)
                {
                    if (document.Project.IsSubmission)
                    {
                        var solution            = document.Project.Solution;
                        var projectIdOfLocation = solution.GetDocument(location.SourceTree).Project.Id;

                        if (solution.Projects.Any(p => p.IsSubmission && p.ProjectReferences.Any(r => r.ProjectId == projectIdOfLocation)))
                        {
                            return(null);
                        }
                    }
                }
                else
                {
                    return(null);
                }
            }

            return(symbol);
        }
Example #4
0
        public static ImmutableArray <DefinitionItem> GetDefinitions(
            ISymbol symbol,
            Solution solution,
            bool thirdPartyNavigationAllowed,
            CancellationToken cancellationToken)
        {
            var alias = symbol as IAliasSymbol;

            if (alias != null)
            {
                if (alias.Target is INamespaceSymbol ns && ns.IsGlobalNamespace)
                {
                    return(ImmutableArray.Create <DefinitionItem>());
                }
            }

            // VB global import aliases have a synthesized SyntaxTree.
            // We can't go to the definition of the alias, so use the target type.

            if (alias != null)
            {
                var sourceLocations = NavigableItemFactory.GetPreferredSourceLocations(
                    solution, symbol, cancellationToken);

                if (sourceLocations.All(l => solution.GetDocument(l.SourceTree) == null))
                {
                    symbol = alias.Target;
                }
            }

            var definition = SymbolFinder.FindSourceDefinitionAsync(symbol, solution, cancellationToken).WaitAndGetResult(cancellationToken);

            cancellationToken.ThrowIfCancellationRequested();

            symbol = definition ?? symbol;

            // If it is a partial method declaration with no body, choose to go to the implementation
            // that has a method body.
            if (symbol is IMethodSymbol method)
            {
                symbol = method.PartialImplementationPart ?? symbol;
            }

            using var definitionsDisposer = ArrayBuilder <DefinitionItem> .GetInstance(out var definitions);

            // Going to a symbol may end up actually showing the symbol in the Find-Usages window.
            // This happens when there is more than one location for the symbol (i.e. for partial
            // symbols) and we don't know the best place to take you to.
            //
            // The FindUsages window supports showing the classified text for an item.  It does this
            // in two ways.  Either the item can pass along its classified text (and the window will
            // defer to that), or the item will have no classified text, and the window will compute
            // it in the BG.
            //
            // Passing along the classified information is valuable for OOP scenarios where we want
            // all that expensive computation done on the OOP side and not in the VS side.
            //
            // However, Go To Definition is all in-process, and is also synchronous.  So we do not
            // want to fetch the classifications here.  It slows down the command and leads to a
            // measurable delay in our perf tests.
            //
            // So, if we only have a single location to go to, this does no unnecessary work.  And,
            // if we do have multiple locations to show, it will just be done in the BG, unblocking
            // this command thread so it can return the user faster.
            var definitionItem = symbol.ToNonClassifiedDefinitionItem(solution, includeHiddenLocations: true);

            if (thirdPartyNavigationAllowed)
            {
                var factory        = solution.Workspace.Services.GetService <IDefinitionsAndReferencesFactory>();
                var thirdPartyItem = factory?.GetThirdPartyDefinitionItem(solution, definitionItem, cancellationToken);
                definitions.AddIfNotNull(thirdPartyItem);
            }

            definitions.Add(definitionItem);
            return(definitions.ToImmutable());
        }
Example #5
0
        public void AugmentPeekSession(IPeekSession session, IList <IPeekableItem> peekableItems)
        {
            if (!string.Equals(session.RelationshipName, PredefinedPeekRelationships.Definitions.Name, StringComparison.OrdinalIgnoreCase))
            {
                return;
            }

            var triggerPoint = session.GetTriggerPoint(_textBuffer.CurrentSnapshot);

            if (!triggerPoint.HasValue)
            {
                return;
            }

            var document = triggerPoint.Value.Snapshot.GetOpenDocumentInCurrentContextWithChanges();

            if (document == null)
            {
                return;
            }

            _waitIndicator.Wait(EditorFeaturesResources.Peek, EditorFeaturesResources.Loading_Peek_information, allowCancel: true, action: context =>
            {
                var cancellationToken = context.CancellationToken;

                IEnumerable <IPeekableItem> results;

                if (!document.SupportsSemanticModel)
                {
                    // For documents without semantic models, just try to use the goto-def service
                    // as a reasonable place to peek at.
                    var goToDefinitionService = document.GetLanguageService <IGoToDefinitionService>();
                    if (goToDefinitionService == null)
                    {
                        return;
                    }

                    var navigableItems = goToDefinitionService.FindDefinitionsAsync(document, triggerPoint.Value.Position, cancellationToken)
                                         .WaitAndGetResult(cancellationToken);

                    results = GetPeekableItemsForNavigableItems(navigableItems, document.Project, _peekResultFactory, cancellationToken);
                }
                else
                {
                    var semanticModel = document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult(cancellationToken);
                    var symbol        = SymbolFinder.GetSemanticInfoAtPositionAsync(
                        semanticModel,
                        triggerPoint.Value.Position,
                        document.Project.Solution.Workspace,
                        cancellationToken).WaitAndGetResult(cancellationToken)
                                        .GetAnySymbol(includeType: true);

                    if (symbol == null)
                    {
                        return;
                    }

                    symbol = symbol.GetOriginalUnreducedDefinition();

                    // Get the symbol back from the originating workspace
                    var symbolMappingService = document.Project.Solution.Workspace.Services.GetRequiredService <ISymbolMappingService>();

                    var mappingResult = symbolMappingService.MapSymbolAsync(document, symbol, cancellationToken)
                                        .WaitAndGetResult(cancellationToken);

                    mappingResult ??= new SymbolMappingResult(document.Project, symbol);

                    results = _peekableItemFactory.GetPeekableItemsAsync(mappingResult.Symbol, mappingResult.Project, _peekResultFactory, cancellationToken)
                              .WaitAndGetResult(cancellationToken);
                }

                peekableItems.AddRange(results);
            });
        }
Example #6
0
        /// <summary>
        /// This will identify the <paramref name="syntaxNode"/> vulnerable or not
        /// </summary>
        /// <param name="syntaxNode"></param>
        /// <param name="model"></param>
        /// <param name="solution"></param>
        /// <returns></returns>
        private bool IsVulnerable(SyntaxNode syntaxNode, SemanticModel model, Solution solution)
        {
            bool    vulnerable = true;
            ISymbol symbol;

            switch (syntaxNode.Kind())
            {
            case SyntaxKind.InvocationExpression:
                symbol = model.GetSymbol(syntaxNode);
                if (symbol.Name == "MustVerifySignature")
                {
                    vulnerable = false;
                }
                //else if (symbol.Name == "DoNotVerifySignature")
                //    vulnerable = true;
                else if (symbol.Name == "WithVerifySignature")
                {
                    var invocation    = syntaxNode as InvocationExpressionSyntax;
                    var argumentValue = model.GetConstantValue(invocation.ArgumentList.Arguments.First().Expression);
                    if (!argumentValue.HasValue)
                    {
                        vulnerable = false;
                    }
                    else if (argumentValue.Value is bool value && value)
                    {
                        vulnerable = false;
                    }
                }
                else if (symbol.DeclaringSyntaxReferences.Count() > 0)
                {
                    SyntaxReference syntaxReference = symbol.DeclaringSyntaxReferences.First();
                    var             declaration     = syntaxReference.GetSyntaxAsync().Result;
                    var             methodModel     = model.Compilation.GetSemanticModel(syntaxReference.SyntaxTree);
                    vulnerable = IsVulnerable(declaration, methodModel, solution);
                }
                return(vulnerable);

            case SyntaxKind.IdentifierName:
                symbol = model.GetSymbol(syntaxNode);
                if (symbol.DeclaringSyntaxReferences.Length > 0)
                {
                    SyntaxReference syntaxReference = symbol.DeclaringSyntaxReferences.First();
                    vulnerable = IsVulnerable(syntaxReference.GetSyntax(), model.Compilation.GetSemanticModel(syntaxReference.SyntaxTree), solution);
                }
                var referencedSymbols = SymbolFinder.FindReferencesAsync(symbol, solution).Result;
                foreach (var referencedSymbol in referencedSymbols)
                {
                    foreach (var referenceLocation in referencedSymbol.Locations)
                    {
                        if (referenceLocation.Location.SourceSpan.Start < syntaxNode.SpanStart)
                        {
                            syntaxNode = referenceLocation.Location.SourceTree.GetRootAsync().Result.FindNode(referenceLocation.Location.SourceSpan);
                            vulnerable = IsVulnerable(syntaxNode, model.Compilation.GetSemanticModel(referenceLocation.Location.SourceTree), solution);
                        }
                    }
                }
                return(vulnerable);

            case SyntaxKind.VariableDeclarator:
                var variableDeclarator = syntaxNode as VariableDeclaratorSyntax;
                return(IsVulnerable(variableDeclarator.Initializer.Value, model, solution));

            case SyntaxKind.ParenthesizedExpression:
                var parenthesized = syntaxNode as ParenthesizedExpressionSyntax;
                return(IsVulnerable(parenthesized.Expression, model, solution));

            case SyntaxKind.MethodDeclaration:
                var methodDeclaration = syntaxNode as MethodDeclarationSyntax;
                if (methodDeclaration.Body != null)
                {
                    var returnStatements = methodDeclaration.Body.DescendantNodes().OfType <ReturnStatementSyntax>();
                    foreach (var item in returnStatements)
                    {
                        if (!IsVulnerable(item.Expression, model, solution))
                        {
                            vulnerable = false;
                            break;
                        }
                    }
                }
                else if (methodDeclaration.ExpressionBody != null)
                {
                    vulnerable = IsVulnerable(methodDeclaration.ExpressionBody.Expression, model, solution);
                }
                return(vulnerable);

            case SyntaxKind.LocalFunctionStatement:
                var localFunctionStatement = syntaxNode as LocalFunctionStatementSyntax;
                if (localFunctionStatement.Body != null)
                {
                    var returnStatements = localFunctionStatement.Body.DescendantNodes().OfType <ReturnStatementSyntax>();
                    foreach (var item in returnStatements)
                    {
                        if (!IsVulnerable(item.Expression, model, solution))
                        {
                            vulnerable = false;
                            break;
                        }
                    }
                }
                else if (localFunctionStatement.ExpressionBody != null)
                {
                    vulnerable = IsVulnerable(localFunctionStatement.ExpressionBody.Expression, model, solution);
                }
                return(vulnerable);

            case SyntaxKind.ConditionalExpression:
                var conditionalExpression = syntaxNode as ConditionalExpressionSyntax;
                if (!IsVulnerable(conditionalExpression.WhenTrue, model, solution))
                {
                    vulnerable = false;
                }
                else if (!IsVulnerable(conditionalExpression.WhenFalse, model, solution))
                {
                    vulnerable = false;
                }
                return(vulnerable);

            default:
                return(vulnerable);
            }
        }
        public static IPropertySymbol OverrideProperty(
            this SyntaxGenerator codeFactory,
            IPropertySymbol overriddenProperty,
            DeclarationModifiers modifiers,
            INamedTypeSymbol containingType,
            Document document,
            CancellationToken cancellationToken)
        {
            var getAccessibility = overriddenProperty.GetMethod.ComputeResultantAccessibility(containingType);
            var setAccessibility = overriddenProperty.SetMethod.ComputeResultantAccessibility(containingType);

            SyntaxNode getBody = null;
            SyntaxNode setBody = null;

            // Implement an abstract property by throwing not implemented in accessors.
            if (overriddenProperty.IsAbstract)
            {
                getBody = codeFactory.CreateThrowNotImplementStatement(document.Project.GetCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken));
                setBody = getBody;
            }
            else if (overriddenProperty.IsIndexer() && document.Project.Language == LanguageNames.CSharp)
            {
                // Indexer: return or set base[]. Only in C#, since VB must refer to these by name.
                getBody = codeFactory.ReturnStatement(
                    codeFactory.ElementAccessExpression(
                        codeFactory.BaseExpression(),
                        codeFactory.CreateArguments(overriddenProperty.Parameters)));

                setBody = codeFactory.ExpressionStatement(
                    codeFactory.AssignmentStatement(
                        codeFactory.ElementAccessExpression(
                            codeFactory.BaseExpression(),
                            codeFactory.CreateArguments(overriddenProperty.Parameters)),
                        codeFactory.IdentifierName("value")));
            }
            else if (overriddenProperty.GetParameters().Any())
            {
                // Call accessors directly if C# overriding VB
                if (document.Project.Language == LanguageNames.CSharp &&
                    SymbolFinder.FindSourceDefinitionAsync(overriddenProperty, document.Project.Solution, cancellationToken)
                    .WaitAndGetResult(CancellationToken.None).Language == LanguageNames.VisualBasic)
                {
                    var getName = overriddenProperty.GetMethod != null ? overriddenProperty.GetMethod.Name : null;
                    var setName = overriddenProperty.SetMethod != null ? overriddenProperty.SetMethod.Name : null;

                    getBody = getName == null
                        ? null
                        : codeFactory.ReturnStatement(
                        codeFactory.InvocationExpression(
                            codeFactory.MemberAccessExpression(
                                codeFactory.BaseExpression(),
                                codeFactory.IdentifierName(getName)),
                            codeFactory.CreateArguments(overriddenProperty.Parameters)));

                    setBody = setName == null
                        ? null
                        : codeFactory.ExpressionStatement(
                        codeFactory.InvocationExpression(
                            codeFactory.MemberAccessExpression(
                                codeFactory.BaseExpression(),
                                codeFactory.IdentifierName(setName)),
                            codeFactory.CreateArguments(overriddenProperty.SetMethod.GetParameters())));
                }
                else
                {
                    getBody = codeFactory.ReturnStatement(
                        codeFactory.InvocationExpression(
                            codeFactory.MemberAccessExpression(
                                codeFactory.BaseExpression(),
                                codeFactory.IdentifierName(overriddenProperty.Name)), codeFactory.CreateArguments(overriddenProperty.Parameters)));
                    setBody = codeFactory.ExpressionStatement(
                        codeFactory.AssignmentStatement(
                            codeFactory.InvocationExpression(
                                codeFactory.MemberAccessExpression(
                                    codeFactory.BaseExpression(),
                                    codeFactory.IdentifierName(overriddenProperty.Name)), codeFactory.CreateArguments(overriddenProperty.Parameters)),
                            codeFactory.IdentifierName("value")));
                }
            }
            else
            {
                // Regular property: return or set the base property
                getBody = codeFactory.ReturnStatement(
                    codeFactory.MemberAccessExpression(
                        codeFactory.BaseExpression(),
                        codeFactory.IdentifierName(overriddenProperty.Name)));
                setBody = codeFactory.ExpressionStatement(
                    codeFactory.AssignmentStatement(
                        codeFactory.MemberAccessExpression(
                            codeFactory.BaseExpression(),
                            codeFactory.IdentifierName(overriddenProperty.Name)),
                        codeFactory.IdentifierName("value")));
            }

            // Only generate a getter if the base getter is accessible.
            IMethodSymbol accessorGet = null;

            if (overriddenProperty.GetMethod != null && overriddenProperty.GetMethod.IsAccessibleWithin(containingType))
            {
                accessorGet = CodeGenerationSymbolFactory.CreateMethodSymbol(
                    overriddenProperty.GetMethod,
                    accessibility: getAccessibility,
                    statements: new[] { getBody },
                    modifiers: modifiers);
            }

            // Only generate a setter if the base setter is accessible.
            IMethodSymbol accessorSet = null;

            if (overriddenProperty.SetMethod != null &&
                overriddenProperty.SetMethod.IsAccessibleWithin(containingType) &&
                overriddenProperty.SetMethod.DeclaredAccessibility != Accessibility.Private)
            {
                accessorSet = CodeGenerationSymbolFactory.CreateMethodSymbol(
                    overriddenProperty.SetMethod,
                    accessibility: setAccessibility,
                    statements: new[] { setBody },
                    modifiers: modifiers);
            }

            return(CodeGenerationSymbolFactory.CreatePropertySymbol(
                       overriddenProperty,
                       accessibility: overriddenProperty.ComputeResultantAccessibility(containingType),
                       modifiers: modifiers,
                       name: overriddenProperty.Name,
                       isIndexer: overriddenProperty.IsIndexer(),
                       getMethod: accessorGet,
                       setMethod: accessorSet));
        }
Example #8
0
        private static async Task <bool> TryFindLiteralReferencesAsync(
            Document document, int position, IFindUsagesContext context)
        {
            var cancellationToken = context.CancellationToken;

            cancellationToken.ThrowIfCancellationRequested();

            var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>();

            // Currently we only support FAR for numbers, strings and characters.  We don't
            // bother with true/false/null as those are likely to have way too many results
            // to be useful.
            var token = await syntaxTree.GetTouchingTokenAsync(
                position,
                t => syntaxFacts.IsNumericLiteral(t) ||
                syntaxFacts.IsCharacterLiteral(t) ||
                syntaxFacts.IsStringLiteral(t),
                cancellationToken).ConfigureAwait(false);

            if (token.RawKind == 0)
            {
                return(false);
            }

            // Searching for decimals not supported currently.  Our index can only store 64bits
            // for numeric values, and a decimal won't fit within that.
            var tokenValue = token.Value;

            if (tokenValue == null || tokenValue is decimal)
            {
                return(false);
            }

            if (token.Parent is null)
            {
                return(false);
            }

            var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var symbol = semanticModel.GetSymbolInfo(token.Parent).Symbol ?? semanticModel.GetDeclaredSymbol(token.Parent);

            // Numeric labels are available in VB.  In that case we want the normal FAR engine to
            // do the searching.  For these literals we want to find symbolic results and not
            // numeric matches.
            if (symbol is ILabelSymbol)
            {
                return(false);
            }

            // Use the literal to make the title.  Trim literal if it's too long.
            var title = syntaxFacts.ConvertToSingleLine(token.Parent).ToString();

            if (title.Length >= 10)
            {
                title = title.Substring(0, 10) + "...";
            }

            var searchTitle = string.Format(EditorFeaturesResources._0_references, title);
            await context.SetSearchTitleAsync(searchTitle).ConfigureAwait(false);

            var solution = document.Project.Solution;

            // There will only be one 'definition' that all matching literal reference.
            // So just create it now and report to the context what it is.
            var definition = DefinitionItem.CreateNonNavigableItem(
                ImmutableArray.Create(TextTags.StringLiteral),
                ImmutableArray.Create(new TaggedText(TextTags.Text, searchTitle)));

            await context.OnDefinitionFoundAsync(definition).ConfigureAwait(false);

            var progressAdapter = new FindLiteralsProgressAdapter(context, definition);

            // Now call into the underlying FAR engine to find reference.  The FAR
            // engine will push results into the 'progress' instance passed into it.
            // We'll take those results, massage them, and forward them along to the
            // FindUsagesContext instance we were given.
            await SymbolFinder.FindLiteralReferencesAsync(
                tokenValue, Type.GetTypeCode(tokenValue.GetType()), solution, progressAdapter, cancellationToken).ConfigureAwait(false);

            return(true);
        }
Example #9
0
 protected override Task <ImmutableArray <ISymbol> > FindDeclarationsAsync(
     string name, SymbolFilter filter, SearchQuery searchQuery)
 {
     return(SymbolFinder.FindAllDeclarationsWithNormalQueryAsync(_project, searchQuery, filter, CancellationToken));
 }
Example #10
0
        private static async Task <Document> ConvertToAutoPropertyAsync(
            Document document,
            PropertyDeclarationSyntax property,
            CancellationToken cancellationToken)
        {
            SyntaxNode oldRoot = await document.GetSyntaxRootAsync(cancellationToken);

            var parentMember = (MemberDeclarationSyntax)property.Parent;

            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken);

            ISymbol fieldSymbol = GetFieldSymbol(property, semanticModel, cancellationToken);

            var declarator = (VariableDeclaratorSyntax)await fieldSymbol.DeclaringSyntaxReferences[0].GetSyntaxAsync(cancellationToken);

            var variableDeclaration = (VariableDeclarationSyntax)declarator.Parent;

            SyntaxList <MemberDeclarationSyntax> members = parentMember.GetMembers();

            int propertyIndex = members.IndexOf(property);

            int fieldIndex = members.IndexOf((FieldDeclarationSyntax)variableDeclaration.Parent);

            IEnumerable <ReferencedSymbol> referencedSymbols = await SymbolFinder.FindReferencesAsync(
                fieldSymbol,
                document.Project.Solution,
                cancellationToken);

            List <IdentifierNameSyntax> identifierNames = GetIdentifierNames(document, oldRoot, referencedSymbols);

            var rewriter = new IdentifierNameSyntaxRewriter(identifierNames, Identifier(property.Identifier.ValueText));

            var newParentMember = (MemberDeclarationSyntax)rewriter.Visit(parentMember);

            members = newParentMember.GetMembers();

            if (variableDeclaration.Variables.Count == 1)
            {
                newParentMember = newParentMember.RemoveMember(fieldIndex);

                if (propertyIndex > fieldIndex)
                {
                    propertyIndex--;
                }
            }
            else
            {
                var field = (FieldDeclarationSyntax)members[fieldIndex];

                FieldDeclarationSyntax newField = field.RemoveNode(
                    field.Declaration.Variables[variableDeclaration.Variables.IndexOf(declarator)],
                    MemberDeclarationRefactoring.DefaultRemoveOptions);

                members = members.Replace(field, newField.WithAdditionalAnnotations(Formatter.Annotation));

                newParentMember = newParentMember.SetMembers(members);
            }

            members = newParentMember.GetMembers();

            property = (PropertyDeclarationSyntax)members[propertyIndex];

            PropertyDeclarationSyntax newProperty = CreateAutoProperty(property, declarator.Initializer);

            members = members.Replace(property, newProperty);

            newParentMember = newParentMember.SetMembers(members);

            SyntaxNode newRoot = oldRoot.ReplaceNode(parentMember, newParentMember);

            return(document.WithSyntaxRoot(newRoot));
        }
            private async Task <bool> TryInitializeAsync(
                TService service,
                Document document,
                TLocalDeclarationStatementSyntax node,
                CancellationToken cancellationToken
                )
            {
                var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>();

                DeclarationStatement = node;

                var variables = syntaxFacts.GetVariablesOfLocalDeclarationStatement(
                    DeclarationStatement
                    );

                if (variables.Count != 1)
                {
                    return(false);
                }

                VariableDeclarator = (TVariableDeclaratorSyntax)variables[0];
                if (!service.IsValidVariableDeclarator(VariableDeclarator))
                {
                    return(false);
                }

                OutermostBlock = syntaxFacts.GetStatementContainer(DeclarationStatement);
                if (!syntaxFacts.IsExecutableBlock(OutermostBlock))
                {
                    return(false);
                }

                var semanticModel = await document
                                    .GetSemanticModelAsync(cancellationToken)
                                    .ConfigureAwait(false);

                LocalSymbol = (ILocalSymbol)semanticModel.GetDeclaredSymbol(
                    service.GetVariableDeclaratorSymbolNode(VariableDeclarator),
                    cancellationToken
                    );
                if (LocalSymbol == null)
                {
                    // This can happen in broken code, for example: "{ object x; object }"
                    return(false);
                }

                var findReferencesResult = await SymbolFinder
                                           .FindReferencesAsync(LocalSymbol, document.Project.Solution, cancellationToken)
                                           .ConfigureAwait(false);

                var findReferencesList = findReferencesResult.ToList();

                if (findReferencesList.Count != 1)
                {
                    return(false);
                }

                var references = findReferencesList[0].Locations.ToList();

                if (references.Count == 0)
                {
                    return(false);
                }

                var syntaxRoot = await document
                                 .GetSyntaxRootAsync(cancellationToken)
                                 .ConfigureAwait(false);

                var referencingStatements = (
                    from r in references
                    let token = syntaxRoot.FindToken(r.Location.SourceSpan.Start)
                                let statement = token.GetAncestor <TStatementSyntax>()
                                                where statement != null
                                                select statement
                    ).ToSet();

                if (referencingStatements.Count == 0)
                {
                    return(false);
                }

                InnermostBlock = syntaxFacts.FindInnermostCommonExecutableBlock(
                    referencingStatements
                    );
                if (InnermostBlock == null)
                {
                    return(false);
                }

                InnermostBlockStatements = syntaxFacts.GetExecutableBlockStatements(InnermostBlock);
                OutermostBlockStatements = syntaxFacts.GetExecutableBlockStatements(OutermostBlock);

                var allAffectedStatements = new HashSet <TStatementSyntax>(
                    referencingStatements.SelectMany(
                        expr => expr.GetAncestorsOrThis <TStatementSyntax>()
                        )
                    );

                FirstStatementAffectedInInnermostBlock = InnermostBlockStatements
                                                         .Cast <TStatementSyntax>()
                                                         .FirstOrDefault(allAffectedStatements.Contains);

                if (FirstStatementAffectedInInnermostBlock == null)
                {
                    return(false);
                }

                if (FirstStatementAffectedInInnermostBlock == DeclarationStatement)
                {
                    return(false);
                }

                IndexOfDeclarationStatementInInnermostBlock = InnermostBlockStatements.IndexOf(
                    DeclarationStatement
                    );
                IndexOfFirstStatementAffectedInInnermostBlock = InnermostBlockStatements.IndexOf(
                    FirstStatementAffectedInInnermostBlock
                    );
                if (
                    IndexOfDeclarationStatementInInnermostBlock >= 0 &&
                    IndexOfDeclarationStatementInInnermostBlock
                    < IndexOfFirstStatementAffectedInInnermostBlock
                    )
                {
                    // Don't want to move a decl with initializer past other decls in order to move it to the first
                    // affected statement.  If we do we can end up in the following situation:
#if false
                    int x = 0;
                    int y = 0;
                    Console.WriteLine(x + y);
#endif
                    // Each of these declarations will want to 'move' down to the WriteLine
                    // statement and we don't want to keep offering the refactoring.  Note: this
                    // solution is overly aggressive.  Technically if 'y' weren't referenced in
                    // Console.Writeline, then it might be a good idea to move the 'x'.  But this
                    // gives good enough behavior most of the time.

                    // Note that if the variable declaration has no initializer, then we still want to offer
                    // the move as the closest reference will be an assignment to the variable
                    // and we should be able to merge the declaration and assignment into a single
                    // statement.
                    // So, we also check if the variable declaration has an initializer below.

                    if (
                        syntaxFacts.GetInitializerOfVariableDeclarator(VariableDeclarator) != null &&
                        InDeclarationStatementGroup(
                            IndexOfDeclarationStatementInInnermostBlock,
                            IndexOfFirstStatementAffectedInInnermostBlock
                            )
                        )
                    {
                        return(false);
                    }
                }

                var previousToken = FirstStatementAffectedInInnermostBlock
                                    .GetFirstToken()
                                    .GetPreviousToken();
                var affectedSpan = TextSpan.FromBounds(
                    previousToken.SpanStart,
                    FirstStatementAffectedInInnermostBlock.Span.End
                    );
                if (
                    semanticModel.SyntaxTree.OverlapsHiddenPosition(affectedSpan, cancellationToken)
                    )
                {
                    return(false);
                }

                return(true);
            }
Example #12
0
        public async Task <GraphNode> AddNodeForSymbolAsync(ISymbol symbol, Project contextProject, Document contextDocument)
        {
            // Figure out what the location for this node should be. We'll arbitrarily pick the
            // first one, unless we have a contextDocument to restrict it
            var preferredLocation = symbol.Locations.FirstOrDefault(l => l.SourceTree != null);

            if (contextDocument != null)
            {
                var syntaxTree = await contextDocument.GetSyntaxTreeAsync(_cancellationToken).ConfigureAwait(false);

                // If we have one in that tree, use it
                preferredLocation = symbol.Locations.FirstOrDefault(l => l.SourceTree == syntaxTree) ?? preferredLocation;
            }

            // We may need to look up source code within this solution
            if (preferredLocation == null && symbol.Locations.Any(loc => loc.IsInMetadata))
            {
                var newSymbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, contextProject.Solution, _cancellationToken).ConfigureAwait(false);

                if (newSymbol != null)
                {
                    preferredLocation = newSymbol.Locations.Where(loc => loc.IsInSource).FirstOrDefault();
                }
            }

            using (_gate.DisposableWait())
            {
                GraphNode node = await GetOrCreateNodeAsync(_graph, symbol, _solution, _cancellationToken).ConfigureAwait(false);

                node[RoslynGraphProperties.SymbolId]         = (SymbolKey?)symbol.GetSymbolKey();
                node[RoslynGraphProperties.ContextProjectId] = GetContextProjectId(contextProject, symbol);
                node[RoslynGraphProperties.ExplicitInterfaceImplementations] = symbol.ExplicitInterfaceImplementations().Select(s => s.GetSymbolKey()).ToList();
                node[RoslynGraphProperties.DeclaredAccessibility]            = symbol.DeclaredAccessibility;
                node[RoslynGraphProperties.SymbolModifiers] = symbol.GetSymbolModifiers();
                node[RoslynGraphProperties.SymbolKind]      = symbol.Kind;

                if (contextDocument != null)
                {
                    node[RoslynGraphProperties.ContextDocumentId] = contextDocument.Id;
                }

                if (preferredLocation != null)
                {
                    var lineSpan       = preferredLocation.GetLineSpan();
                    var sourceLocation = new SourceLocation(
                        preferredLocation.SourceTree.FilePath,
                        new Position(lineSpan.StartLinePosition.Line, lineSpan.StartLinePosition.Character),
                        new Position(lineSpan.EndLinePosition.Line, lineSpan.EndLinePosition.Character));
                    node[CodeNodeProperties.SourceLocation] = sourceLocation;
                }

                // Keep track of this as a node we have added. Note this is a HashSet, so if the node was already added
                // we won't double-count.
                _createdNodes.Add(node);

                _nodeToSymbolMap[node]          = symbol;
                _nodeToContextProjectMap[node]  = contextProject;
                _nodeToContextDocumentMap[node] = contextDocument;

                return(node);
            }
        }
Example #13
0
        public async Task <RenameResponse> Handle(RenameRequest request)
        {
            var response = new RenameResponse();

            var document = _workspace.GetDocument(request.FileName);

            if (document != null)
            {
                var sourceText = await document.GetTextAsync();

                var position = sourceText.Lines.GetPosition(new LinePosition(request.Line, request.Column));

                var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position);

                Solution solution = _workspace.CurrentSolution;

                if (symbol != null)
                {
                    try
                    {
                        solution = await Renamer.RenameSymbolAsync(solution, symbol, request.RenameTo, _workspace.Options);
                    }
                    catch (ArgumentException e)
                    {
                        response.ErrorMessage = e.Message;
                    }
                }

                var changes         = new Dictionary <string, ModifiedFileResponse>();
                var solutionChanges = solution.GetChanges(_workspace.CurrentSolution);

                foreach (var projectChange in solutionChanges.GetProjectChanges())
                {
                    foreach (var changedDocumentId in projectChange.GetChangedDocuments())
                    {
                        var changedDocument = solution.GetDocument(changedDocumentId);

                        ModifiedFileResponse modifiedFileResponse;
                        if (!changes.TryGetValue(changedDocument.FilePath, out modifiedFileResponse))
                        {
                            modifiedFileResponse = new ModifiedFileResponse(changedDocument.FilePath);
                            changes[changedDocument.FilePath] = modifiedFileResponse;
                        }

                        if (!request.WantsTextChanges)
                        {
                            var changedText = await changedDocument.GetTextAsync();

                            modifiedFileResponse.Buffer = changedText.ToString();
                        }
                        else
                        {
                            var originalDocument = _workspace.CurrentSolution.GetDocument(changedDocumentId);
                            var textChanges      = await changedDocument.GetTextChangesAsync(originalDocument);

                            var linePositionSpanTextChanges = await LinePositionSpanTextChange.Convert(originalDocument, textChanges);

                            modifiedFileResponse.Changes = modifiedFileResponse.Changes != null
                                ? modifiedFileResponse.Changes.Union(linePositionSpanTextChanges)
                                : linePositionSpanTextChanges;
                        }
                    }
                }

                if (request.ApplyTextChanges)
                {
                    // Attempt to update the workspace
                    if (_workspace.TryApplyChanges(solution))
                    {
                        response.Changes = changes.Values;
                    }
                }
                else
                {
                    response.Changes = changes.Values;
                }
            }

            return(response);
        }
Example #14
0
 public Task <ImmutableArray <ISymbol> > DetermineCascadedSymbolsAsync(
     ISymbol symbol, Solution solution, IImmutableSet <Project> projects,
     FindReferencesSearchOptions options, CancellationToken cancellationToken)
 {
     return(SymbolFinder.FindLinkedSymbolsAsync(symbol, solution, cancellationToken));
 }
Example #15
0
        internal async Task <ChangeSignatureAnalyzedContext> GetContextAsync(
            Document document, int position, bool restrictToDeclarations, CancellationToken cancellationToken)
        {
            var(symbol, selectedIndex) = await GetInvocationSymbolAsync(
                document, position, restrictToDeclarations, cancellationToken).ConfigureAwait(false);

            // Cross-language symbols will show as metadata, so map it to source if possible.
            symbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, document.Project.Solution, cancellationToken).ConfigureAwait(false) ?? symbol;

            if (symbol == null)
            {
                return(new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.IncorrectKind));
            }

            if (symbol is IMethodSymbol method)
            {
                var containingType = method.ContainingType;

                if (method.Name == WellKnownMemberNames.DelegateBeginInvokeName &&
                    containingType != null &&
                    containingType.IsDelegateType() &&
                    containingType.DelegateInvokeMethod != null)
                {
                    symbol = containingType.DelegateInvokeMethod;
                }
            }

            if (symbol is IEventSymbol ev)
            {
                symbol = ev.Type;
            }

            if (symbol is INamedTypeSymbol typeSymbol)
            {
                if (typeSymbol.IsDelegateType() && typeSymbol.DelegateInvokeMethod != null)
                {
                    symbol = typeSymbol.DelegateInvokeMethod;
                }
            }

            if (!symbol.MatchesKind(SymbolKind.Method, SymbolKind.Property))
            {
                return(new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.IncorrectKind));
            }

            if (symbol.Locations.Any(loc => loc.IsInMetadata))
            {
                return(new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.DefinedInMetadata));
            }

            // This should be called after the metadata check above to avoid looking for nodes in metadata.
            var declarationLocation = symbol.Locations.FirstOrDefault();

            if (declarationLocation == null)
            {
                return(new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.DefinedInMetadata));
            }

            var solution            = document.Project.Solution;
            var declarationDocument = solution.GetRequiredDocument(declarationLocation.SourceTree !);
            var declarationChangeSignatureService = declarationDocument.GetRequiredLanguageService <AbstractChangeSignatureService>();

            int insertPosition;
            var reference = symbol.DeclaringSyntaxReferences.FirstOrDefault();

            if (reference != null)
            {
                insertPosition = declarationChangeSignatureService.GetPositionBeforeParameterListClosingBrace(reference.GetSyntax());
            }
            else
            {
                // There may be no declaring syntax reference, for example delegate Invoke methods. Use an
                // insertPosition of 0 and continue on.
                insertPosition = 0;
            }

            var parameterConfiguration = ParameterConfiguration.Create(
                symbol.GetParameters().Select(p => new ExistingParameter(p)).ToImmutableArray <Parameter>(),
                symbol.IsExtensionMethod(), selectedIndex);

            return(new ChangeSignatureAnalysisSucceededContext(
                       declarationDocument, insertPosition, symbol, parameterConfiguration));
        }
        internal static IInlineRenameInfo GetRenameInfo(
            IEnumerable <IRefactorNotifyService> refactorNotifyServices,
            Document document, SyntaxToken triggerToken, CancellationToken cancellationToken)
        {
            var syntaxFactsService = document.GetLanguageService <ISyntaxFactsService>();

            if (syntaxFactsService.IsReservedOrContextualKeyword(triggerToken))
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_must_rename_an_identifier));
            }

            var semanticModel = document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var semanticFacts = document.GetLanguageService <ISemanticFactsService>();

            var tokenRenameInfo = RenameUtilities.GetTokenRenameInfo(semanticFacts, semanticModel, triggerToken, cancellationToken);

            // Rename was invoked on a member group reference in a nameof expression.
            // Trigger the rename on any of the candidate symbols but force the
            // RenameOverloads option to be on.
            var triggerSymbol = tokenRenameInfo.HasSymbols ? tokenRenameInfo.Symbols.First() : null;

            if (triggerSymbol == null)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
            }

            // see https://github.com/dotnet/roslyn/issues/10898
            // we are disabling rename for tuple fields for now
            // 1) compiler does not return correct location information in these symbols
            // 2) renaming tuple fields seems a complex enough thing to require some design
            if (triggerSymbol.ContainingType?.IsTupleType == true)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
            }

            // If rename is invoked on a member group reference in a nameof expression, then the
            // RenameOverloads option should be forced on.
            var forceRenameOverloads = tokenRenameInfo.IsMemberGroup;

            if (syntaxFactsService.IsTypeNamedVarInVariableOrFieldDeclaration(triggerToken, triggerToken.Parent))
            {
                // To check if var in this context is a real type, or the keyword, we need to
                // speculatively bind the identifier "var". If it returns a symbol, it's a real type,
                // if not, it's the keyword.
                // see bugs 659683 (compiler API) and 659705 (rename/workspace api) for examples
                var symbolForVar = semanticModel.GetSpeculativeSymbolInfo(
                    triggerToken.SpanStart,
                    triggerToken.Parent,
                    SpeculativeBindingOption.BindAsTypeOrNamespace).Symbol;

                if (symbolForVar == null)
                {
                    return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
                }
            }

            var symbolAndProjectId = RenameLocations.ReferenceProcessing.GetRenamableSymbolAsync(document, triggerToken.SpanStart, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken);
            var symbol             = symbolAndProjectId.Symbol;

            if (symbol == null)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
            }

            if (symbol.Kind == SymbolKind.Alias && symbol.IsExtern)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
            }

            // Cannot rename constructors in VB.  TODO: this logic should be in the VB subclass of this type.
            var workspace = document.Project.Solution.Workspace;

            if (symbol != null &&
                symbol.Kind == SymbolKind.NamedType &&
                symbol.Language == LanguageNames.VisualBasic &&
                triggerToken.ToString().Equals("New", StringComparison.OrdinalIgnoreCase))
            {
                var originalSymbol = SymbolFinder.FindSymbolAtPositionAsync(semanticModel, triggerToken.SpanStart, workspace, cancellationToken: cancellationToken)
                                     .WaitAndGetResult(cancellationToken);

                if (originalSymbol != null && originalSymbol.IsConstructor())
                {
                    return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
                }
            }

            if (syntaxFactsService.IsTypeNamedDynamic(triggerToken, triggerToken.Parent))
            {
                if (symbol.Kind == SymbolKind.DynamicType)
                {
                    return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
                }
            }

            // we allow implicit locals and parameters of Event handlers
            if (symbol.IsImplicitlyDeclared &&
                symbol.Kind != SymbolKind.Local &&
                !(symbol.Kind == SymbolKind.Parameter &&
                  symbol.ContainingSymbol.Kind == SymbolKind.Method &&
                  symbol.ContainingType != null &&
                  symbol.ContainingType.IsDelegateType() &&
                  symbol.ContainingType.AssociatedSymbol != null))
            {
                // We enable the parameter in RaiseEvent, if the Event is declared with a signature. If the Event is declared as a
                // delegate type, we do not have a connection between the delegate type and the event.
                // this prevents a rename in this case :(.
                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
            }

            if (symbol.Kind == SymbolKind.Property && symbol.ContainingType.IsAnonymousType)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.Renaming_anonymous_type_members_is_not_yet_supported));
            }

            if (symbol.IsErrorType())
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.Please_resolve_errors_in_your_code_before_renaming_this_element));
            }

            if (symbol.Kind == SymbolKind.Method && ((IMethodSymbol)symbol).MethodKind == MethodKind.UserDefinedOperator)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_operators));
            }

            var symbolLocations = symbol.Locations;

            // Does our symbol exist in an unchangeable location?
            var navigationService = workspace.Services.GetService <IDocumentNavigationService>();

            foreach (var location in symbolLocations)
            {
                if (location.IsInMetadata)
                {
                    return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_elements_that_are_defined_in_metadata));
                }
                else if (location.IsInSource)
                {
                    if (document.Project.IsSubmission)
                    {
                        var solution            = document.Project.Solution;
                        var projectIdOfLocation = solution.GetDocument(location.SourceTree).Project.Id;

                        if (solution.Projects.Any(p => p.IsSubmission && p.ProjectReferences.Any(r => r.ProjectId == projectIdOfLocation)))
                        {
                            return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_elements_from_previous_submissions));
                        }
                    }
                    else
                    {
                        var sourceText   = location.SourceTree.GetTextAsync(cancellationToken).WaitAndGetResult(cancellationToken);
                        var textSnapshot = sourceText.FindCorrespondingEditorTextSnapshot();

                        if (textSnapshot != null)
                        {
                            var buffer       = textSnapshot.TextBuffer;
                            var originalSpan = location.SourceSpan.ToSnapshotSpan(textSnapshot).TranslateTo(buffer.CurrentSnapshot, SpanTrackingMode.EdgeInclusive);

                            if (buffer.IsReadOnly(originalSpan) || !navigationService.CanNavigateToSpan(workspace, document.Id, location.SourceSpan))
                            {
                                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
                            }
                        }
                    }
                }
                else
                {
                    return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
                }
            }

            return(new SymbolInlineRenameInfo(
                       refactorNotifyServices, document, triggerToken.Span,
                       symbolAndProjectId, forceRenameOverloads, cancellationToken));
        }
Example #17
0
        public override Task <IEnumerable <SearchResult> > FindReferences(string documentationCommentId, MonoDevelop.Projects.Project hintProject, CancellationToken token)
        {
            return(Task.Run(async delegate {
                var result = new List <SearchResult> ();
                var antiDuplicatesSet = new HashSet <SearchResult> (new SearchResultComparer());
                foreach (var workspace in TypeSystemService.AllWorkspaces.OfType <MonoDevelopWorkspace> ())
                {
                    LookupResult lookup = null;

                    foreach (var project in workspace.CurrentSolution.Projects)
                    {
                        lookup = await TryLookupSymbolInProject(project, documentationCommentId, token);
                        if (lookup.Success)
                        {
                            break;
                        }
                    }

                    if (lookup == null || !lookup.Success)
                    {
                        continue;
                    }

                    foreach (var loc in lookup.Symbol.Locations)
                    {
                        if (token.IsCancellationRequested)
                        {
                            break;
                        }

                        if (!loc.IsInSource)
                        {
                            continue;
                        }
                        var fileName = loc.SourceTree.FilePath;
                        var offset = loc.SourceSpan.Start;
                        string projectedName;
                        int projectedOffset;
                        if (workspace.TryGetOriginalFileFromProjection(fileName, offset, out projectedName, out projectedOffset))
                        {
                            fileName = projectedName;
                            offset = projectedOffset;
                        }
                        var sr = new MemberReference(lookup.Symbol, fileName, offset, loc.SourceSpan.Length);
                        sr.ReferenceUsageType = ReferenceUsageType.Declariton;
                        antiDuplicatesSet.Add(sr);
                        result.Add(sr);
                    }

                    foreach (var mref in await SymbolFinder.FindReferencesAsync(lookup.Symbol, lookup.Solution).ConfigureAwait(false))
                    {
                        foreach (var loc in mref.Locations)
                        {
                            if (token.IsCancellationRequested)
                            {
                                break;
                            }
                            var fileName = loc.Document.FilePath;
                            var offset = loc.Location.SourceSpan.Start;
                            string projectedName;
                            int projectedOffset;
                            if (workspace.TryGetOriginalFileFromProjection(fileName, offset, out projectedName, out projectedOffset))
                            {
                                fileName = projectedName;
                                offset = projectedOffset;
                            }
                            var sr = new MemberReference(lookup.Symbol, fileName, offset, loc.Location.SourceSpan.Length);


                            if (antiDuplicatesSet.Add(sr))
                            {
                                var root = loc.Location.SourceTree.GetRoot();
                                var node = root.FindNode(loc.Location.SourceSpan);
                                var trivia = root.FindTrivia(loc.Location.SourceSpan.Start);
                                sr.ReferenceUsageType = HighlightUsagesExtension.GetUsage(node);
                                result.Add(sr);
                            }
                        }
                    }
                }
                return (IEnumerable <SearchResult>)result;
            }));
        }
        private async Task StreamingFindReferencesAsync(
            Document document, int caretPosition, IStreamingFindUsagesPresenter presenter, CancellationToken cancellationToken)
        {
            try
            {
                // first, let's see if we even have a comment, otherwise there's no use in starting a search
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                var relevantSymbol = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(document, caretPosition, new CancellationToken());

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
                var symbol = relevantSymbol?.symbol;
                if (symbol == null)
                {
                    return; // would be useful if we could notify the user why we didn't do anything
                }
                // maybe using something like an info bar?

                var findUsagesService = document.GetLanguageService <IFindUsagesService>();

                using var token = _asyncListener.BeginAsyncOperation(nameof(StreamingFindReferencesAsync));

                var context = presenter.StartSearch(EditorFeaturesResources.Find_References, supportsReferences: true, cancellationToken);

                using (Logger.LogBlock(
                           FunctionId.CommandHandler_FindAllReference,
                           KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "streaming"),
                           context.CancellationToken))
                {
                    var symbolsToLookup = new List <ISymbol>();

                    foreach (var curSymbol in symbol.ContainingType.GetMembers()
                             .Where(m => m.Kind == symbol.Kind && m.Name == symbol.Name))
                    {
                        Compilation compilation;
                        if (!document.Project.TryGetCompilation(out compilation))
                        {
                            // TODO: should we do anything more here?
                            continue;
                        }

                        foreach (var sym in SymbolFinder.FindSimilarSymbols(curSymbol, compilation, context.CancellationToken))
                        {
                            // assumption here is, that FindSimilarSymbols returns symbols inside same project
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                            var symbolsToAdd = await GatherSymbolsAsync(sym, document.Project.Solution, context.CancellationToken);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
                            symbolsToLookup.AddRange(symbolsToAdd);
                        }
                    }

                    foreach (var candidate in symbolsToLookup)
                    {
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                        await AbstractFindUsagesService.FindSymbolReferencesAsync(context, candidate, document.Project);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
                    }

                    // Note: we don't need to put this in a finally.  The only time we might not hit
                    // this is if cancellation or another error gets thrown.  In the former case,
                    // that means that a new search has started.  We don't care about telling the
                    // context it has completed.  In the latter case something wrong has happened
                    // and we don't want to run any more code in this particular context.
                    await context.OnCompletedAsync().ConfigureAwait(false);
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception e) when(FatalError.ReportAndCatch(e))
            {
            }
        }
        private async Task ScanAllMethodReferenceLocations(IMethodSymbol methodSymbol, int depth, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (cancellationToken.IsCancellationRequested)
            {
                cancellationToken.ThrowIfCancellationRequested();
            }
            methodSymbol = methodSymbol.OriginalDefinition;
            if ((!_configuration.CanSearchForMethodReferences(methodSymbol) && !_mustScanForMethodReferences.Contains(methodSymbol)) ||
                !_searchedMethodReferences.TryAdd(methodSymbol))
            {
                return;
            }
            // FindReferencesAsync will not search just for the passed method symbol but also for all its overrides, interfaces and external interfaces
            // so we need to add all related symbols to the searched list in order to avoid scanning those related members in the future calls
            // If any of the related symbols was already searched then we know that all references of the current method were already found
            var alreadyScanned = false;

            foreach (var relatedMethod in GetAllRelatedMethods(methodSymbol))
            {
                if (!_searchedMethodReferences.TryAdd(relatedMethod))
                {
                    alreadyScanned = true;
                }
            }
            if (alreadyScanned)
            {
                return;
            }

            var references = await SymbolFinder.FindReferencesAsync(methodSymbol, _solution, _analyzeDocuments, cancellationToken).ConfigureAwait(false);

            depth++;
            if (depth > _maxScanningDepth)
            {
                _maxScanningDepth = depth;
            }
            foreach (var refLocation in references.SelectMany(o => o.Locations))
            {
                if (_scannedLocationsSymbols.Contains(refLocation))
                {
                    continue;
                }
                _scannedLocationsSymbols.TryAdd(refLocation);

                if (refLocation.Document.Project != ProjectData.Project)
                {
                    throw new InvalidOperationException($"Reference {refLocation} is located in a document from another project");
                }

                var documentData = ProjectData.GetDocumentData(refLocation.Document);
                if (documentData == null)
                {
                    continue;
                }
                var symbol = documentData.GetEnclosingSymbol(refLocation);
                if (symbol == null)
                {
                    documentData.AddDiagnostic($"Symbol not found for reference ${refLocation}", DiagnosticSeverity.Hidden);
                    continue;
                }

                if (symbol.Kind != SymbolKind.Method)
                {
                    TryLinkToRealReference(symbol, documentData, refLocation);
                    continue;
                }

                var baseMethodData = documentData.GetFunctionData(symbol);
                if (baseMethodData == null)                 // TODO: Current is null for lambda in fields
                {
                    var refMethodSymbol = (IMethodSymbol)symbol;
                    if (refMethodSymbol.MethodKind == MethodKind.AnonymousFunction || refMethodSymbol.MethodKind == MethodKind.LambdaMethod)
                    {
                        documentData.AddDiagnostic(
                            $"Function inside member {refMethodSymbol.ContainingSymbol} cannot be async because of its kind {refMethodSymbol.MethodKind}",
                            DiagnosticSeverity.Hidden);
                    }
                    else
                    {
                        documentData.AddDiagnostic(
                            $"Method {refMethodSymbol} cannot be async because of its kind {refMethodSymbol.MethodKind}",
                            DiagnosticSeverity.Hidden);
                    }
                    continue;
                }

                // Find the real method on that reference as FindReferencesAsync will also find references to base and interface methods
                // Save the reference as it can be made async
                var nameNode = baseMethodData.GetNode().GetSimpleName(refLocation.Location.SourceSpan);
                if (nameNode == null)
                {
                    continue;                     // Can happen for a foreach token
                }
                var referenceSymbolInfo   = documentData.SemanticModel.GetSymbolInfo(nameNode);
                var referenceSymbol       = referenceSymbolInfo.Symbol;
                var methodReferenceSymbol = referenceSymbol as IMethodSymbol;
                if (methodReferenceSymbol == null && referenceSymbol is IPropertySymbol propertyReferenceSymbol)
                {
                    // We need to find the usage of the property, if getter or setter is used
                    methodReferenceSymbol = nameNode.IsAssigned()
                                                ? propertyReferenceSymbol.SetMethod
                                                : propertyReferenceSymbol.GetMethod;
                }
                if (methodReferenceSymbol == null)
                {
                    // Check if the node is inside a nameof keyword as GetSymbolInfo will never return a symbol for it only candidates
                    if (nameNode.IsInsideNameOf())
                    {
                        var referencedFuncs = new Dictionary <IMethodSymbol, FunctionData>();
                        foreach (var candidateSymbol in referenceSymbolInfo.CandidateSymbols.OfType <IMethodSymbol>())
                        {
                            var nameofReferenceData = ProjectData.GetFunctionData(candidateSymbol);
                            referencedFuncs.Add(candidateSymbol, nameofReferenceData);
                        }
                        var nameofReference = new NameofFunctionDataReference(baseMethodData, refLocation, nameNode, referencedFuncs, true);
                        if (!baseMethodData.References.TryAdd(nameofReference))
                        {
                            _logger.Debug($"Performance hit: MembersReferences {nameNode} already added");
                        }
                        foreach (var referencedFun in referencedFuncs.Values.Where(o => o != null))
                        {
                            referencedFun.SelfReferences.TryAdd(nameofReference);
                        }
                        continue;
                    }

                    methodReferenceSymbol = TryFindCandidate(nameNode, referenceSymbolInfo, documentData.SemanticModel);
                    if (methodReferenceSymbol == null)
                    {
                        baseMethodData.AddDiagnostic($"Unable to find symbol for node {nameNode} ({nameNode.GetLinePosition().Format()})",
                                                     DiagnosticSeverity.Info);
                        continue;
                    }
                    baseMethodData.AddDiagnostic(
                        $"GetSymbolInfo did not successfully resolved symbol for node {nameNode} ({nameNode.GetLinePosition().Format()})" +
                        $"but we got a candidate instead. CandidateReason: {referenceSymbolInfo.CandidateReason}",
                        DiagnosticSeverity.Info);
                }
                var referenceFunctionData = ProjectData.GetFunctionData(methodReferenceSymbol);
                // Check if the reference is a cref reference or a nameof
                if (nameNode.IsInsideCref())
                {
                    var crefReference = new CrefFunctionDataReference(baseMethodData, refLocation, nameNode, methodReferenceSymbol, referenceFunctionData, true);
                    if (!baseMethodData.References.TryAdd(crefReference))
                    {
                        _logger.Debug($"Performance hit: MembersReferences {nameNode} already added");
                    }
                    referenceFunctionData?.SelfReferences.TryAdd(crefReference);
                    continue;                     // No need to further scan a cref reference
                }
                var methodReferenceData = new BodyFunctionDataReference(baseMethodData, refLocation, nameNode, methodReferenceSymbol, referenceFunctionData);
                if (!baseMethodData.References.TryAdd(methodReferenceData))
                {
                    _logger.Debug($"Performance hit: method reference {methodReferenceSymbol} already processed");
                    continue;                     // Reference already processed
                }
                referenceFunctionData?.SelfReferences.TryAdd(methodReferenceData);

                if (baseMethodData.Conversion == MethodConversion.Ignore)
                {
                    continue;
                }
                // Do not scan for method that will be only copied (e.g. the containing type is a new type).
                if (baseMethodData.Conversion == MethodConversion.Copy)
                {
                    continue;
                }

                if (baseMethodData is MethodOrAccessorData methodData && !_scannedMethodOrAccessors.Contains(methodData))
                {
                    await ScanMethodData(methodData, depth, cancellationToken).ConfigureAwait(false);
                }
                // Scan a local/anonymous function only if there is a chance that can be called elsewere. (e.g. saved to a variable or local function)
                // TODO: support local variables
                if (baseMethodData is LocalFunctionData)
                {
                    await ScanAllMethodReferenceLocations(baseMethodData.Symbol, depth, cancellationToken).ConfigureAwait(false);
                }
            }
        }
Example #20
0
        public void PinvokeMethodReferences_CS()
        {
            var tree = Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(
                @"

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Runtime.InteropServices;
static class Module1
{
	[DllImport(""kernel32"", EntryPoint = ""CreateDirectoryA"", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
    public static extern int CreateDirectory(string lpPathName);

        private static int prop;
        public static int Prop1
        {
            get { return prop; }
            set
            {
                CreateDirectory(""T"");
                // Method Call 1
                prop = value;
                prop = null;
            }
        }

        public static void Main()
        {
            CreateDirectory(""T""); // Method Call 2            
            NormalMethod(); // Method Call 1
            NormalMethod(); // Method Call 2
        }

        public static void NormalMethod()
        {
        }
    }
                ");

            ProjectId  prj1Id = ProjectId.CreateNewId();
            DocumentId docId  = DocumentId.CreateNewId(prj1Id);

            var sln = new CustomWorkspace().CurrentSolution
                      .AddProject(prj1Id, "testDeclareReferences", "testAssembly", LanguageNames.CSharp)
                      .AddMetadataReference(prj1Id, MscorlibRef)
                      .AddDocument(docId, "testFile", tree.GetText());

            Microsoft.CodeAnalysis.Project prj = sln.GetProject(prj1Id).WithCompilationOptions(new CSharp.CSharpCompilationOptions(OutputKind.ConsoleApplication));
            tree = (SyntaxTree)prj.GetDocument(docId).GetSyntaxTreeAsync().Result;
            Compilation comp = prj.GetCompilationAsync().Result;

            SemanticModel semanticModel = comp.GetSemanticModel(tree);

            List <Microsoft.CodeAnalysis.CSharp.Syntax.MethodDeclarationSyntax> methodlist = tree.GetRoot().DescendantNodes().OfType <Microsoft.CodeAnalysis.CSharp.Syntax.MethodDeclarationSyntax>().ToList();
            SyntaxNode declareMethod = methodlist.ElementAt(0);
            SyntaxNode normalMethod  = methodlist.ElementAt(2);

            // pinvoke method calls
            var symbol     = semanticModel.GetDeclaredSymbol(declareMethod);
            var references = SymbolFinder.FindReferencesAsync(symbol, prj.Solution).Result;

            Assert.Equal(2, references.ElementAt(0).Locations.Count());

            // normal method calls
            symbol     = semanticModel.GetDeclaredSymbol(normalMethod);
            references = SymbolFinder.FindReferencesAsync(symbol, prj.Solution).Result;
            Assert.Equal(2, references.ElementAt(0).Locations.Count());
        }
        private async Task <Document> InlineTemporaryAsync(Document document, VariableDeclaratorSyntax declarator, CancellationToken cancellationToken)
        {
            var workspace = document.Project.Solution.Workspace;

            // Annotate the variable declarator so that we can get back to it later.
            var updatedDocument = await document.ReplaceNodeAsync(declarator, declarator.WithAdditionalAnnotations(DefinitionAnnotation), cancellationToken).ConfigureAwait(false);

            var semanticModel = await updatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var variableDeclarator = await FindDeclaratorAsync(updatedDocument, cancellationToken).ConfigureAwait(false);

            // Create the expression that we're actually going to inline.
            var expressionToInline = await CreateExpressionToInlineAsync(variableDeclarator, updatedDocument, cancellationToken).ConfigureAwait(false);

            // Collect the identifier names for each reference.
            var local      = (ILocalSymbol)semanticModel.GetDeclaredSymbol(variableDeclarator, cancellationToken);
            var symbolRefs = await SymbolFinder.FindReferencesAsync(local, updatedDocument.Project.Solution, cancellationToken).ConfigureAwait(false);

            var references = symbolRefs.Single(r => r.Definition == local).Locations;
            var syntaxRoot = await updatedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            // Collect the topmost parenting expression for each reference.
            var nonConflictingIdentifierNodes = references
                                                .Select(loc => (IdentifierNameSyntax)syntaxRoot.FindToken(loc.Location.SourceSpan.Start).Parent)
                                                .Where(ident => !HasConflict(ident, variableDeclarator));

            // Add referenceAnnotations to identifier nodes being replaced.
            updatedDocument = await updatedDocument.ReplaceNodesAsync(
                nonConflictingIdentifierNodes,
                (o, n) => n.WithAdditionalAnnotations(ReferenceAnnotation),
                cancellationToken).ConfigureAwait(false);

            semanticModel = await updatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            variableDeclarator = await FindDeclaratorAsync(updatedDocument, cancellationToken).ConfigureAwait(false);

            // Get the annotated reference nodes.
            nonConflictingIdentifierNodes = await FindReferenceAnnotatedNodesAsync(updatedDocument, cancellationToken).ConfigureAwait(false);

            var topmostParentingExpressions = nonConflictingIdentifierNodes
                                              .Select(ident => GetTopMostParentingExpression(ident))
                                              .Distinct();

            var originalInitializerSymbolInfo = semanticModel.GetSymbolInfo(variableDeclarator.Initializer.Value, cancellationToken);

            // Make each topmost parenting statement or Equals Clause Expressions semantically explicit.
            updatedDocument = await updatedDocument.ReplaceNodesAsync(topmostParentingExpressions, (o, n) => Simplifier.Expand(n, semanticModel, workspace, cancellationToken: cancellationToken), cancellationToken).ConfigureAwait(false);

            semanticModel = await updatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var semanticModelBeforeInline = semanticModel;

            variableDeclarator = await FindDeclaratorAsync(updatedDocument, cancellationToken).ConfigureAwait(false);

            var scope = GetScope(variableDeclarator);

            var newScope = ReferenceRewriter.Visit(semanticModel, scope, variableDeclarator, expressionToInline, cancellationToken);

            updatedDocument = await updatedDocument.ReplaceNodeAsync(scope, newScope, cancellationToken).ConfigureAwait(false);

            semanticModel = await updatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            variableDeclarator = await FindDeclaratorAsync(updatedDocument, cancellationToken).ConfigureAwait(false);

            newScope = GetScope(variableDeclarator);
            var conflicts           = newScope.GetAnnotatedNodesAndTokens(ConflictAnnotation.Kind);
            var declaratorConflicts = variableDeclarator.GetAnnotatedNodesAndTokens(ConflictAnnotation.Kind);

            // Note that we only remove the local declaration if there weren't any conflicts,
            // unless those conflicts are inside the local declaration.
            if (conflicts.Count() == declaratorConflicts.Count())
            {
                // Certain semantic conflicts can be detected only after the reference rewriter has inlined the expression
                var newDocument = await DetectSemanticConflicts(updatedDocument,
                                                                semanticModel,
                                                                semanticModelBeforeInline,
                                                                originalInitializerSymbolInfo,
                                                                cancellationToken).ConfigureAwait(false);

                if (updatedDocument == newDocument)
                {
                    // No semantic conflicts, we can remove the definition.
                    updatedDocument = await updatedDocument.ReplaceNodeAsync(newScope, RemoveDeclaratorFromScope(variableDeclarator, newScope), cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    // There were some semantic conflicts, don't remove the definition.
                    updatedDocument = newDocument;
                }
            }

            return(updatedDocument);
        }
Example #22
0
        public void FindReferences_InterfaceMapping()
        {
            var text     = @"
abstract class C
{
    public abstract void Boo(); // Line 3
}
interface A
{
    void Boo(); // Line 7
}
 
class B : C, A
{
   void A.Boo() { } // Line 12
   public override void Boo() { } // Line 13
   public void Bar() { Boo(); } // Line 14
}
";
            var solution = GetSingleDocumentSolution(text);
            var project  = solution.Projects.First();
            var comp     = project.GetCompilationAsync().Result;

            // Find references on definition B.Boo()
            var typeB  = comp.GetTypeByMetadataName("B");
            var boo    = typeB.GetMembers("Boo").First();
            var result = SymbolFinder.FindReferencesAsync(boo, solution).Result.ToList();

            Assert.Equal(2, result.Count); // 2 symbols found

            HashSet <int> expectedMatchedLines = new HashSet <int> {
                3, 13, 14
            };

            result.ForEach((reference) => Verify(reference, expectedMatchedLines));

            Assert.Empty(expectedMatchedLines);

            // Find references on definition C.Boo()
            var typeC = comp.GetTypeByMetadataName("C");

            boo    = typeC.GetMembers("Boo").First();
            result = SymbolFinder.FindReferencesAsync(boo, solution).Result.ToList();
            Assert.Equal(2, result.Count); // 2 symbols found

            expectedMatchedLines = new HashSet <int> {
                3, 13, 14
            };
            result.ForEach((reference) => Verify(reference, expectedMatchedLines));

            Assert.Empty(expectedMatchedLines);

            // Find references on definition A.Boo()
            var typeA = comp.GetTypeByMetadataName("A");

            boo    = typeA.GetMembers("Boo").First();
            result = SymbolFinder.FindReferencesAsync(boo, solution).Result.ToList();
            Assert.Equal(2, result.Count); // 2 symbols found

            expectedMatchedLines = new HashSet <int> {
                7, 12
            };
            result.ForEach((reference) => Verify(reference, expectedMatchedLines));

            Assert.Empty(expectedMatchedLines);
        }
Example #23
0
        protected override async Task FixAllAsync(Document document, ImmutableArray <Diagnostic> diagnostics, SyntaxEditor syntaxEditor, CancellationToken cancellationToken)
        {
            var nodesToRemove = new HashSet <SyntaxNode>();

            // Create actions and keep their SpanStart.
            // Execute actions ordered descending by SpanStart to avoid conflicts.
            var actionsToPerform = new List <(int, Action)>();
            var root             = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var documentEditor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);

            var documentsToBeSearched = ImmutableHashSet.Create(document);

            foreach (var diagnostic in diagnostics)
            {
                var token = diagnostic.Location.FindToken(cancellationToken);
                var node  = root.FindNode(diagnostic.Location.SourceSpan);
                if (IsCatchDeclarationIdentifier(token))
                {
                    (int, Action)pair = (token.Parent.SpanStart,
                                         () => syntaxEditor.ReplaceNode(
                                             token.Parent,
                                             token.Parent.ReplaceToken(token, default(SyntaxToken)).WithAdditionalAnnotations(Formatter.Annotation)));
                    actionsToPerform.Add(pair);
                }
                else
                {
                    nodesToRemove.Add(node);
                }

                var symbol            = documentEditor.SemanticModel.GetDeclaredSymbol(node);
                var referencedSymbols = await SymbolFinder.FindReferencesAsync(symbol, document.Project.Solution, documentsToBeSearched, cancellationToken).ConfigureAwait(false);

                foreach (var referencedSymbol in referencedSymbols)
                {
                    if (referencedSymbol?.Locations != null)
                    {
                        foreach (var location in referencedSymbol.Locations)
                        {
                            var referencedSymbolNode = root.FindNode(location.Location.SourceSpan);
                            if (referencedSymbolNode != null)
                            {
                                var nodeToRemoveOrReplace = GetNodeToRemoveOrReplace(referencedSymbolNode);
                                if (nodeToRemoveOrReplace != null)
                                {
                                    nodesToRemove.Add(nodeToRemoveOrReplace);
                                }
                            }
                        }
                    }
                }
            }

            MergeNodesToRemove(nodesToRemove);
            var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>();

            foreach (var node in nodesToRemove)
            {
                actionsToPerform.Add((node.SpanStart, () => RemoveOrReplaceNode(syntaxEditor, node, syntaxFacts)));
            }

            // Process nodes in reverse order
            // to complete with nested declarations before processing the outer ones.
            foreach (var node in actionsToPerform.OrderByDescending(n => n.Item1))
            {
                node.Item2();
            }
        }
Example #24
0
        public static void FindRefs(ISymbol symbol)
        {
            var monitor   = IdeApp.Workbench.ProgressMonitors.GetSearchProgressMonitor(true, true);
            var workspace = TypeSystemService.Workspace as MonoDevelopWorkspace;

            if (workspace == null)
            {
                return;
            }
            var solution = workspace.CurrentSolution;

            Task.Run(async delegate {
                try {
                    var antiDuplicatesSet = new HashSet <SearchResult> (new SearchResultComparer());
                    foreach (var loc in symbol.Locations)
                    {
                        if (!loc.IsInSource)
                        {
                            continue;
                        }
                        var fileName = loc.SourceTree.FilePath;
                        var offset   = loc.SourceSpan.Start;
                        string projectedName;
                        int projectedOffset;
                        if (workspace.TryGetOriginalFileFromProjection(fileName, offset, out projectedName, out projectedOffset))
                        {
                            fileName = projectedName;
                            offset   = projectedOffset;
                        }
                        var sr = new SearchResult(new FileProvider(fileName), offset, loc.SourceSpan.Length);
                        antiDuplicatesSet.Add(sr);
                        monitor.ReportResult(sr);
                    }

                    foreach (var mref in await SymbolFinder.FindReferencesAsync(symbol, solution).ConfigureAwait(false))
                    {
                        foreach (var loc in mref.Locations)
                        {
                            var fileName = loc.Document.FilePath;
                            var offset   = loc.Location.SourceSpan.Start;
                            string projectedName;
                            int projectedOffset;
                            if (workspace.TryGetOriginalFileFromProjection(fileName, offset, out projectedName, out projectedOffset))
                            {
                                fileName = projectedName;
                                offset   = projectedOffset;
                            }
                            var sr = new SearchResult(new FileProvider(fileName), offset, loc.Location.SourceSpan.Length);
                            if (antiDuplicatesSet.Add(sr))
                            {
                                monitor.ReportResult(sr);
                            }
                        }
                    }
                } catch (Exception ex) {
                    if (monitor != null)
                    {
                        monitor.ReportError("Error finding references", ex);
                    }
                    else
                    {
                        LoggingService.LogError("Error finding references", ex);
                    }
                } finally {
                    if (monitor != null)
                    {
                        monitor.Dispose();
                    }
                }
            });
        }
Example #25
0
        public async Task Rename(ISymbol symbol)
        {
            var solution = IdeApp.ProjectOperations.CurrentSelectedSolution;
            var ws       = TypeSystemService.GetWorkspace(solution);

            var currentSolution = ws.CurrentSolution;
            var cts             = new CancellationTokenSource();
            var newSolution     = await MessageService.ExecuteTaskAndShowWaitDialog(Task.Run(() => Renamer.RenameSymbolAsync(currentSolution, symbol, "_" + symbol.Name + "_", ws.Options, cts.Token)), GettextCatalog.GetString("Looking for all references"), cts);

            var projectChanges   = currentSolution.GetChanges(newSolution).GetProjectChanges().ToList();
            var changedDocuments = new HashSet <string> ();

            foreach (var change in projectChanges)
            {
                foreach (var changedDoc in change.GetChangedDocuments())
                {
                    changedDocuments.Add(ws.CurrentSolution.GetDocument(changedDoc).FilePath);
                }
            }

            if (changedDocuments.Count > 1)
            {
                using (var dlg = new RenameItemDialog(symbol, this))
                    MessageService.ShowCustomDialog(dlg);
                return;
            }

            var projectChange = projectChanges [0];
            var changes       = projectChange.GetChangedDocuments().ToList();

            if (changes.Count != 1 || symbol.Kind == SymbolKind.NamedType)
            {
                using (var dlg = new RenameItemDialog(symbol, this))
                    MessageService.ShowCustomDialog(dlg);
                return;
            }
            var doc        = IdeApp.Workbench.ActiveDocument;
            var editor     = doc.Editor;
            var oldVersion = editor.Version;

            var links = new List <TextLink> ();
            var link  = new TextLink("name");

            var documents = ImmutableHashSet.Create(doc.AnalysisDocument);

            foreach (var loc in symbol.Locations)
            {
                if (loc.IsInSource && FilePath.PathComparer.Equals(loc.SourceTree.FilePath, doc.FileName))
                {
                    link.AddLink(new TextSegment(loc.SourceSpan.Start, loc.SourceSpan.Length));
                }
            }

            foreach (var mref in await SymbolFinder.FindReferencesAsync(symbol, TypeSystemService.Workspace.CurrentSolution, documents, default(CancellationToken)))
            {
                foreach (var loc in mref.Locations)
                {
                    TextSpan span   = loc.Location.SourceSpan;
                    var      root   = loc.Location.SourceTree.GetRoot();
                    var      node   = root.FindNode(loc.Location.SourceSpan);
                    var      trivia = root.FindTrivia(loc.Location.SourceSpan.Start);
                    if (!trivia.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia))
                    {
                        span = node.Span;
                    }
                    if (span.Start != loc.Location.SourceSpan.Start)
                    {
                        span = loc.Location.SourceSpan;
                    }
                    var segment = new TextSegment(span.Start, span.Length);
                    if (segment.Offset <= editor.CaretOffset && editor.CaretOffset <= segment.EndOffset)
                    {
                        link.Links.Insert(0, segment);
                    }
                    else
                    {
                        link.AddLink(segment);
                    }
                }
            }
            links.Add(link);

            editor.StartTextLinkMode(new TextLinkModeOptions(links, (arg) => {
                //If user cancel renaming revert changes
                if (!arg.Success)
                {
                    var textChanges = editor.Version.GetChangesTo(oldVersion).ToList();
                    foreach (var v in textChanges)
                    {
                        editor.ReplaceText(v.Offset, v.RemovalLength, v.InsertedText);
                    }
                }
            }));
        }
Example #26
0
        public async Task FindBasesAsync(
            Document document,
            int position,
            IFindUsagesContext context
            )
        {
            var cancellationToken   = context.CancellationToken;
            var symbolAndProjectOpt = await FindUsagesHelpers
                                      .GetRelevantSymbolAndProjectAtPositionAsync(document, position, cancellationToken)
                                      .ConfigureAwait(false);

            if (symbolAndProjectOpt == null)
            {
                await context
                .ReportMessageAsync(
                    EditorFeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret
                    )
                .ConfigureAwait(false);

                return;
            }

            var(symbol, project) = symbolAndProjectOpt.Value;

            var solution = project.Solution;
            var bases    = await FindBaseHelpers
                           .FindBasesAsync(symbol, solution, cancellationToken)
                           .ConfigureAwait(false);

            await context
            .SetSearchTitleAsync(
                string.Format(
                    EditorFeaturesResources._0_bases,
                    FindUsagesHelpers.GetDisplayName(symbol)
                    )
                )
            .ConfigureAwait(false);

            var found = false;

            // For each potential base, try to find its definition in sources.
            // If found, add it's definitionItem to the context.
            // If not found but the symbol is from metadata, create it's definition item from metadata and add to the context.
            foreach (var baseSymbol in bases)
            {
                var sourceDefinition = await SymbolFinder
                                       .FindSourceDefinitionAsync(baseSymbol, solution, cancellationToken)
                                       .ConfigureAwait(false);

                if (sourceDefinition != null)
                {
                    var definitionItem = await sourceDefinition
                                         .ToClassifiedDefinitionItemAsync(
                        solution,
                        isPrimary : true,
                        includeHiddenLocations : false,
                        FindReferencesSearchOptions.Default,
                        cancellationToken : cancellationToken
                        )
                                         .ConfigureAwait(false);

                    await context.OnDefinitionFoundAsync(definitionItem).ConfigureAwait(false);

                    found = true;
                }
                else if (baseSymbol.Locations.Any(l => l.IsInMetadata))
                {
                    var definitionItem = baseSymbol.ToNonClassifiedDefinitionItem(
                        solution,
                        includeHiddenLocations: true
                        );
                    await context.OnDefinitionFoundAsync(definitionItem).ConfigureAwait(false);

                    found = true;
                }
            }

            if (!found)
            {
                await context
                .ReportMessageAsync(EditorFeaturesResources.The_symbol_has_no_base)
                .ConfigureAwait(false);
            }
        }
            private ImmutableArray <IMethodSymbol> GetExtensionMethodsForSymbolsFromDifferentCompilation(
                MultiDictionary <ITypeSymbol, IMethodSymbol> matchingMethodSymbols,
                CancellationToken cancellationToken
                )
            {
                using var _ = ArrayBuilder <IMethodSymbol> .GetInstance(out var builder);

                // Matching extension method symbols are grouped based on their receiver type.
                foreach (var(declaredReceiverType, methodSymbols) in matchingMethodSymbols)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var declaredReceiverTypeInOriginatingCompilation = SymbolFinder
                                                                       .FindSimilarSymbols(
                        declaredReceiverType,
                        _originatingSemanticModel.Compilation,
                        cancellationToken
                        )
                                                                       .FirstOrDefault();
                    if (declaredReceiverTypeInOriginatingCompilation == null)
                    {
                        // Bug: https://github.com/dotnet/roslyn/issues/45404
                        // SymbolFinder.FindSimilarSymbols would fail if originating and referenced compilation targeting different frameworks say net472 and netstandard respectively.
                        // Here's SymbolKey for System.String from those two framework as an example:
                        //
                        //  {1 (D "String" (N "System" 0 (N "" 0 (U (S "netstandard" 4) 3) 2) 1) 0 0 (% 0) 0)}
                        //  {1 (D "String" (N "System" 0 (N "" 0 (U (S "mscorlib" 4) 3) 2) 1) 0 0 (% 0) 0)}
                        //
                        // Also we don't use the "ignoreAssemblyKey" option for SymbolKey resolution because its perfermance doesn't meet our requirement.
                        continue;
                    }

                    if (
                        _checkedReceiverTypes.TryGetValue(
                            declaredReceiverTypeInOriginatingCompilation,
                            out var cachedResult
                            ) && !cachedResult
                        )
                    {
                        // If we already checked an extension method with same receiver type before, and we know it can't be applied
                        // to the receiverTypeSymbol, then no need to proceed methods from this group..
                        continue;
                    }

                    // This is also affected by the symbol resolving issue mentioned above, which means in case referenced projects
                    // are targeting different framework, we will miss extension methods with any framework type in their signature from those projects.
                    var isFirstMethod = true;
                    foreach (
                        var methodInOriginatingCompilation in methodSymbols
                        .Select(
                            s =>
                            SymbolFinder
                            .FindSimilarSymbols(
                                s,
                                _originatingSemanticModel.Compilation
                                )
                            .FirstOrDefault()
                            )
                        .WhereNotNull()
                        )
                    {
                        if (isFirstMethod)
                        {
                            isFirstMethod = false;

                            // We haven't seen this receiver type yet. Try to check by reducing one extension method
                            // to the given receiver type and save the result.
                            if (!cachedResult)
                            {
                                // If this is the first symbol we retrived from originating compilation,
                                // try to check if we can apply it to given receiver type, and save result to our cache.
                                // Since method symbols are grouped by their declared receiver type, they are either all matches to the receiver type
                                // or all mismatches. So we only need to call ReduceExtensionMethod on one of them.
                                var reducedMethodSymbol =
                                    methodInOriginatingCompilation.ReduceExtensionMethod(
                                        _receiverTypeSymbol
                                        );
                                cachedResult = reducedMethodSymbol != null;
                                _checkedReceiverTypes[
                                    declaredReceiverTypeInOriginatingCompilation
                                ] = cachedResult;

                                // Now, cachedResult being false means method doesn't match the receiver type,
                                // stop processing methods from this group.
                                if (!cachedResult)
                                {
                                    break;
                                }
                            }
                        }

                        if (
                            _originatingSemanticModel.IsAccessible(
                                _position,
                                methodInOriginatingCompilation
                                )
                            )
                        {
                            builder.Add(methodInOriginatingCompilation);
                        }
                    }
                }

                return(builder.ToImmutable());
            }
Example #28
0
        public static async Task <ImmutableArray <SymbolAndProjectId> > FindImplementationsForInterfaceMemberAsync(
            this SymbolAndProjectId <ITypeSymbol> typeSymbolAndProjectId,
            SymbolAndProjectId interfaceMemberAndProjectId,
            Solution solution,
            CancellationToken cancellationToken)
        {
            // This method can return multiple results.  Consider the case of:
            //
            // interface IGoo<X> { void Goo(X x); }
            //
            // class C : IGoo<int>, IGoo<string> { void Goo(int x); void Goo(string x); }
            //
            // If you're looking for the implementations of IGoo<X>.Goo then you want to find both
            // results in C.

            var arrBuilder = ArrayBuilder <SymbolAndProjectId> .GetInstance();

            var interfaceMember = interfaceMemberAndProjectId.Symbol;

            // TODO(cyrusn): Implement this using the actual code for
            // TypeSymbol.FindImplementationForInterfaceMember
            var typeSymbol = typeSymbolAndProjectId.Symbol;

            if (typeSymbol == null || interfaceMember == null)
            {
                return(arrBuilder.ToImmutableAndFree());
            }

            if (interfaceMember.Kind != SymbolKind.Event &&
                interfaceMember.Kind != SymbolKind.Method &&
                interfaceMember.Kind != SymbolKind.Property)
            {
                return(arrBuilder.ToImmutableAndFree());
            }

            // WorkItem(4843)
            //
            // 'typeSymbol' has to at least implement the interface containing the member.  note:
            // this just means that the interface shows up *somewhere* in the inheritance chain of
            // this type.  However, this type may not actually say that it implements it.  For
            // example:
            //
            // interface I { void Goo(); }
            //
            // class B { }
            //
            // class C : B, I { }
            //
            // class D : C { }
            //
            // D does implement I transitively through C.  However, even if D has a "Goo" method, it
            // won't be an implementation of I.Goo.  The implementation of I.Goo must be from a type
            // that actually has I in it's direct interface chain, or a type that's a base type of
            // that.  in this case, that means only classes C or B.
            var interfaceType = interfaceMember.ContainingType;

            if (!typeSymbol.ImplementsIgnoringConstruction(interfaceType))
            {
                return(arrBuilder.ToImmutableAndFree());
            }

            // We've ascertained that the type T implements some constructed type of the form I<X>.
            // However, we're not precisely sure which constructions of I<X> are being used.  For
            // example, a type C might implement I<int> and I<string>.  If we're searching for a
            // method from I<X> we might need to find several methods that implement different
            // instantiations of that method.
            var originalInterfaceType   = interfaceMember.ContainingType.OriginalDefinition;
            var originalInterfaceMember = interfaceMember.OriginalDefinition;

            var constructedInterfaces = typeSymbol.AllInterfaces.Where(i =>
                                                                       SymbolEquivalenceComparer.Instance.Equals(i.OriginalDefinition, originalInterfaceType));

            // Try to get the compilation for the symbol we're searching for,
            // which can help identify matches with the call to SymbolFinder.OriginalSymbolsMatch.
            // OriginalSymbolMatch allows types to be matched across different assemblies
            // if they are considered to be the same type, which provides a more accurate
            // implementations list for interfaces.
            var typeSymbolProject      = solution.GetProject(typeSymbolAndProjectId.ProjectId);
            var interfaceMemberProject = solution.GetProject(interfaceMemberAndProjectId.ProjectId);

            var typeSymbolCompilation = await GetCompilationOrNullAsync(typeSymbolProject, cancellationToken).ConfigureAwait(false);

            var interfaceMemberCompilation = await GetCompilationOrNullAsync(interfaceMemberProject, cancellationToken).ConfigureAwait(false);

            foreach (var constructedInterface in constructedInterfaces)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var constructedInterfaceMember = constructedInterface.GetMembers().FirstOrDefault(typeSymbol =>
                                                                                                  SymbolFinder.OriginalSymbolsMatch(
                                                                                                      typeSymbol,
                                                                                                      interfaceMember,
                                                                                                      solution,
                                                                                                      typeSymbolCompilation,
                                                                                                      interfaceMemberCompilation,
                                                                                                      cancellationToken));

                if (constructedInterfaceMember == null)
                {
                    continue;
                }

                // Now we need to walk the base type chain, but we start at the first type that actually
                // has the interface directly in its interface hierarchy.
                var seenTypeDeclaringInterface = false;
                for (var currentType = typeSymbol; currentType != null; currentType = currentType.BaseType)
                {
                    seenTypeDeclaringInterface = seenTypeDeclaringInterface ||
                                                 currentType.GetOriginalInterfacesAndTheirBaseInterfaces().Contains(interfaceType.OriginalDefinition);

                    if (seenTypeDeclaringInterface)
                    {
                        var result = currentType.FindImplementations(constructedInterfaceMember, solution.Workspace);

                        if (result != null)
                        {
                            arrBuilder.Add(typeSymbolAndProjectId.WithSymbol(result));
                            break;
                        }
                    }
                }
            }

            return(arrBuilder.ToImmutableAndFree());
Example #29
0
        protected override async Task <IEnumerable <SymbolCallerInfo> > GetCallersAsync(ISymbol symbol, Project project, IImmutableSet <Document> documents, CancellationToken cancellationToken)
        {
            var callers = await SymbolFinder.FindCallersAsync(symbol, project.Solution, documents, cancellationToken).ConfigureAwait(false);

            return(callers.Where(c => c.IsDirect));
        }
Example #30
0
        internal async Task <IEnumerable <ValueTuple <ISymbol, IEnumerable <PatternMatch> > > > FindNavigableSourceSymbolsAsync(
            Project project, CancellationToken cancellationToken)
        {
            var results = new List <ValueTuple <ISymbol, IEnumerable <PatternMatch> > >();

            // The compiler API only supports a predicate which is given a symbol's name.  Because
            // we only have the name, and nothing else, we need to check it against the last segment
            // of the pattern.  i.e. if the pattern is 'Console.WL' and we are given 'WriteLine', then
            // we don't want to check the whole pattern against it (as it will clearly fail), instead
            // we only want to check the 'WL' portion.  Then, after we get all the candidate symbols
            // we'll check if the full name matches the full pattern.
            var patternMatcher = new PatternMatcher(_searchPattern);
            var symbols        = await SymbolFinder.FindSourceDeclarationsAsync(
                project, k => patternMatcher.GetMatchesForLastSegmentOfPattern(k) != null, SymbolFilter.TypeAndMember, cancellationToken).ConfigureAwait(false);

            symbols = symbols.Where(s =>
                                    !s.IsConstructor() &&
                                    !s.IsStaticConstructor() && // not constructors, they get matched on type name
                                    !(s is INamespaceSymbol) && // not namespaces
                                    s.Locations.Any(loc => loc.IsInSource)); // only source symbols

            foreach (var symbol in symbols)
            {
                cancellationToken.ThrowIfCancellationRequested();

                // As an optimization, don't bother getting the container for this symbol if this
                // isn't a dotted pattern.  Getting the container could cause lots of string
                // allocations that we don't if we're never going to check it.
                var matches = !patternMatcher.IsDottedPattern
                    ? patternMatcher.GetMatches(GetSearchName(symbol))
                    : patternMatcher.GetMatches(GetSearchName(symbol), GetContainer(symbol));

                if (matches == null)
                {
                    continue;
                }

                results.Add(ValueTuple.Create(symbol, matches));

                // also report matching constructors (using same match result as type)
                var namedType = symbol as INamedTypeSymbol;
                if (namedType != null)
                {
                    foreach (var constructor in namedType.Constructors)
                    {
                        // only constructors that were explicitly declared
                        if (!constructor.IsImplicitlyDeclared)
                        {
                            results.Add(ValueTuple.Create((ISymbol)constructor, matches));
                        }
                    }
                }

                // report both parts of partial methods
                var method = symbol as IMethodSymbol;
                if (method != null && method.PartialImplementationPart != null)
                {
                    results.Add(ValueTuple.Create((ISymbol)method, matches));
                }
            }

            return(results);
        }