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;
        }
示例#2
0
 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;
            }
示例#5
0
        private InsertionPoint(SemanticDocument document, SyntaxAnnotation annotation)
        {
            Contract.ThrowIfNull(document);
            Contract.ThrowIfNull(annotation);

            this.SemanticDocument = document;
            _annotation = annotation;
            _context = CreateLazyContextNode();
        }
示例#6
0
        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;
        }
示例#12
0
        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);
 }
示例#14
0
 public InsertionPoint With(SemanticDocument document)
 {
     return new InsertionPoint(document, _annotation);
 }
示例#15
0
 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;
 }
示例#18
0
 public ITypeSymbol GetVariableType(SemanticDocument document)
 {
     return(document.SemanticModel.ResolveType(_variableSymbol.OriginalType));
 }
示例#19
0
 public SyntaxToken GetIdentifierTokenAtDeclaration(SemanticDocument document)
 {
     return(document.GetTokenWithAnnotation(_variableSymbol.IdentifierTokenAnnotation));
 }
示例#20
0
 protected abstract SyntaxNode GetPreviousMember(SemanticDocument document);
示例#21
0
            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);
            }
示例#22
0
 protected virtual Task <GeneratedCode> CreateGeneratedCodeAsync(OperationStatus status, SemanticDocument newDocument, CancellationToken cancellationToken)
 {
     return(Task.FromResult(new GeneratedCode(
                                status,
                                newDocument,
                                MethodNameAnnotation,
                                CallSiteAnnotation,
                                MethodDefinitionAnnotation)));
 }
示例#23
0
 protected virtual Task <SemanticDocument> UpdateMethodAfterGenerationAsync(
     SemanticDocument originalDocument,
     OperationStatus <IMethodSymbol> methodSymbolResult,
     CancellationToken cancellationToken)
 => Task.FromResult(originalDocument);
 protected abstract AbstractInvocationInfo CreateInvocationMethodInfo(SemanticDocument document, State abstractState);
示例#25
0
        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);
        }
示例#26
0
 protected abstract bool TryInitializeState(SemanticDocument document, TextSpan textSpan, CancellationToken cancellationToken, out SyntaxNode baseTypeNode, out INamedTypeSymbol classType);
示例#27
0
            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);
示例#30
0
 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);
            }
示例#32
0
 protected override bool IsSimpleNameGeneration(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken)
 => node is SimpleNameSyntax;
示例#33
0
        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);
        }
示例#34
0
 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));
            }
示例#36
0
        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);
 }
示例#40
0
            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));
            }
示例#41
0
 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));
            }
        }
示例#46
0
            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;
            }
示例#48
0
 protected abstract Task <InsertionPoint> GetInsertionPointAsync(SemanticDocument document, CancellationToken cancellationToken);