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); }
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); }
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()); }
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); }); }
/// <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)); }
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); }
protected override Task <ImmutableArray <ISymbol> > FindDeclarationsAsync( string name, SymbolFilter filter, SearchQuery searchQuery) { return(SymbolFinder.FindAllDeclarationsWithNormalQueryAsync(_project, searchQuery, filter, CancellationToken)); }
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); }
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); } }
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); }
public Task <ImmutableArray <ISymbol> > DetermineCascadedSymbolsAsync( ISymbol symbol, Solution solution, IImmutableSet <Project> projects, FindReferencesSearchOptions options, CancellationToken cancellationToken) { return(SymbolFinder.FindLinkedSymbolsAsync(symbol, solution, cancellationToken)); }
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)); }
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); } } }
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); }
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); }
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(); } }
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(); } } }); }
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); } } })); }
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()); }
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());
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)); }
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); }