private static bool ParameterTypesMatch(SemanticDocument document, IList<ITypeSymbol> parameterTypes, IMethodSymbol method) { if (method == null) { return false; } if (parameterTypes.Count < method.Parameters.Length) { return false; } var compilation = document.SemanticModel.Compilation; var semanticFactsService = document.Document.GetLanguageService<ISemanticFactsService>(); for (var i = 0; i < parameterTypes.Count; i++) { var type1 = parameterTypes[i]; if (type1 != null) { var type2 = method.Parameters[i].Type; if (!semanticFactsService.IsAssignableTo(type1, type2, compilation)) { return false; } } } return true; }
public static async Task<InsertionPoint> CreateAsync(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken) { var root = document.Root; var annotation = new SyntaxAnnotation(); var newRoot = root.AddAnnotations(SpecializedCollections.SingletonEnumerable(Tuple.Create(node, annotation))); return new InsertionPoint(await document.WithSyntaxRootAsync(newRoot, cancellationToken).ConfigureAwait(false), annotation); }
public AnalyzerResult( SemanticDocument document, IEnumerable<ITypeParameterSymbol> typeParametersInDeclaration, IEnumerable<ITypeParameterSymbol> typeParametersInConstraintList, IList<VariableInfo> variables, VariableInfo variableToUseAsReturnValue, ITypeSymbol returnType, bool awaitTaskReturn, bool instanceMemberIsUsed, bool endOfSelectionReachable, OperationStatus status) { var semanticModel = document.SemanticModel; this.UseInstanceMember = instanceMemberIsUsed; this.EndOfSelectionReachable = endOfSelectionReachable; this.AwaitTaskReturn = awaitTaskReturn; this.SemanticDocument = document; _typeParametersInDeclaration = typeParametersInDeclaration.Select(s => semanticModel.ResolveType(s)).ToList(); _typeParametersInConstraintList = typeParametersInConstraintList.Select(s => semanticModel.ResolveType(s)).ToList(); _variables = variables; this.ReturnType = semanticModel.ResolveType(returnType); _variableToUseAsReturnValue = variableToUseAsReturnValue; this.Status = status; }
public TriviaResult(SemanticDocument document, ITriviaSavedResult result, int endOfLineKind, int whitespaceKind) { this.SemanticDocument = document; _result = result; _endOfLineKind = endOfLineKind; _whitespaceKind = whitespaceKind; }
private InsertionPoint(SemanticDocument document, SyntaxAnnotation annotation) { Contract.ThrowIfNull(document); Contract.ThrowIfNull(annotation); this.SemanticDocument = document; _annotation = annotation; _context = CreateLazyContextNode(); }
private ExtractMethodResult CreateExtractMethodResult( OperationStatus status, SemanticDocument semanticDocument, SyntaxAnnotation invocationAnnotation, SyntaxAnnotation methodAnnotation) { var newRoot = semanticDocument.Root; var annotatedTokens = newRoot.GetAnnotatedNodesAndTokens(invocationAnnotation); var methodDefinition = newRoot.GetAnnotatedNodesAndTokens(methodAnnotation).FirstOrDefault().AsNode(); return new SimpleExtractMethodResult(status, semanticDocument.Document, GetMethodNameAtInvocation(annotatedTokens), methodDefinition); }
public StatementResult( OperationStatus status, TextSpan originalSpan, TextSpan finalSpan, OptionSet options, bool selectionInExpression, SemanticDocument document, SyntaxAnnotation firstTokenAnnotation, SyntaxAnnotation lastTokenAnnotation) : base(status, originalSpan, finalSpan, options, selectionInExpression, document, firstTokenAnnotation, lastTokenAnnotation) { }
internal static async Task<State> GenerateAsync( SemanticDocument document, LocalDeclarationStatementSyntax statement, CancellationToken cancellationToken) { var state = new State(); if (!await state.TryInitializeAsync(document, statement, cancellationToken).ConfigureAwait(false)) { return null; } return state; }
public GeneratedCode( OperationStatus status, SemanticDocument document, SyntaxAnnotation methodNameAnnotation, SyntaxAnnotation callsiteAnnotation, SyntaxAnnotation methodDefinitionAnnotation) { Contract.ThrowIfNull(document); Contract.ThrowIfNull(methodNameAnnotation); Contract.ThrowIfNull(callsiteAnnotation); Contract.ThrowIfNull(methodDefinitionAnnotation); this.Status = status; this.SemanticDocument = document; this.MethodNameAnnotation = methodNameAnnotation; this.CallSiteAnnotation = callsiteAnnotation; this.MethodDefinitionAnnotation = methodDefinitionAnnotation; }
public AnalyzerResult With(SemanticDocument document) { if (this.SemanticDocument == document) { return this; } return new AnalyzerResult( document, _typeParametersInDeclaration, _typeParametersInConstraintList, _variables, _variableToUseAsReturnValue, this.ReturnType, this.AwaitTaskReturn, this.UseInstanceMember, this.EndOfSelectionReachable, this.Status); }
public static IMethodSymbol GetDelegatingConstructor( SemanticDocument document, SymbolInfo symbolInfo, ISet<IMethodSymbol> candidateInstanceConstructors, INamedTypeSymbol containingType, IList<ITypeSymbol> parameterTypes) { var symbol = symbolInfo.Symbol as IMethodSymbol; if (symbol == null && symbolInfo.CandidateSymbols.Length == 1) { // Even though the symbol info has a non-viable candidate symbol, we are trying // to speculate a base constructor invocation from a different position then // where the invocation to it would be generated. Passed in candidateInstanceConstructors // actually represent all accessible and invocable constructor symbols. So, we allow // candidate symbol for inaccessible OR not creatable candidate reason if it is in // the given candidateInstanceConstructors. // // Note: if we get either of these cases, we ensure that we can at least convert // the parameter types we have to the constructor parameter types. This way we // don't accidently think we delegate to a constructor in an abstract base class // when the parameter types don't match. if (symbolInfo.CandidateReason == CandidateReason.Inaccessible || (symbolInfo.CandidateReason == CandidateReason.NotCreatable && containingType.IsAbstract)) { var method = symbolInfo.CandidateSymbols.Single() as IMethodSymbol; if (ParameterTypesMatch(document, parameterTypes, method)) { symbol = method; } } } if (symbol != null && candidateInstanceConstructors.Contains(symbol)) { return symbol; } return null; }
private Document RewriteExpressionBodiedMemberAndIntroduceLocalDeclaration( SemanticDocument document, ExpressionSyntax expression, NameSyntax newLocalName, LocalDeclarationStatementSyntax declarationStatement, bool allOccurrences, CancellationToken cancellationToken) { var oldBody = expression.GetAncestorOrThis <ArrowExpressionClauseSyntax>(); var oldParentingNode = oldBody.Parent; var leadingTrivia = oldBody.GetLeadingTrivia() .AddRange(oldBody.ArrowToken.TrailingTrivia); var newStatement = Rewrite(document, expression, newLocalName, document, oldBody.Expression, allOccurrences, cancellationToken); var newBody = SyntaxFactory.Block(declarationStatement, SyntaxFactory.ReturnStatement(newStatement)) .WithLeadingTrivia(leadingTrivia) .WithTrailingTrivia(oldBody.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); SyntaxNode newParentingNode = null; if (oldParentingNode is BasePropertyDeclarationSyntax) { var getAccessor = SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration, newBody); var accessorList = SyntaxFactory.AccessorList(SyntaxFactory.List(new[] { getAccessor })); newParentingNode = ((BasePropertyDeclarationSyntax)oldParentingNode).RemoveNode(oldBody, SyntaxRemoveOptions.KeepNoTrivia); if (newParentingNode.IsKind(SyntaxKind.PropertyDeclaration)) { var propertyDeclaration = ((PropertyDeclarationSyntax)newParentingNode); newParentingNode = propertyDeclaration .WithAccessorList(accessorList) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None)) .WithTrailingTrivia(propertyDeclaration.SemicolonToken.TrailingTrivia); } else if (newParentingNode.IsKind(SyntaxKind.IndexerDeclaration)) { var indexerDeclaration = ((IndexerDeclarationSyntax)newParentingNode); newParentingNode = indexerDeclaration .WithAccessorList(accessorList) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None)) .WithTrailingTrivia(indexerDeclaration.SemicolonToken.TrailingTrivia); } } else if (oldParentingNode is BaseMethodDeclarationSyntax) { newParentingNode = ((BaseMethodDeclarationSyntax)oldParentingNode) .RemoveNode(oldBody, SyntaxRemoveOptions.KeepNoTrivia) .WithBody(newBody); if (newParentingNode.IsKind(SyntaxKind.MethodDeclaration)) { var methodDeclaration = ((MethodDeclarationSyntax)newParentingNode); newParentingNode = methodDeclaration .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None)) .WithTrailingTrivia(methodDeclaration.SemicolonToken.TrailingTrivia); } else if (newParentingNode.IsKind(SyntaxKind.OperatorDeclaration)) { var operatorDeclaration = ((OperatorDeclarationSyntax)newParentingNode); newParentingNode = operatorDeclaration .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None)) .WithTrailingTrivia(operatorDeclaration.SemicolonToken.TrailingTrivia); } else if (newParentingNode.IsKind(SyntaxKind.ConversionOperatorDeclaration)) { var conversionOperatorDeclaration = ((ConversionOperatorDeclarationSyntax)newParentingNode); newParentingNode = conversionOperatorDeclaration .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None)) .WithTrailingTrivia(conversionOperatorDeclaration.SemicolonToken.TrailingTrivia); } } var newRoot = document.Root.ReplaceNode(oldParentingNode, newParentingNode); return(document.Document.WithSyntaxRoot(newRoot)); }
public ITypeSymbol GetVariableType(SemanticDocument document) { return document.SemanticModel.ResolveType(_variableSymbol.OriginalType); }
public InsertionPoint With(SemanticDocument document) { return new InsertionPoint(document, _annotation); }
protected abstract Task<InsertionPoint> GetInsertionPointAsync(SemanticDocument document, int position, CancellationToken cancellationToken);
protected abstract bool TryInitializeExplicitInterfaceState(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken, out SyntaxToken identifierToken, out IPropertySymbol propertySymbol, out INamedTypeSymbol typeToGenerateIn);
private State(SemanticDocument document) { SemanticDocument = document; }
public ITypeSymbol GetVariableType(SemanticDocument document) { return(document.SemanticModel.ResolveType(_variableSymbol.OriginalType)); }
public SyntaxToken GetIdentifierTokenAtDeclaration(SemanticDocument document) { return(document.GetTokenWithAnnotation(_variableSymbol.IdentifierTokenAnnotation)); }
protected abstract SyntaxNode GetPreviousMember(SemanticDocument document);
private bool TryInitializeIdentifierName( TService service, SemanticDocument semanticDocument, TSimpleNameSyntax identifierName, CancellationToken cancellationToken) { SimpleName = identifierName; if (!service.TryInitializeIdentifierNameState(semanticDocument, identifierName, cancellationToken, out var identifierToken, out var simpleNameOrMemberAccessExpression)) { return(false); } IdentifierToken = identifierToken; SimpleNameOrMemberAccessExpression = simpleNameOrMemberAccessExpression; var semanticModel = semanticDocument.SemanticModel; var semanticFacts = semanticDocument.Document.GetLanguageService <ISemanticFactsService>(); var syntaxFacts = semanticDocument.Document.GetLanguageService <ISyntaxFactsService>(); if (semanticFacts.IsWrittenTo(semanticModel, SimpleNameOrMemberAccessExpression, cancellationToken) || syntaxFacts.IsInNamespaceOrTypeContext(SimpleNameOrMemberAccessExpression)) { return(false); } // Now, try to bind the invocation and see if it succeeds or not. if it succeeds and // binds uniquely, then we don't need to offer this quick fix. cancellationToken.ThrowIfCancellationRequested(); var containingType = semanticModel.GetEnclosingNamedType(identifierToken.SpanStart, cancellationToken); if (containingType == null) { return(false); } var semanticInfo = semanticModel.GetSymbolInfo(SimpleNameOrMemberAccessExpression, cancellationToken); if (cancellationToken.IsCancellationRequested) { return(false); } if (semanticInfo.Symbol != null) { return(false); } // Either we found no matches, or this was ambiguous. Either way, we might be able // to generate a method here. Determine where the user wants to generate the method // into, and if it's valid then proceed. if (!TryDetermineTypeToGenerateIn( semanticDocument, containingType, simpleNameOrMemberAccessExpression, cancellationToken, out var typeToGenerateIn, out var isStatic)) { return(false); } if (!isStatic) { return(false); } TypeToGenerateIn = typeToGenerateIn; return(true); }
protected virtual Task <GeneratedCode> CreateGeneratedCodeAsync(OperationStatus status, SemanticDocument newDocument, CancellationToken cancellationToken) { return(Task.FromResult(new GeneratedCode( status, newDocument, MethodNameAnnotation, CallSiteAnnotation, MethodDefinitionAnnotation))); }
protected virtual Task <SemanticDocument> UpdateMethodAfterGenerationAsync( SemanticDocument originalDocument, OperationStatus <IMethodSymbol> methodSymbolResult, CancellationToken cancellationToken) => Task.FromResult(originalDocument);
protected abstract AbstractInvocationInfo CreateInvocationMethodInfo(SemanticDocument document, State abstractState);
protected override bool TryInitializeState( SemanticDocument document, SimpleNameSyntax simpleName, CancellationToken cancellationToken, out GenerateTypeServiceStateOptions generateTypeServiceStateOptions) { generateTypeServiceStateOptions = new GenerateTypeServiceStateOptions(); if (simpleName.IsVar) { return(false); } if (SyntaxFacts.IsAliasQualifier(simpleName)) { return(false); } // Never offer if we're in a using directive, unless its a static using. The feeling here is that it's highly // unlikely that this would be a location where a user would be wanting to generate // something. They're really just trying to reference something that exists but // isn't available for some reason (i.e. a missing reference). var usingDirectiveSyntax = simpleName.GetAncestorOrThis <UsingDirectiveSyntax>(); if (usingDirectiveSyntax != null && usingDirectiveSyntax.StaticKeyword.Kind() != SyntaxKind.StaticKeyword) { return(false); } ExpressionSyntax nameOrMemberAccessExpression = null; if (simpleName.IsRightSideOfDot()) { // This simplename comes from the cref if (simpleName.IsParentKind(SyntaxKind.NameMemberCref)) { return(false); } nameOrMemberAccessExpression = generateTypeServiceStateOptions.NameOrMemberAccessExpression = (ExpressionSyntax)simpleName.Parent; // If we're on the right side of a dot, then the left side better be a name (and // not an arbitrary expression). var leftSideExpression = simpleName.GetLeftSideOfDot(); if (!leftSideExpression.IsKind( SyntaxKind.QualifiedName, SyntaxKind.IdentifierName, SyntaxKind.AliasQualifiedName, SyntaxKind.GenericName, SyntaxKind.SimpleMemberAccessExpression)) { return(false); } } else { nameOrMemberAccessExpression = generateTypeServiceStateOptions.NameOrMemberAccessExpression = simpleName; } // BUG(5712): Don't offer generate type in an enum's base list. if (nameOrMemberAccessExpression.Parent is BaseTypeSyntax && nameOrMemberAccessExpression.Parent.IsParentKind(SyntaxKind.BaseList) && ((BaseTypeSyntax)nameOrMemberAccessExpression.Parent).Type == nameOrMemberAccessExpression && nameOrMemberAccessExpression.Parent.Parent.IsParentKind(SyntaxKind.EnumDeclaration)) { return(false); } // If we can guarantee it's a type only context, great. Otherwise, we may not want to // provide this here. var semanticModel = document.SemanticModel; if (!SyntaxFacts.IsInNamespaceOrTypeContext(nameOrMemberAccessExpression)) { // Don't offer Generate Type in an expression context *unless* we're on the left // side of a dot. In that case the user might be making a type that they're // accessing a static off of. var syntaxTree = semanticModel.SyntaxTree; var start = nameOrMemberAccessExpression.SpanStart; var tokenOnLeftOfStart = syntaxTree.FindTokenOnLeftOfPosition(start, cancellationToken); var isExpressionContext = syntaxTree.IsExpressionContext(start, tokenOnLeftOfStart, attributes: true, cancellationToken: cancellationToken, semanticModelOpt: semanticModel); var isStatementContext = syntaxTree.IsStatementContext(start, tokenOnLeftOfStart, cancellationToken); var isExpressionOrStatementContext = isExpressionContext || isStatementContext; // Delegate Type Creation is not allowed in Non Type Namespace Context generateTypeServiceStateOptions.IsDelegateAllowed = false; if (!isExpressionOrStatementContext) { return(false); } if (!simpleName.IsLeftSideOfDot() && !simpleName.IsInsideNameOf()) { if (nameOrMemberAccessExpression == null || !nameOrMemberAccessExpression.IsKind(SyntaxKind.SimpleMemberAccessExpression) || !simpleName.IsRightSideOfDot()) { return(false); } var leftSymbol = semanticModel.GetSymbolInfo(((MemberAccessExpressionSyntax)nameOrMemberAccessExpression).Expression).Symbol; var token = simpleName.GetLastToken().GetNextToken(); // We let only the Namespace to be left of the Dot if (leftSymbol == null || !leftSymbol.IsKind(SymbolKind.Namespace) || !token.IsKind(SyntaxKind.DotToken)) { return(false); } else { generateTypeServiceStateOptions.IsMembersWithModule = true; generateTypeServiceStateOptions.IsTypeGeneratedIntoNamespaceFromMemberAccess = true; } } // Global Namespace if (!generateTypeServiceStateOptions.IsTypeGeneratedIntoNamespaceFromMemberAccess && !SyntaxFacts.IsInNamespaceOrTypeContext(simpleName)) { var token = simpleName.GetLastToken().GetNextToken(); if (token.IsKind(SyntaxKind.DotToken) && simpleName.Parent == token.Parent) { generateTypeServiceStateOptions.IsMembersWithModule = true; generateTypeServiceStateOptions.IsTypeGeneratedIntoNamespaceFromMemberAccess = true; } } } var fieldDeclaration = simpleName.GetAncestor <FieldDeclarationSyntax>(); if (fieldDeclaration != null && fieldDeclaration.Parent is CompilationUnitSyntax && document.Document.SourceCodeKind == SourceCodeKind.Regular) { return(false); } // Check to see if Module could be an option in the Type Generation in Cross Language Generation var nextToken = simpleName.GetLastToken().GetNextToken(); if (simpleName.IsLeftSideOfDot() || nextToken.IsKind(SyntaxKind.DotToken)) { if (simpleName.IsRightSideOfDot()) { var parent = simpleName.Parent as QualifiedNameSyntax; if (parent != null) { var leftSymbol = semanticModel.GetSymbolInfo(parent.Left).Symbol; if (leftSymbol != null && leftSymbol.IsKind(SymbolKind.Namespace)) { generateTypeServiceStateOptions.IsMembersWithModule = true; } } } } if (SyntaxFacts.IsInNamespaceOrTypeContext(nameOrMemberAccessExpression)) { if (nextToken.IsKind(SyntaxKind.DotToken)) { // In Namespace or Type Context we cannot have Interface, Enum, Delegate as part of the Left Expression of a QualifiedName generateTypeServiceStateOptions.IsDelegateAllowed = false; generateTypeServiceStateOptions.IsInterfaceOrEnumNotAllowedInTypeContext = true; generateTypeServiceStateOptions.IsMembersWithModule = true; } // case: class Foo<T> where T: MyType if (nameOrMemberAccessExpression.GetAncestors <TypeConstraintSyntax>().Any()) { generateTypeServiceStateOptions.IsClassInterfaceTypes = true; return(true); } // Events if (nameOrMemberAccessExpression.GetAncestors <EventFieldDeclarationSyntax>().Any() || nameOrMemberAccessExpression.GetAncestors <EventDeclarationSyntax>().Any()) { // Case : event foo name11 // Only Delegate if (simpleName.Parent != null && !(simpleName.Parent is QualifiedNameSyntax)) { generateTypeServiceStateOptions.IsDelegateOnly = true; return(true); } // Case : event SomeSymbol.foo name11 if (nameOrMemberAccessExpression is QualifiedNameSyntax) { // Only Namespace, Class, Struct and Module are allowed to contain Delegate // Case : event Something.Mytype.<Delegate> Identifier if (nextToken.IsKind(SyntaxKind.DotToken)) { if (nameOrMemberAccessExpression.Parent != null && nameOrMemberAccessExpression.Parent is QualifiedNameSyntax) { return(true); } else { Contract.Fail("Cannot reach this point"); } } else { // Case : event Something.<Delegate> Identifier generateTypeServiceStateOptions.IsDelegateOnly = true; return(true); } } } } else { // MemberAccessExpression if ((nameOrMemberAccessExpression.IsKind(SyntaxKind.SimpleMemberAccessExpression) || (nameOrMemberAccessExpression.Parent != null && nameOrMemberAccessExpression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression))) && nameOrMemberAccessExpression.IsLeftSideOfDot()) { // Check to see if the expression is part of Invocation Expression ExpressionSyntax outerMostMemberAccessExpression = null; if (nameOrMemberAccessExpression.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { outerMostMemberAccessExpression = nameOrMemberAccessExpression; } else { Debug.Assert(nameOrMemberAccessExpression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)); outerMostMemberAccessExpression = (ExpressionSyntax)nameOrMemberAccessExpression.Parent; } outerMostMemberAccessExpression = outerMostMemberAccessExpression.GetAncestorsOrThis <ExpressionSyntax>().SkipWhile((n) => n != null && n.IsKind(SyntaxKind.SimpleMemberAccessExpression)).FirstOrDefault(); if (outerMostMemberAccessExpression != null && outerMostMemberAccessExpression is InvocationExpressionSyntax) { generateTypeServiceStateOptions.IsEnumNotAllowed = true; } } } // Cases: // // 1 - Function Address // var s2 = new MyD2(foo); // // 2 - Delegate // MyD1 d = null; // var s1 = new MyD2(d); // // 3 - Action // Action action1 = null; // var s3 = new MyD2(action1); // // 4 - Func // Func<int> lambda = () => { return 0; }; // var s4 = new MyD3(lambda); if (nameOrMemberAccessExpression.Parent is ObjectCreationExpressionSyntax) { var objectCreationExpressionOpt = generateTypeServiceStateOptions.ObjectCreationExpressionOpt = (ObjectCreationExpressionSyntax)nameOrMemberAccessExpression.Parent; // Enum and Interface not Allowed in Object Creation Expression generateTypeServiceStateOptions.IsInterfaceOrEnumNotAllowedInTypeContext = true; if (objectCreationExpressionOpt.ArgumentList != null) { if (objectCreationExpressionOpt.ArgumentList.CloseParenToken.IsMissing) { return(false); } // Get the Method symbol for the Delegate to be created if (generateTypeServiceStateOptions.IsDelegateAllowed && objectCreationExpressionOpt.ArgumentList.Arguments.Count == 1) { generateTypeServiceStateOptions.DelegateCreationMethodSymbol = GetMethodSymbolIfPresent(semanticModel, objectCreationExpressionOpt.ArgumentList.Arguments[0].Expression, cancellationToken); } else { generateTypeServiceStateOptions.IsDelegateAllowed = false; } } if (objectCreationExpressionOpt.Initializer != null) { foreach (var expression in objectCreationExpressionOpt.Initializer.Expressions) { var simpleAssignmentExpression = expression as AssignmentExpressionSyntax; if (simpleAssignmentExpression == null) { continue; } var name = simpleAssignmentExpression.Left as SimpleNameSyntax; if (name == null) { continue; } generateTypeServiceStateOptions.PropertiesToGenerate.Add(name); } } } if (generateTypeServiceStateOptions.IsDelegateAllowed) { // MyD1 z1 = foo; if (nameOrMemberAccessExpression.Parent.IsKind(SyntaxKind.VariableDeclaration)) { var variableDeclaration = (VariableDeclarationSyntax)nameOrMemberAccessExpression.Parent; if (variableDeclaration.Variables.Count != 0) { var firstVarDeclWithInitializer = variableDeclaration.Variables.FirstOrDefault(var => var.Initializer != null && var.Initializer.Value != null); if (firstVarDeclWithInitializer != null && firstVarDeclWithInitializer.Initializer != null && firstVarDeclWithInitializer.Initializer.Value != null) { generateTypeServiceStateOptions.DelegateCreationMethodSymbol = GetMethodSymbolIfPresent(semanticModel, firstVarDeclWithInitializer.Initializer.Value, cancellationToken); } } } // var w1 = (MyD1)foo; if (nameOrMemberAccessExpression.Parent.IsKind(SyntaxKind.CastExpression)) { var castExpression = (CastExpressionSyntax)nameOrMemberAccessExpression.Parent; if (castExpression.Expression != null) { generateTypeServiceStateOptions.DelegateCreationMethodSymbol = GetMethodSymbolIfPresent(semanticModel, castExpression.Expression, cancellationToken); } } } return(true); }
protected abstract bool TryInitializeState(SemanticDocument document, TextSpan textSpan, CancellationToken cancellationToken, out SyntaxNode baseTypeNode, out INamedTypeSymbol classType);
protected override SyntaxNode GetPreviousMember(SemanticDocument document) { var node = this.InsertionPoint.With(document).GetContext(); return((node.Parent is GlobalStatementSyntax) ? node.Parent : node); }
protected abstract bool TryInitializeState(SemanticDocument document, TSimpleNameSyntax simpleName, CancellationToken cancellationToken, out GenerateTypeServiceStateOptions generateTypeServiceStateOptions);
protected abstract bool TryInitializeIdentifierNameState(SemanticDocument document, TSimpleNameSyntax identifierName, CancellationToken cancellationToken, out SyntaxToken identifierToken, out TExpressionSyntax simpleNameOrMemberAccessExpression, out bool isInExecutableBlock, out bool isinConditionalAccessExpression);
protected override bool IsConstructorInitializerGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken) => node is ConstructorInitializerSyntax;
private bool TryInitializeSimpleName( TService service, SemanticDocument document, TSimpleNameSyntax simpleName, CancellationToken cancellationToken) { SyntaxToken identifierToken; TExpressionSyntax simpleNameOrMemberAccessExpression; bool isInExecutableBlock; bool isInConditionalAccessExpression; if (!service.TryInitializeIdentifierNameState( document, simpleName, cancellationToken, out identifierToken, out simpleNameOrMemberAccessExpression, out isInExecutableBlock, out isInConditionalAccessExpression)) { return(false); } if (string.IsNullOrWhiteSpace(identifierToken.ValueText)) { return(false); } this.SimpleNameOpt = simpleName; this.IdentifierToken = identifierToken; this.SimpleNameOrMemberAccessExpressionOpt = simpleNameOrMemberAccessExpression; this.IsInExecutableBlock = isInExecutableBlock; this.IsInConditionalAccessExpression = isInConditionalAccessExpression; // If we're in a type context then we shouldn't offer to generate a field or // property. var syntaxFacts = document.Project.LanguageServices.GetService <ISyntaxFactsService>(); if (syntaxFacts.IsInNamespaceOrTypeContext(this.SimpleNameOrMemberAccessExpressionOpt)) { return(false); } this.IsConstant = syntaxFacts.IsInConstantContext(this.SimpleNameOrMemberAccessExpressionOpt); // If we're not in a type, don't even bother. NOTE(cyrusn): We'll have to rethink this // for C# Script. cancellationToken.ThrowIfCancellationRequested(); var semanticModel = document.SemanticModel; this.ContainingType = semanticModel.GetEnclosingNamedType(this.IdentifierToken.SpanStart, cancellationToken); if (this.ContainingType == null) { return(false); } // Now, try to bind the invocation and see if it succeeds or not. if it succeeds and // binds uniquely, then we don't need to offer this quick fix. cancellationToken.ThrowIfCancellationRequested(); var semanticInfo = semanticModel.GetSymbolInfo(this.SimpleNameOrMemberAccessExpressionOpt, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); if (semanticInfo.Symbol != null) { return(false); } // Either we found no matches, or this was ambiguous. Either way, we might be able // to generate a method here. Determine where the user wants to generate the method // into, and if it's valid then proceed. cancellationToken.ThrowIfCancellationRequested(); INamedTypeSymbol typeToGenerateIn; bool isStatic; if (!service.TryDetermineTypeToGenerateIn(document, this.ContainingType, this.SimpleNameOrMemberAccessExpressionOpt, cancellationToken, out typeToGenerateIn, out isStatic)) { return(false); } this.TypeToGenerateIn = typeToGenerateIn; this.IsStatic = isStatic; DetermineFieldType(document, cancellationToken); var semanticFacts = document.Project.LanguageServices.GetService <ISemanticFactsService>(); this.IsInRefContext = semanticFacts.IsInRefContext(semanticModel, this.SimpleNameOrMemberAccessExpressionOpt, cancellationToken); this.IsInOutContext = semanticFacts.IsInOutContext(semanticModel, this.SimpleNameOrMemberAccessExpressionOpt, cancellationToken); this.IsWrittenTo = semanticFacts.IsWrittenTo(semanticModel, this.SimpleNameOrMemberAccessExpressionOpt, cancellationToken); this.IsOnlyWrittenTo = semanticFacts.IsOnlyWrittenTo(semanticModel, this.SimpleNameOrMemberAccessExpressionOpt, cancellationToken); this.IsInConstructor = DetermineIsInConstructor(document); this.IsInMemberContext = this.SimpleNameOpt != this.SimpleNameOrMemberAccessExpressionOpt || syntaxFacts.IsObjectInitializerNamedAssignmentIdentifier(this.SimpleNameOrMemberAccessExpressionOpt); return(true); }
protected override bool IsSimpleNameGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken) => node is SimpleNameSyntax;
private async Task<Tuple<bool, OperationStatus>> TryCheckVariableTypeAsync( SemanticDocument document, SyntaxNode contextNode, IEnumerable<VariableInfo> variables, OperationStatus status, CancellationToken cancellationToken) { if (status.FailedWithNoBestEffortSuggestion()) { return Tuple.Create(false, status); } var location = contextNode.GetLocation(); foreach (var variable in variables) { var originalType = variable.GetVariableType(document); var result = await CheckTypeAsync(document.Document, contextNode, location, originalType, cancellationToken).ConfigureAwait(false); if (result.FailedWithNoBestEffortSuggestion()) { status = status.With(result); return Tuple.Create(false, status); } } return Tuple.Create(true, status); }
internal abstract IMethodSymbol GetDelegatingConstructor(State state, SemanticDocument document, int argumentCount, INamedTypeSymbol namedType, ISet <IMethodSymbol> candidates, CancellationToken cancellationToken);
private async Task <bool> TryInitializeAsync( TService service, SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken) { if (service.IsIdentifierNameGeneration(node)) { // Cases that we deal with currently: // // 1) expr.Foo // 2) expr->Foo // 3) Foo if (!TryInitializeSimpleName(service, document, (TSimpleNameSyntax)node, cancellationToken)) { return(false); } } else if (service.IsExplicitInterfaceGeneration(node)) { // 4) bool IFoo.NewProp if (!TryInitializeExplicitInterface(service, document, node, cancellationToken)) { return(false); } } else { return(false); } // Ok. It either didn't bind to any symbols, or it bound to a symbol but with // errors. In the former case we definitely want to offer to generate a field. In // the latter case, we want to generate a field *unless* there's an existing member // with the same name. Note: it's ok if there's a method with the same name. var existingMembers = this.TypeToGenerateIn.GetMembers(this.IdentifierToken.ValueText) .Where(m => m.Kind != SymbolKind.Method); if (existingMembers.Any()) { // TODO: Code coverage // There was an existing method that the new method would clash with. return(false); } if (cancellationToken.IsCancellationRequested) { return(false); } this.TypeToGenerateIn = await SymbolFinder.FindSourceDefinitionAsync(this.TypeToGenerateIn, document.Project.Solution, cancellationToken).ConfigureAwait(false) as INamedTypeSymbol; if (!service.ValidateTypeToGenerateIn( document.Project.Solution, this.TypeToGenerateIn, this.IsStatic, ClassInterfaceModuleStructTypes, cancellationToken)) { return(false); } this.IsContainedInUnsafeType = service.ContainingTypesOrSelfHasUnsafeKeyword(this.TypeToGenerateIn); return(CanGenerateLocal() || CodeGenerator.CanAdd(document.Project.Solution, this.TypeToGenerateIn, cancellationToken)); }
public async Task <ExtractMethodResult> ExtractMethodAsync(CancellationToken cancellationToken) { var operationStatus = OriginalSelectionResult.Status; var analyzeResult = await AnalyzeAsync(OriginalSelectionResult, LocalFunction, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); operationStatus = await CheckVariableTypesAsync(analyzeResult.Status.With(operationStatus), analyzeResult, cancellationToken).ConfigureAwait(false); if (operationStatus.FailedWithNoBestEffortSuggestion()) { return(new FailedExtractMethodResult(operationStatus)); } var insertionPoint = await GetInsertionPointAsync(analyzeResult.SemanticDocument, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); var triviaResult = await PreserveTriviaAsync(OriginalSelectionResult.With(insertionPoint.SemanticDocument), cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); var expandedDocument = await ExpandAsync(OriginalSelectionResult.With(triviaResult.SemanticDocument), cancellationToken).ConfigureAwait(false); var options = await analyzeResult.SemanticDocument.Document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var generatedCode = await GenerateCodeAsync( insertionPoint.With(expandedDocument), OriginalSelectionResult.With(expandedDocument), analyzeResult.With(expandedDocument), options, cancellationToken).ConfigureAwait(false); var applied = await triviaResult.ApplyAsync(generatedCode, cancellationToken).ConfigureAwait(false); var afterTriviaRestored = applied.With(operationStatus); cancellationToken.ThrowIfCancellationRequested(); if (afterTriviaRestored.Status.FailedWithNoBestEffortSuggestion()) { return(await CreateExtractMethodResultAsync( operationStatus, generatedCode.SemanticDocument, generatedCode.MethodNameAnnotation, generatedCode.MethodDefinitionAnnotation, cancellationToken).ConfigureAwait(false)); } var finalDocument = afterTriviaRestored.Data.Document; finalDocument = await Formatter.FormatAsync( finalDocument, Formatter.Annotation, options : null, rules : GetFormattingRules(finalDocument), cancellationToken : cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); return(await CreateExtractMethodResultAsync( operationStatus.With(generatedCode.Status), await SemanticDocument.CreateAsync(finalDocument, cancellationToken).ConfigureAwait(false), generatedCode.MethodNameAnnotation, generatedCode.MethodDefinitionAnnotation, cancellationToken).ConfigureAwait(false)); }
protected override Task <Tuple <Document, SyntaxNode, int> > IntroduceFieldAsync( SemanticDocument document, ExpressionSyntax expression, bool allOccurrences, bool isConstant, CancellationToken cancellationToken) { var oldTypeDeclaration = expression.GetAncestorOrThis <TypeDeclarationSyntax>(); var oldType = oldTypeDeclaration != null ? document.SemanticModel.GetDeclaredSymbol(oldTypeDeclaration, cancellationToken) as INamedTypeSymbol : document.SemanticModel.Compilation.ScriptClass; var newNameToken = (SyntaxToken)GenerateUniqueFieldName(document, expression, isConstant, cancellationToken); var newQualifiedName = oldTypeDeclaration != null ? SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ParseName(oldType.ToDisplayString(Ambience.NameFormat)), SyntaxFactory.IdentifierName(newNameToken)) : (ExpressionSyntax)SyntaxFactory.IdentifierName(newNameToken); newQualifiedName = newQualifiedName.WithAdditionalAnnotations(Simplifier.Annotation); var newFieldDeclaration = SyntaxFactory.FieldDeclaration( default(SyntaxList <AttributeListSyntax>), MakeFieldModifiers(isConstant, inScript: oldType.IsScriptClass), SyntaxFactory.VariableDeclaration( GetTypeSymbol(document, expression, cancellationToken).GenerateTypeSyntax(), SyntaxFactory.SingletonSeparatedList( SyntaxFactory.VariableDeclarator( newNameToken.WithAdditionalAnnotations(RenameAnnotation.Create()), null, SyntaxFactory.EqualsValueClause(expression))))).WithAdditionalAnnotations(Formatter.Annotation); if (oldTypeDeclaration != null) { var newTypeDeclaration = Rewrite( document, expression, newQualifiedName, document, oldTypeDeclaration, allOccurrences, cancellationToken); var insertionIndex = isConstant ? DetermineConstantInsertPosition(oldTypeDeclaration.Members, newTypeDeclaration.Members) : DetermineFieldInsertPosition(oldTypeDeclaration.Members, newTypeDeclaration.Members); var finalTypeDeclaration = InsertMember(newTypeDeclaration, newFieldDeclaration, insertionIndex); SyntaxNode destination = oldTypeDeclaration; var newRoot = document.Root.ReplaceNode(oldTypeDeclaration, finalTypeDeclaration); return(Task.FromResult(Tuple.Create(document.Document.WithSyntaxRoot(newRoot), destination, insertionIndex))); } else { var oldCompilationUnit = (CompilationUnitSyntax)document.Root; var newCompilationUnit = Rewrite( document, expression, newQualifiedName, document, oldCompilationUnit, allOccurrences, cancellationToken); var insertionIndex = isConstant ? DetermineConstantInsertPosition(oldCompilationUnit.Members, newCompilationUnit.Members) : DetermineFieldInsertPosition(oldCompilationUnit.Members, newCompilationUnit.Members); SyntaxNode destination = oldCompilationUnit; var newRoot = newCompilationUnit.WithMembers(newCompilationUnit.Members.Insert(insertionIndex, newFieldDeclaration)); return(Task.FromResult(Tuple.Create(document.Document.WithSyntaxRoot(newRoot), destination, insertionIndex))); } }
private static bool CanSimplify( SemanticDocument document, ExpressionSyntax lambda, List <SyntaxToken> paramNames, InvocationExpressionSyntax invocation, CancellationToken cancellationToken) { if (invocation == null) { return(false); } if (invocation.ArgumentList.Arguments.Count != paramNames.Count) { return(false); } for (var i = 0; i < paramNames.Count; i++) { var argument = invocation.ArgumentList.Arguments[i]; if (argument.NameColon != null || argument.RefOrOutKeyword.Kind() != SyntaxKind.None || !argument.Expression.IsKind(SyntaxKind.IdentifierName)) { return(false); } var identifierName = (IdentifierNameSyntax)argument.Expression; if (identifierName.Identifier.ValueText != paramNames[i].ValueText) { return(false); } } var semanticModel = document.SemanticModel; var lambdaSemanticInfo = semanticModel.GetSymbolInfo(lambda, cancellationToken); var invocationSemanticInfo = semanticModel.GetSymbolInfo(invocation, cancellationToken); if (lambdaSemanticInfo.Symbol == null || invocationSemanticInfo.Symbol == null) { // Don't offer this if there are any errors or ambiguities. return(false); } var lambdaMethod = lambdaSemanticInfo.Symbol as IMethodSymbol; var invocationMethod = invocationSemanticInfo.Symbol as IMethodSymbol; if (lambdaMethod == null || invocationMethod == null) { return(false); } // TODO(cyrusn): Handle extension methods as well. if (invocationMethod.IsExtensionMethod) { return(false); } // Check if any of the parameter is of Type Dynamic foreach (var parameter in lambdaMethod.Parameters) { if (parameter.Type != null && parameter.Type.Kind == SymbolKind.DynamicType) { return(false); } } // Check if the parameter and return types match between the lambda and the // invocation. Note: return types can be covariant and argument types can be // contravariant. if (lambdaMethod.ReturnsVoid != invocationMethod.ReturnsVoid || lambdaMethod.Parameters.Length != invocationMethod.Parameters.Length) { return(false); } if (!lambdaMethod.ReturnsVoid) { // Return type has to be covariant. var conversion = document.SemanticModel.Compilation.ClassifyConversion( invocationMethod.ReturnType, lambdaMethod.ReturnType); if (!conversion.IsIdentityOrImplicitReference()) { return(false); } } // Parameter types have to be contravariant. for (var i = 0; i < lambdaMethod.Parameters.Length; i++) { var conversion = document.SemanticModel.Compilation.ClassifyConversion( lambdaMethod.Parameters[i].Type, invocationMethod.Parameters[i].Type); if (!conversion.IsIdentityOrImplicitReference()) { return(false); } } if (WouldCauseAmbiguity(lambda, invocation, semanticModel, cancellationToken)) { return(false); } // Looks like something we can simplify. return(true); }
public SyntaxToken GetIdentifierTokenAtDeclaration(SemanticDocument document) { return document.GetTokenWithAnnotaton(_variableSymbol.IdentifierTokenAnnotation); }
protected override async Task <GeneratedCode> CreateGeneratedCodeAsync(OperationStatus status, SemanticDocument newDocument, CancellationToken cancellationToken) { if (status.Succeeded()) { // in hybrid code cases such as extract method, formatter will have some difficulties on where it breaks lines in two. // here, we explicitly insert newline at the end of "{" of auto generated method decl so that anchor knows how to find out // indentation of inserted statements (from users code) with user code style preserved var root = newDocument.Root; var methodDefinition = root.GetAnnotatedNodes <MethodDeclarationSyntax>(this.MethodDefinitionAnnotation).First(); var newMethodDefinition = methodDefinition.ReplaceToken( methodDefinition.Body.OpenBraceToken, methodDefinition.Body.OpenBraceToken.WithAppendedTrailingTrivia( SpecializedCollections.SingletonEnumerable(SyntaxFactory.CarriageReturnLineFeed))); newDocument = await newDocument.WithSyntaxRootAsync(root.ReplaceNode(methodDefinition, newMethodDefinition), cancellationToken).ConfigureAwait(false); } return(await base.CreateGeneratedCodeAsync(status, newDocument, cancellationToken).ConfigureAwait(false)); }
public InvocationExpressionInfo(SemanticDocument document, State state) : base(document, state) { _invocationExpression = state.InvocationExpressionOpt; }
internal abstract IMethodSymbol GetDelegatingConstructor( SemanticDocument document, TObjectCreationExpressionSyntax objectCreation, INamedTypeSymbol namedType, ISet <IMethodSymbol> candidates, CancellationToken cancellationToken);
protected abstract Task <Document> IntroduceLocalAsync(SemanticDocument document, TExpressionSyntax expression, bool allOccurrences, bool isConstant, CancellationToken cancellationToken);
protected abstract Task <Tuple <Document, SyntaxNode, int> > IntroduceFieldAsync(SemanticDocument document, TExpressionSyntax expression, bool allOccurrences, bool isConstant, CancellationToken cancellationToken);
protected override Task<Tuple<Document, SyntaxNode, int>> IntroduceFieldAsync( SemanticDocument document, ExpressionSyntax expression, bool allOccurrences, bool isConstant, CancellationToken cancellationToken) { var oldTypeDeclaration = expression.GetAncestorOrThis<TypeDeclarationSyntax>(); var oldType = oldTypeDeclaration != null ? document.SemanticModel.GetDeclaredSymbol(oldTypeDeclaration, cancellationToken) as INamedTypeSymbol : document.SemanticModel.Compilation.ScriptClass; var newNameToken = GenerateUniqueFieldName(document, expression, isConstant, cancellationToken); var newQualifiedName = oldTypeDeclaration != null ? SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ParseName(oldType.ToNameDisplayString()), SyntaxFactory.IdentifierName(newNameToken)) : (ExpressionSyntax)SyntaxFactory.IdentifierName(newNameToken); newQualifiedName = newQualifiedName.WithAdditionalAnnotations(Simplifier.Annotation); var newFieldDeclaration = SyntaxFactory.FieldDeclaration( default(SyntaxList<AttributeListSyntax>), MakeFieldModifiers(isConstant, inScript: oldType.IsScriptClass), SyntaxFactory.VariableDeclaration( GetTypeSymbol(document, expression, cancellationToken).GenerateTypeSyntax(), SyntaxFactory.SingletonSeparatedList( SyntaxFactory.VariableDeclarator( newNameToken.WithAdditionalAnnotations(RenameAnnotation.Create()), null, SyntaxFactory.EqualsValueClause(expression))))).WithAdditionalAnnotations(Formatter.Annotation); if (oldTypeDeclaration != null) { var newTypeDeclaration = Rewrite( document, expression, newQualifiedName, document, oldTypeDeclaration, allOccurrences, cancellationToken); var insertionIndex = isConstant ? DetermineConstantInsertPosition(oldTypeDeclaration.Members, newTypeDeclaration.Members) : DetermineFieldInsertPosition(oldTypeDeclaration.Members, newTypeDeclaration.Members); var finalTypeDeclaration = InsertMember(newTypeDeclaration, newFieldDeclaration, insertionIndex); SyntaxNode destination = oldTypeDeclaration; var newRoot = document.Root.ReplaceNode(oldTypeDeclaration, finalTypeDeclaration); return Task.FromResult(Tuple.Create(document.Document.WithSyntaxRoot(newRoot), destination, insertionIndex)); } else { var oldCompilationUnit = (CompilationUnitSyntax)document.Root; var newCompilationUnit = Rewrite( document, expression, newQualifiedName, document, oldCompilationUnit, allOccurrences, cancellationToken); var insertionIndex = isConstant ? DetermineConstantInsertPosition(oldCompilationUnit.Members, newCompilationUnit.Members) : DetermineFieldInsertPosition(oldCompilationUnit.Members, newCompilationUnit.Members); SyntaxNode destination = oldCompilationUnit; var newRoot = newCompilationUnit.WithMembers(newCompilationUnit.Members.Insert(insertionIndex, newFieldDeclaration)); return Task.FromResult(Tuple.Create(document.Document.WithSyntaxRoot(newRoot), destination, insertionIndex)); } }
private bool TryInitializeSimpleName( TService service, SemanticDocument semanticDocument, TSimpleNameSyntax simpleName, CancellationToken cancellationToken) { MethodKind = MethodKind.Ordinary; SimpleNameOpt = simpleName; if (!service.TryInitializeSimpleNameState( semanticDocument, simpleName, cancellationToken, out var identifierToken, out var simpleNameOrMemberAccessExpression, out var invocationExpressionOpt, out var isInConditionalExpression)) { return(false); } IdentifierToken = identifierToken; SimpleNameOrMemberAccessExpression = simpleNameOrMemberAccessExpression; InvocationExpressionOpt = invocationExpressionOpt; IsInConditionalAccessExpression = isInConditionalExpression; if (string.IsNullOrWhiteSpace(IdentifierToken.ValueText)) { return(false); } // If we're not in a type, don't even bother. NOTE(cyrusn): We'll have to rethink this // for C# Script. cancellationToken.ThrowIfCancellationRequested(); var semanticModel = semanticDocument.SemanticModel; ContainingType = semanticModel.GetEnclosingNamedType(SimpleNameOpt.SpanStart, cancellationToken); if (ContainingType == null) { return(false); } if (InvocationExpressionOpt != null) { SignatureInfo = service.CreateInvocationMethodInfo(semanticDocument, this); } else { var typeInference = semanticDocument.Document.GetLanguageService <ITypeInferenceService>(); var delegateType = typeInference.InferDelegateType(semanticModel, SimpleNameOrMemberAccessExpression, cancellationToken); if (delegateType != null && delegateType.DelegateInvokeMethod != null) { SignatureInfo = new MethodSignatureInfo(semanticDocument, this, delegateType.DelegateInvokeMethod); } else { // We don't have and invocation expression or a delegate, but we may have a special expression without parenthesis. Lets see // if the type inference service can directly infer the type for our expression. var expressionType = service.DetermineReturnTypeForSimpleNameOrMemberAccessExpression(typeInference, semanticModel, SimpleNameOrMemberAccessExpression, cancellationToken); if (expressionType == null) { return(false); } SignatureInfo = new MethodSignatureInfo(semanticDocument, this, CreateMethodSymbolWithReturnType(expressionType)); } } // Now, try to bind the invocation and see if it succeeds or not. if it succeeds and // binds uniquely, then we don't need to offer this quick fix. cancellationToken.ThrowIfCancellationRequested(); // If the name bound with errors, then this is a candidate for generate method. var semanticInfo = semanticModel.GetSymbolInfo(SimpleNameOrMemberAccessExpression, cancellationToken); if (semanticInfo.GetAllSymbols().Any(s => s.Kind == SymbolKind.Local || s.Kind == SymbolKind.Parameter) && !service.AreSpecialOptionsActive(semanticModel)) { // if the name bound to something in scope then we don't want to generate the // method because it will be shadowed by what's in scope. Unless we are in a // special state such as Option Strict On where we want to generate fixes even // if we shadow types. return(false); } // Check if the symbol is on the list of valid symbols for this language. cancellationToken.ThrowIfCancellationRequested(); if (semanticInfo.Symbol != null && !service.IsValidSymbol(semanticInfo.Symbol, semanticModel)) { return(false); } // Either we found no matches, or this was ambiguous. Either way, we might be able // to generate a method here. Determine where the user wants to generate the method // into, and if it's valid then proceed. cancellationToken.ThrowIfCancellationRequested(); if (!service.TryDetermineTypeToGenerateIn( semanticDocument, ContainingType, SimpleNameOrMemberAccessExpression, cancellationToken, out var typeToGenerateIn, out var isStatic)) { return(false); } var semanticFacts = semanticDocument.Document.GetLanguageService <ISemanticFactsService>(); IsWrittenTo = semanticFacts.IsWrittenTo(semanticModel, InvocationExpressionOpt ?? SimpleNameOrMemberAccessExpression, cancellationToken); TypeToGenerateIn = typeToGenerateIn; IsStatic = isStatic; MethodGenerationKind = MethodGenerationKind.Member; return(true); }
private async Task<bool> TryInitializeAsync( SemanticDocument document, LocalDeclarationStatementSyntax node, CancellationToken cancellationToken) { if (node == null) { return false; } this.DeclarationStatement = node; if (!(this.DeclarationStatement.IsParentKind(SyntaxKind.Block) && this.DeclarationStatement.Declaration.Variables.Count == 1)) { return false; } this.VariableDeclaration = this.DeclarationStatement.Declaration; this.VariableDeclarator = this.VariableDeclaration.Variables[0]; this.OutermostBlock = (BlockSyntax)this.DeclarationStatement.Parent; this.LocalSymbol = (ILocalSymbol)document.SemanticModel.GetDeclaredSymbol(this.VariableDeclarator, cancellationToken); if (this.LocalSymbol == null) { // This can happen in broken code, for example: "{ object x; object }" return false; } var findReferencesResult = await SymbolFinder.FindReferencesAsync(this.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 syntaxTree = document.SyntaxTree; var referencingStatements = (from r in references let token = document.Root.FindToken(r.Location.SourceSpan.Start) let statement = token.GetAncestor<StatementSyntax>() where statement != null select statement).ToList(); if (referencingStatements.Count == 0) { return false; } this.InnermostBlock = referencingStatements.FindInnermostCommonBlock(); var allAffectedStatements = new HashSet<StatementSyntax>(referencingStatements.SelectMany(expr => expr.GetAncestorsOrThis<StatementSyntax>())); this.FirstStatementAffectedInInnermostBlock = this.InnermostBlock.Statements.FirstOrDefault(allAffectedStatements.Contains); if (this.FirstStatementAffectedInInnermostBlock == null) { return false; } if (this.FirstStatementAffectedInInnermostBlock == this.DeclarationStatement) { return false; } var originalIndexInBlock = this.InnermostBlock.Statements.IndexOf(this.DeclarationStatement); var firstStatementIndexAffectedInBlock = this.InnermostBlock.Statements.IndexOf(this.FirstStatementAffectedInInnermostBlock); if (originalIndexInBlock >= 0 && originalIndexInBlock < firstStatementIndexAffectedInBlock) { // Don't want to move a decl 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. if (InDeclarationStatementGroup(originalIndexInBlock, firstStatementIndexAffectedInBlock)) { return false; } } var previousNodeOrToken = firstStatementIndexAffectedInBlock == 0 ? this.InnermostBlock.OpenBraceToken : (SyntaxNodeOrToken)this.InnermostBlock.Statements[firstStatementIndexAffectedInBlock - 1]; var affectedSpan = TextSpan.FromBounds(previousNodeOrToken.SpanStart, FirstStatementAffectedInInnermostBlock.Span.End); if (syntaxTree.OverlapsHiddenPosition(affectedSpan, cancellationToken)) { return false; } return true; }
protected abstract Task <InsertionPoint> GetInsertionPointAsync(SemanticDocument document, CancellationToken cancellationToken);